cxf-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Parwiz Rezai (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (CXF-4912) cxf rest client always picks the first ResponseExceptionMapper for a method with different exception throws
Date Sat, 23 Mar 2013 08:01:20 GMT

    [ https://issues.apache.org/jira/browse/CXF-4912?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13611657#comment-13611657
] 

Parwiz Rezai commented on CXF-4912:
-----------------------------------

i commented in a fixed bug that was complaining about run time exception mapping for client
side.. so here is that one as well. https://issues.apache.org/jira/browse/CXF-4496

actually the bigger issue is that it always picks the first exception mapper based on method
signature.
https://issues.apache.org/jira/browse/CXF-4912
what's happening right now is if you say have two different exception in your throws method
myMethod() throws Exception2, Exception1;
and mappers for both of those exceptions on server side and client side (maybe you are doing
different
things.. so yes i know you can have one super class if they are both checked exceptions..
let's say 
you have a legacy exception and you don't have source for it.. and a new exception you created
for something else)
now the client code is blind and picks the first mapper when a fault occurs so in this it
will always
default to Exception2ResponeMapper on client side.. even if in the method you happen to throw
Exception1
this is incorrect..
please take a look again as this is a big issue if you have multiple mappers and a method
that
throws more than one exception in its signature (be it checked or runtime or multiple checked
exceptions)... 
it will pick the first mapper for the first exception listed after throws keyword.. not 
actually match based on actual exception type and mappers available.
maybe allow the response to have a header of some sort that contains the exception name/class
and in the findExceptionMapper() use that header to know exactly what exception occurred and
go
find a mapper based on that type instead of picking the first exception after the throws clause

aka Class<?>[] exTypes = m.getExceptionTypes(); <-- the mapper is selected based
on the order returned by this
                
> cxf rest client always picks the first ResponseExceptionMapper for a method with different
exception throws
> -----------------------------------------------------------------------------------------------------------
>
>                 Key: CXF-4912
>                 URL: https://issues.apache.org/jira/browse/CXF-4912
>             Project: CXF
>          Issue Type: Bug
>          Components: JAX-RS
>    Affects Versions: 2.7.3
>         Environment: apache-tomcat-6.0.33, jdk1.6.0_34, spring 3.2.1.RELEASE, jackson
2.1.4
>            Reporter: Parwiz Rezai
>         Attachments: cxftest.zip
>
>
> The selection for response mapper on client side will always pick the first
> exception listed and invoke the mapper for that guy.. it will never
> invoke Exception1ResponseMapper  even though our exception is of type
> Exception1.. 
> throws Exception2, Exception1  <-- this will always find a mapper for Exception2 
> first and use that even if our actual eexception is Exception1 in this case.
> I think the code needs to lookup the mapper based on type as well
> instead of generic first mapper found for that service.
> I have two differnt exceptions:
> {code:borderStyle=solid}
> public class Exception1 extends Exception {
>     public Exception1() { }
>     public Exception1(String msg) {
>         super(msg);
>     }
> }
> public class Exception2 extends Exception {
>     public Exception2() {}
>     public Exception2(String msg) {
>         super(msg);
>     }
> }
> {code}
> {code:title=Exception1ResponseMapper.java|borderStyle=solid}
> import com.fasterxml.jackson.core.JsonParser;
> import com.fasterxml.jackson.databind.MappingJsonFactory;
> import java.io.InputStream;
> import javax.ws.rs.core.Response;
> import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
> public class Exception1ResponseMapper implements ResponseExceptionMapper<Exception1>
{
>     @Override
>     public Exception1 fromResponse(Response response) {
>         try {
> 	    MappingJsonFactory factory = new MappingJsonFactory();
> 	    JsonParser parser = factory.createJsonParser((InputStream) response.getEntity());
> 	    Exception1 exception = parser.readValueAs(Exception1.class);
> 	    return exception;
> 	} catch (Exception ex) {
> 	    return new Exception1("Could not deserialize server side exception: " + ex.getMessage());
>         }
>     }
> }
> {code}
> {code:title=Exception2ResponseMapper.java|borderStyle=solid}
> import com.fasterxml.jackson.core.JsonParser;
> import com.fasterxml.jackson.databind.MappingJsonFactory;
> import java.io.InputStream;
> import javax.ws.rs.core.Response;
> import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
> public class Exception2ResponseMapper implements ResponseExceptionMapper<Exception2>
{
>     @Override
>     public Exception2 fromResponse(Response response) {
>         try {
> 	    MappingJsonFactory factory = new MappingJsonFactory();
> 	    JsonParser parser = factory.createJsonParser((InputStream) response.getEntity());
> 	    Exception2 exception = parser.readValueAs(Exception2.class);
>             // do some specific work for exception 2 only
> 	    return exception;
> 	} catch (Exception ex) {
> 	    return new Exception2("Could not deserialize server side exception: " + ex.getMessage());
>         }
>     }
> }
> {code}
> so suppose one mapper does something different than the other one.
> now my service method:
> {code:borderStyle=solid}
> @Path("/cool")
> @Consumes(MediaType.APPLICATION_JSON)
> @Produces(MediaType.APPLICATION_JSON)
> public interface MyService {
>     @GET
>     SomeCoolObject myMethod() throws Exception2, Exception1;
> }
> @Service("myService")
> public class MyServiceImpl implements MyService {
>     public SomeCoolObject myMethod() throws Exception2, Exception1 {
>         throw new Exception1("hey this exception will still go exception 2 mapper.. why?");
>     }
> }
> {code}
> {code:title=creating client proxy|borderStyle=solid}
>     List providers = new ArrayList<Object>();
>     providers.add(new com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider());
>     providers.add(new Exception1ResponseMapper());
>     providers.add(new Exception2ResponseMapper());
>     MyService serviceProxy = JAXRSClientFactory.create("http://localhost:8080/", MyService.class,
providers);
>     try {
>         serviceProxy.myMethod();
>     } catch(Exception e) {
>      // should get back Exception1 but no go
>     }
> {code}
> following is exception to response mappers on service side
> {code:title=Exception mapping on server side|borderStyle=solid}
> @Provider
> public class Exception1AsResponseMapper implements ExceptionMapper<Exception1>
{
>     @Override
>     public Response toResponse(Exception1 exception) {
>         return Response.ok(exception, MediaType.APPLICATION_JSON).status(Response.Status.BAD_REQUEST).build();
>     }
> }
> @Provider
> public class Exception2AsResponseMapper implements ExceptionMapper<Exception2>
{
>     @Override
>     public Response toResponse(Exception2 exception) {
>         return Response.ok(exception, MediaType.APPLICATION_JSON).status(Response.Status.BAD_REQUEST).build();
>     }
> }
> {code}
> {code:xml|title=spring configs for cxf servlet}
> <import resource="classpath:META-INF/cxf/cxf.xml" />
> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
> <context:annotation-config/>
> 	
> <context:component-scan base-package="com.test"/>
> <jaxrs:server id="services" address="/">
> 		<jaxrs:serviceBeans>
> 			<ref bean="myService"/>
> 		</jaxrs:serviceBeans>
> 		<jaxrs:providers>
> 			<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
> 			<bean class="com.test.server.Exception1AsResponseMapper"/>
> 			<bean class="com.test.server.Exception2AsResponseMapper"/>
> 		</jaxrs:providers>
> 		<jaxrs:extensionMappings>
> 			<entry key="json" value="application/json" />
> 		</jaxrs:extensionMappings>
> 	</jaxrs:server>
> {code}
> on the server side the right response mapper is invoked correctly based on type of Exception
thrown.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Mime
View raw message