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

Reply via email to