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.getClass
(),
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