Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
2.7.3
-
None
-
apache-tomcat-6.0.33, jdk1.6.0_34, spring 3.2.1.RELEASE, jackson 2.1.4
-
Unknown
Description
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:
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); } }
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()); } } }
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()); } } }
so suppose one mapper does something different than the other one.
now my service method:
@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?"); } }
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 }
following is exception to response mappers on service side
@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(); } }
<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>
on the server side the right response mapper is invoked correctly based on type of Exception thrown.