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.

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





Reply via email to