[ 
https://issues.apache.org/jira/browse/CXF-4912?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Parwiz Rezai updated CXF-4912:
------------------------------

    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:

{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.Exception1AsResponseMapper"/>
                        <bean class="com.test.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.

  was:
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}

The selection for response mapper 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.. 

I think the code needs to lookup the mapper based on type as well
instead of generic first mapper found for that service.

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.Exception1AsResponseMapper"/>
                        <bean class="com.test.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.

    
> 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
>
> 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.Exception1AsResponseMapper"/>
>                       <bean class="com.test.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

Reply via email to