Hi,
I've reverted to the original code, but also updated the RS code to
throw WAE subclasses where possible as per the spec, example,
NotFoundException will be thrown instead of
WebApplicationException(404), etc
Thanks, Sergey
On 02/11/12 15:28, Sergey Beryozkin wrote:
Hi Duncan
On 02/11/12 12:13, Duncan Keysell (dkeysell) wrote:
Hi Sergey,
The temporary workaround is not working for me :-(. I am getting class
cast exception. This is because in my application I also have an
exception:
public class XMPWebApplicationException extends WebApplicationException {
Š.
{
And a mapper for it:
public class XMPWebAppExceptionMapper implements
ExceptionMapper<XMPWebApplicationException> {
Š.
}
So with the workaround in JAXRSUtils.convertFaultToResponse(T ex, Message
inMessage) that is provided in 2.7.1-SNAPSHOT:
Again the mapper and the exception satisfy the if statement and so the
exception get changed to a javax.ws.rs.BadRequestException inside
getWebApplicationExceptionClass method but the mapper is still expecting
to receive a XMPWebApplicationException or a subclass. So this causes
class cast exception.
I'm going to revert to the original code (the one that was there in
2.6.x) asap. It appears I've misinterpreted what exactly we've agreed to
awhile back on the spec list re mapping WebApplicationExceptions on the
server side.
While I still think that there's a certain degree of ambiguity with
application-thrown WebApplicationExceptions not being mapped to
specialized WebApplicationException subclass mappers, example
(WebApplicationException(404) -> NotFoundException mapper), I'm going to
drop this code and revert to the old one.
Thanks for the patience
Sergey
Thanks
Duncan
On 30/10/2012 13:47, "Sergey Beryozkin"<[email protected]> wrote:
Hi Duncan
On 30/10/12 11:16, Duncan Keysell (dkeysell) wrote:
Hi,
Thanks for the update. I'm building my application against
2.7.1-SNAPSHOT
now so I can try out a fix once you've had a time to look at this :-).
I've just committed a temporarily fix. I'm looking for the final
confirmation on whether this mapping of base WebApplicationExceptions to
WebApplicationException subclass mappers will be actually supported, if
yes - then I will optimize the current solution, if not - I will revert
to the original code - I'll keep you up to date
Thanks for reporting this issue,
Sergey
Thanks
Duncan
On 25/10/2012 18:15, "Sergey Beryozkin"<[email protected]> wrote:
On 25/10/12 17:17, Sergey Beryozkin wrote:
Hi Duncan
Thanks for the analysis, comments inline
On 25/10/12 14:18, Duncan Keysell (dkeysell) wrote:
Hi,
In the application code for my REST service all the exceptions are
wrapped in WebApplicationException and then thrown. I have a test
case
to check this is working and below is the resource called in that
test
case:
@GET
@Path("/plainBad")
public MgmtResponse throwPlainException() throws Exception {
throw new WebApplicationException(new Exception("Some lame
message"));
}
I have an exception mapper (implementation of
ExceptionMapper<WebApplicationException>) that creates the Response.
This Response contains the message from the original exception as
well
as the exception type, up until I have moved to use 2.7.0.
This is due to a change in the JAXRSUtils.convertFaultToResponse(T,
Message) message between 2.6.2 and 2.7.0.
Previously the method was (line 1217):
public static<T extends Throwable> Response convertFaultToResponse(T
ex, Message inMessage) {
ExceptionMapper<T> mapper =
ProviderFactory.getInstance(inMessage).createExceptionMapper(ex.getCla
ss
(),
inMessage);
if (mapper != null) {
try {
return mapper.toResponse(ex);
} catch (Exception mapperEx) {
mapperEx.printStackTrace();
return Response.serverError().build();
}
}
return null;
}
And now it is (line 1352):
@SuppressWarnings("unchecked")
public static<T extends Throwable> Response convertFaultToResponse(T
ex, Message inMessage) {
ProviderFactory factory = ProviderFactory.getInstance(inMessage);
ExceptionMapper<T> mapper = factory.createExceptionMapper(ex,
inMessage);
if (mapper != null) {
if (ex.getClass() == WebApplicationException.class
&& mapper.getClass() != WebApplicationExceptionMapper.class) {
WebApplicationException webEx = (WebApplicationException)ex;
Class<?> exceptionClass =
getWebApplicationExceptionClass(webEx.getResponse(),
WebApplicationException.class);
if (exceptionClass != WebApplicationException.class) {
try {
Constructor<?> ctr = exceptionClass.getConstructor(Response.class);
ex = (T)ctr.newInstance(webEx.getResponse());
} catch (Exception ex2) {
ex2.printStackTrace();
return Response.serverError().build();
}
}
}
try {
return mapper.toResponse(ex);
} catch (Exception mapperEx) {
mapperEx.printStackTrace();
return Response.serverError().build();
} finally {
factory.clearExceptionMapperProxies();
}
}
return null;
}
So the problem is that the exception 'ex' and my 'mapper' pass
the if
statement (line 1356):
if (ex.getClass() == WebApplicationException.class
&& mapper.getClass() != WebApplicationExceptionMapper.class)
And then the ex gets over written and I loose all the details that
the
original WebApplicationException was holding. Shouldn't the if
statement be changed not to allow any mapping implementing
ExceptionMapper<WebApplicationException>? Is there some workaround
for
this?
I'm going to work on test case shortly. The actual change was needed
to
get new JAX-RS 2.0 exceptions such as NotFoundException (alternative
to
new WebApplicationException(404)), etc, captured by existing
ExceptionMapper<WebApplicationException> mappers if no a mapper like
ExceptionMapper<NotFoundException> exists, but a regression has been
introduced.
It is the other way around, if we have
ExceptionMapper<NotFoundException> but the code has thrown "new
WebApplicationException(404)" then NotFoundExceptionMapper should be
chosen given that NotFoundException extends WebApplicationException.
I can see that the exception is lost in all the cases where the origin
ex is WebApplicationException and the mapper is not known to CXF,
it is
really to do with a wrong constructor check, still looking, but will
likely fix early next week due to the long weekend coming in
The tests show that if you register say
ExceptionMapper<InternalServerErrorException> and throw
InternalServerErrorException then no cause exception is lost, in
meantime I'll have a look at the other cases
Cheers, Sergey
The possible workarounds: provide
ExceptionMapper<ServerErrorException>
or extend CXF WebApplicationExceptionMapper. Another one is CXF
specific
and it is to register a custom CXF invoker which will get a chance to
capture the original WebApplicationException, I guess it should be
the
last resort option, I'll provide more info if doing other exception
mappers won't help
Thanks, Sergey
Thanks
Duncan
--
Sergey Beryozkin
Talend Community Coders
http://coders.talend.com/
Blog: http://sberyozkin.blogspot.com