You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by "Lambert, Michael" <mi...@michaellambert.com> on 2014/10/21 19:24:10 UTC

jax-rs exception mapping

Hello gentleman!

My impression was that when implementing ExceptionMapper that the mapper of
the nearest superclass of an exception would be used if an exact
exceptionmapper match to the exception didnt exist.

For example if I created a FooException which extended BarException  I
would only have to create a BarExceptionMapper to catch and map both types
of exceptions; the BarExceptionMapper would be used when a FooException was
thrown.

The red hat docs seem to reinforce this opinion:


   -

   When any exception other than a WebApplicationException exception, or
   one of its subclasses, is thrown, the runtime will check for an appropriate
   exception mapper. An exception mapper is selected if it handles the
   specific exception thrown. If there is not an exception mapper for the
   specific exception that was thrown, the exception mapper for the nearest
   superclass of the exception is selected.


https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/RESTExceptionMapper.html

The reality is different for us however. In fact, if we create a custom
WebApplicationExceptionMapper ClientErrorExceptions are not caught by the
mapper. CXF seems to default to attempt to use whichever Mapper is the
first one we registered (e.g. if we defined a FooExceptionMapper and
registered it, CXF would attempt to use that and throw an error rather than
try to use the WebApplicationExceptionMapper).

Can someone tell me what the expected behavior is? Is my question clear?

We are using CXF version 2.7.11.

Thanks!

Mike

Re: jax-rs exception mapping

Posted by "Lambert, Michael" <mi...@michaellambert.com>.
Great news Sergey; thanks once again!

On Tue, Oct 28, 2014 at 1:00 PM, Sergey Beryozkin <sb...@gmail.com>
wrote:

> You are right, the issue was resolved as part of
> https://issues.apache.org/jira/browse/CXF-6067
>
> Many thanks for your help with identifying the issue
> Please try 2.7.14-SNAPSHOT a bit later
> Cheers, Sergey
>
> On 24/10/14 15:16, Lambert, Michael wrote:
>
>> Correction the problem method is ProviderFactory.getGenericInterfaces.
>> Its
>> not the comparator.
>>
>> On Thu, Oct 23, 2014 at 4:55 PM, Lambert, Michael <
>> michael@michaellambert.com> wrote:
>>
>>  Fleshed it out a bit more with comment. It looks like the
>>> ProviderFactory.Comparator will choose whichever class in the
>>> parent/child
>>> lineage which implements ExceptionMapper and base its ordering on that.
>>> This means that a parent class cannot implement ExceptionMapper unless
>>> the
>>> child ALSO implments ExceptionMapper.
>>>
>>> package foo.test;
>>>
>>> import static org.junit.Assert.*;
>>>
>>> import javax.ws.rs.core.Response;
>>> import javax.ws.rs.ext.ExceptionMapper;
>>> import javax.ws.rs.ext.Provider;
>>>
>>> import org.apache.cxf.jaxrs.provider.ProviderFactory;
>>> import org.apache.cxf.message.MessageImpl;
>>>
>>> public class ExceptionMapperTest {
>>>   @org.junit.Before
>>> public void setup() {
>>> ProviderFactory.getInstance().clearProviders();
>>> }
>>>   @org.junit.Test
>>> public void testBadCustomExceptionMappersHierarchyWithGenerics() throws
>>> Exception {
>>>   ProviderFactory pf = ProviderFactory.getInstance();
>>>   BadExceptionMapperA badExceptionMapperA = new BadExceptionMapperA();
>>> pf.registerUserProvider(badExceptionMapperA);
>>>   BadExceptionMapperB badExceptionMapperB = new BadExceptionMapperB();
>>> pf.registerUserProvider(badExceptionMapperB);
>>>   Object mapperResponse1 =
>>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>>> assertSame(badExceptionMapperA, mapperResponse1);
>>>   Object mapperResponse2 =
>>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>>> assertSame(badExceptionMapperB, mapperResponse2);
>>>   Object mapperResponse3 =
>>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>>> assertSame(badExceptionMapperA, mapperResponse3);
>>>   Object mapperResponse4 =
>>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>>> assertSame(badExceptionMapperB, mapperResponse4);
>>> }
>>>   /**
>>>   * To fix the problem the mapper must NOT extend from a class that
>>> implements the ExceptionMapper interface. The parent class should be
>>>   * a normal java class and the mapper should implement the
>>> ExceptionMapper
>>> interface DIRECTLY!
>>>   *
>>>   * @throws Exception
>>>   */
>>> @org.junit.Test
>>> public void testFixedCustomExceptionMappersHierarchyWithGenerics()
>>> throws
>>> Exception {
>>>   ProviderFactory pf = ProviderFactory.getInstance();
>>>   FixedExceptionMapperA exceptionMapperA = new FixedExceptionMapperA();
>>> pf.registerUserProvider(exceptionMapperA);
>>>   FixedExceptionMapperB exceptionMapperB = new FixedExceptionMapperB();
>>> pf.registerUserProvider(exceptionMapperB);
>>>   Object mapperResponse1 =
>>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>>> assertSame(exceptionMapperA, mapperResponse1);
>>>   Object mapperResponse2 =
>>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>>> assertSame(exceptionMapperB, mapperResponse2);
>>>   Object mapperResponse3 =
>>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>>> assertSame(exceptionMapperA, mapperResponse3);
>>>   Object mapperResponse4 =
>>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>>> assertSame(exceptionMapperB, mapperResponse4);
>>> }
>>>
>>>
>>> @org.junit.Test
>>> public void testGoodExceptionMappersHierarchyWithGenerics() throws
>>> Exception {
>>>   ProviderFactory pf = ProviderFactory.getInstance();
>>>   GoodRuntimeExceptionAMapper runtimeExceptionAMapper = new
>>> GoodRuntimeExceptionAMapper();
>>> pf.registerUserProvider(runtimeExceptionAMapper);
>>>   GoodRuntimeExceptionBMapper runtimeExceptionBMapper = new
>>> GoodRuntimeExceptionBMapper();
>>> pf.registerUserProvider(runtimeExceptionBMapper);
>>>   Object mapperResponse1 =
>>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>>> assertSame(runtimeExceptionAMapper, mapperResponse1);
>>>   Object mapperResponse2 =
>>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>>> assertSame(runtimeExceptionBMapper, mapperResponse2);
>>>   Object mapperResponse3 =
>>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>>> assertSame(runtimeExceptionAMapper, mapperResponse3);
>>>   Object mapperResponse4 =
>>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>>> assertSame(runtimeExceptionBMapper, mapperResponse4);
>>> }
>>>   private class RuntimeExceptionA extends RuntimeException {
>>> private static final long serialVersionUID = 1L;
>>> }
>>>   private class RuntimeExceptionAA extends RuntimeExceptionA {
>>> private static final long serialVersionUID = 1L;
>>> }
>>>   private class RuntimeExceptionB extends RuntimeException {
>>> private static final long serialVersionUID = 1L;
>>> }
>>>   private class RuntimeExceptionBB extends RuntimeExceptionB {
>>> private static final long serialVersionUID = 1L;
>>> }
>>>   private class GoodRuntimeExceptionAMapper implements
>>> ExceptionMapper<RuntimeExceptionA> {
>>>
>>> @Override
>>> public Response toResponse(RuntimeExceptionA exception) {
>>> // TODO Auto-generated method stub
>>> return null;
>>> }
>>> }
>>>   private class GoodRuntimeExceptionBMapper implements
>>> ExceptionMapper<RuntimeExceptionB> {
>>>
>>> @Override
>>> public Response toResponse(RuntimeExceptionB exception) {
>>> // TODO Auto-generated method stub
>>> return null;
>>> }
>>> }
>>>   /**
>>>   * The parent implements ExceptionMapper and as a result will be what
>>> the
>>> ProviderFactory.Comparator class incorrectly chooses when sort ordering
>>>   * the mappers rather than its children
>>>   *
>>>   */
>>> private abstract class BadParentExceptionMapper<T extends Throwable>
>>> implements ExceptionMapper<T> {
>>> }
>>>   /**
>>>   * This does not implement ExceptionMapper and so its parent will be
>>> incorrectly selected by he ProviderFactory.Comparator class for sort
>>> ordering
>>>   *
>>>   */
>>> @Provider
>>> private class BadExceptionMapperA extends
>>> BadParentExceptionMapper<RuntimeExceptionA> {
>>>
>>> @Override
>>> public Response toResponse(RuntimeExceptionA exception) {
>>> return null;
>>> }
>>> }
>>>   /**
>>>   * This does not implement ExceptionMapper and so its parent will be
>>> incorrectly selected by he ProviderFactory.Comparator class for sort
>>> ordering
>>>   *
>>>   */
>>> @Provider
>>> private class BadExceptionMapperB extends
>>> BadParentExceptionMapper<RuntimeExceptionB> {
>>>
>>> @Override
>>> public Response toResponse(RuntimeExceptionB exception) {
>>> return null;
>>> }
>>> }
>>>   /**
>>>   * This does NOT implement ExceptionMapper
>>>   *
>>>   */
>>> private abstract class FixedParentExceptionMapper {
>>> }
>>>   /**
>>>   * The mapper implements ExceptionMapper directly
>>>   *
>>>   */
>>> @Provider
>>> private class FixedExceptionMapperA extends FixedParentExceptionMapper
>>> implements ExceptionMapper<RuntimeExceptionA> {
>>>
>>> @Override
>>> public Response toResponse(RuntimeExceptionA exception) {
>>> return null;
>>> }
>>> }
>>>   /**
>>>   * The mapper implements ExceptionMapper directly
>>>   *
>>>   */
>>> @Provider
>>> private class FixedExceptionMapperB extends FixedParentExceptionMapper
>>> implements ExceptionMapper<RuntimeExceptionB> {
>>>
>>> @Override
>>> public Response toResponse(RuntimeExceptionB exception) {
>>> return null;
>>> }
>>> }
>>> }
>>>
>>>
>>> On Thu, Oct 23, 2014 at 4:30 PM, Lambert, Michael <
>>> michael@michaellambert.com> wrote:
>>>
>>>  Sergei,
>>>>
>>>> Here is a test case that demonstrates the problem. Note that the only
>>>> difference between the good test and the bad test is that the mapper
>>>> itself
>>>> is derived from a parent class. This test is based on cxf 2.7.11 but i
>>>> presume it will also work with 3.0 by swapping out the providerfactory
>>>> class with serviceproviderfactory.
>>>>
>>>>
>>>> package foo.test;
>>>>
>>>> import static org.junit.Assert.*;
>>>>
>>>> import javax.ws.rs.core.Response;
>>>> import javax.ws.rs.ext.ExceptionMapper;
>>>> import javax.ws.rs.ext.Provider;
>>>>
>>>> import org.apache.cxf.jaxrs.provider.ProviderFactory;
>>>> import org.apache.cxf.message.MessageImpl;
>>>>
>>>> public class ExceptionMapperTest {
>>>>   @org.junit.Before
>>>> public void setup() {
>>>> ProviderFactory.getInstance().clearProviders();
>>>> }
>>>>   @org.junit.Test
>>>> public void testBadCustomExceptionMappersHierarchyWithGenerics() throws
>>>> Exception {
>>>>   ProviderFactory pf = ProviderFactory.getInstance();
>>>>   BadExceptionMapperA badExceptionMapperA = new BadExceptionMapperA();
>>>> pf.registerUserProvider(badExceptionMapperA);
>>>>   BadExceptionMapperB badExceptionMapperB = new BadExceptionMapperB();
>>>> pf.registerUserProvider(badExceptionMapperB);
>>>>   Object mapperResponse1 =
>>>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>>>> assertSame(badExceptionMapperA, mapperResponse1);
>>>>   Object mapperResponse2 =
>>>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>>>> assertSame(badExceptionMapperB, mapperResponse2);
>>>>   Object mapperResponse3 =
>>>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>>>> assertSame(badExceptionMapperA, mapperResponse3);
>>>>   Object mapperResponse4 =
>>>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>>>> assertSame(badExceptionMapperB, mapperResponse4);
>>>> }
>>>>
>>>> @org.junit.Test
>>>> public void testGoodExceptionMappersHierarchyWithGenerics() throws
>>>> Exception {
>>>>   ProviderFactory pf = ProviderFactory.getInstance();
>>>>   GoodRuntimeExceptionAMapper runtimeExceptionAMapper = new
>>>> GoodRuntimeExceptionAMapper();
>>>> pf.registerUserProvider(runtimeExceptionAMapper);
>>>>   GoodRuntimeExceptionBMapper runtimeExceptionBMapper = new
>>>> GoodRuntimeExceptionBMapper();
>>>> pf.registerUserProvider(runtimeExceptionBMapper);
>>>>   Object mapperResponse1 =
>>>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>>>> assertSame(runtimeExceptionAMapper, mapperResponse1);
>>>>   Object mapperResponse2 =
>>>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>>>> assertSame(runtimeExceptionBMapper, mapperResponse2);
>>>>   Object mapperResponse3 =
>>>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>>>> assertSame(runtimeExceptionAMapper, mapperResponse3);
>>>>   Object mapperResponse4 =
>>>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>>>> assertSame(runtimeExceptionBMapper, mapperResponse4);
>>>> }
>>>>   private class RuntimeExceptionA extends RuntimeException {
>>>> private static final long serialVersionUID = 1L;
>>>> }
>>>>   private class RuntimeExceptionAA extends RuntimeExceptionA {
>>>> private static final long serialVersionUID = 1L;
>>>> }
>>>>   private class RuntimeExceptionB extends RuntimeException {
>>>> private static final long serialVersionUID = 1L;
>>>> }
>>>>   private class RuntimeExceptionBB extends RuntimeExceptionB {
>>>> private static final long serialVersionUID = 1L;
>>>> }
>>>>   private class GoodRuntimeExceptionAMapper implements
>>>> ExceptionMapper<RuntimeExceptionA> {
>>>>
>>>> @Override
>>>> public Response toResponse(RuntimeExceptionA exception) {
>>>> // TODO Auto-generated method stub
>>>> return null;
>>>> }
>>>> }
>>>>   private class GoodRuntimeExceptionBMapper implements
>>>> ExceptionMapper<RuntimeExceptionB> {
>>>>
>>>> @Override
>>>> public Response toResponse(RuntimeExceptionB exception) {
>>>> // TODO Auto-generated method stub
>>>> return null;
>>>> }
>>>> }
>>>>   public abstract class BadParentExceptionMapper<T extends Throwable>
>>>> implements ExceptionMapper<T> {
>>>> }
>>>>   @Provider
>>>> public class BadExceptionMapperA extends
>>>> BadParentExceptionMapper<RuntimeExceptionA> {
>>>>
>>>> @Override
>>>> public Response toResponse(RuntimeExceptionA exception) {
>>>> return null;
>>>> }
>>>> }
>>>>   @Provider
>>>> public class BadExceptionMapperB extends
>>>> BadParentExceptionMapper<RuntimeExceptionB> {
>>>>
>>>> @Override
>>>> public Response toResponse(RuntimeExceptionB exception) {
>>>> return null;
>>>> }
>>>> }
>>>> }
>>>>
>>>>
>>>>
>>>> On Wed, Oct 22, 2014 at 8:06 AM, Lambert, Michael <
>>>> michael@michaellambert.com> wrote:
>>>>
>>>>  Good to know Sergey we will look at it again today. Definitely
>>>>> experiencing the behavior I described so we will look for some delta
>>>>> between our code and the test
>>>>> On Oct 22, 2014 5:50 AM, "Sergey Beryozkin" <sb...@gmail.com>
>>>>> wrote:
>>>>>
>>>>>  ProviderFactoryTest has the following:
>>>>>>
>>>>>> private static class RuntimeExceptionMapper1
>>>>>>          extends AbstractTestExceptionMapper<RuntimeException> {
>>>>>>
>>>>>>      }
>>>>>>
>>>>>>      private static class RuntimeExceptionMapper2
>>>>>>          extends AbstractTestExceptionMapper<WebApplicationException>
>>>>>> {
>>>>>>
>>>>>>      }
>>>>>>
>>>>>>      private static class AbstractTestExceptionMapper<T extends
>>>>>> RuntimeException>
>>>>>>          implements ExceptionMapper<T> {
>>>>>>
>>>>>>          public Response toResponse(T arg0) {
>>>>>>              // TODO Auto-generated method stub
>>>>>>              return null;
>>>>>>          }
>>>>>>
>>>>>>      }
>>>>>>
>>>>>> This is identical to your example where you say the bug is expected,
>>>>>> also note WebApplicationException is RuntimeException.
>>>>>>
>>>>>> @Test
>>>>>>      public void testExceptionMappersHierarchyWithGenerics() throws
>>>>>> Exception {
>>>>>>          ServerProviderFactory pf = ServerProviderFactory.
>>>>>> getInstance();
>>>>>>          RuntimeExceptionMapper1 exMapper1 = new
>>>>>> RuntimeExceptionMapper1();
>>>>>>          pf.registerUserProvider(exMapper1);
>>>>>>          RuntimeExceptionMapper2 exMapper2 = new
>>>>>> RuntimeExceptionMapper2();
>>>>>>          pf.registerUserProvider(exMapper2);
>>>>>>          assertSame(exMapper1, pf.createExceptionMapper(
>>>>>> RuntimeException.class,
>>>>>> new MessageImpl()));
>>>>>>          Object webExMapper = pf.createExceptionMapper(
>>>>>> WebApplicationException.class,
>>>>>> new MessageImpl());
>>>>>>          assertSame(exMapper2, webExMapper);
>>>>>>      }
>>>>>>
>>>>>> When RuntimeExceptionMapper2 is registered, RuntimeExceptionMapper1 is
>>>>>> not picked for WebApplicationException. Updating the test not to
>>>>>> register
>>>>>> RuntimeExceptionMapper2 leads to RuntimeExceptionMapper1 being
>>>>>> selected for
>>>>>> WebApplicationException.
>>>>>>
>>>>>> Looks like it is all correct to me, may be the issue is there in
>>>>>> 2.7.11
>>>>>> but def not on the trunk/3.0.2
>>>>>>
>>>>>> Cheers, Sergey
>>>>>>
>>>>>> On 21/10/14 20:04, Lambert, Michael wrote:
>>>>>>
>>>>>>  To be clear:
>>>>>>>
>>>>>>> This bug will only manifest itself if two exception mapper are both
>>>>>>> derived
>>>>>>> from the same interface:
>>>>>>>
>>>>>>>       public class AbstractMapper<T extends Throwable> implements
>>>>>>> ExceptionMapper<T> {
>>>>>>>           ...
>>>>>>>       }
>>>>>>>
>>>>>>>       public class FooMapper extends AbstractMapper<FooException> {
>>>>>>>           ...
>>>>>>>       }
>>>>>>>
>>>>>>>       // ProviderFactory.ClassComparator.compare will return "0"
>>>>>>> when
>>>>>>> BarMapper is compared to FooMapper
>>>>>>>       public class BarMapper extends AbstractMapper<BarException> {
>>>>>>>           ...
>>>>>>>       }
>>>>>>>
>>>>>>> If each exception mapper instance is derived from a DIFFERENT
>>>>>>> INTERFACE
>>>>>>> everything works fine:
>>>>>>>
>>>>>>>       public interface IFooMapper extends
>>>>>>> ExceptionMapper<FooException>
>>>>>>> {
>>>>>>>           ...
>>>>>>>       }
>>>>>>>
>>>>>>>       public class FooMapper extends implements IFooMapper  {
>>>>>>>           ...
>>>>>>>       }
>>>>>>>
>>>>>>>       public interface IBarMapper extends
>>>>>>> ExceptionMapper<BarException>
>>>>>>> {
>>>>>>>           ...
>>>>>>>       }
>>>>>>>
>>>>>>>       // ProviderFactory.ClassComparator.compare will return "1" or
>>>>>>> -1
>>>>>>> when
>>>>>>> BarMapper is compared to FooMapper
>>>>>>>       public class BarMapper extends implements IBarMapper {
>>>>>>>           ...
>>>>>>>       }
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Tue, Oct 21, 2014 at 2:34 PM, Lambert, Michael <
>>>>>>> michael@michaellambert.com> wrote:
>>>>>>>
>>>>>>>   Guys... it looks like there is a bug in ProviderFactory$
>>>>>>>
>>>>>>>> ClassComparator.
>>>>>>>> Given two mappers it always ends up comparing them as if both
>>>>>>>> mappers
>>>>>>>> were
>>>>>>>> ExceptionMapper<Throwable>. There must be a problem in the way the
>>>>>>>> interfaces and "actual types" are derived (which is done in the
>>>>>>>> InjectionUtils class).
>>>>>>>>
>>>>>>>> -Mike
>>>>>>>>
>>>>>>>> On Tue, Oct 21, 2014 at 1:24 PM, Lambert, Michael <
>>>>>>>> michael@michaellambert.com> wrote:
>>>>>>>>
>>>>>>>>   Hello gentleman!
>>>>>>>>
>>>>>>>>>
>>>>>>>>> My impression was that when implementing ExceptionMapper that the
>>>>>>>>> mapper
>>>>>>>>> of the nearest superclass of an exception would be used if an exact
>>>>>>>>> exceptionmapper match to the exception didnt exist.
>>>>>>>>>
>>>>>>>>> For example if I created a FooException which extended BarException
>>>>>>>>> I
>>>>>>>>> would only have to create a BarExceptionMapper to catch and map
>>>>>>>>> both
>>>>>>>>> types
>>>>>>>>> of exceptions; the BarExceptionMapper would be used when a
>>>>>>>>> FooException was
>>>>>>>>> thrown.
>>>>>>>>>
>>>>>>>>> The red hat docs seem to reinforce this opinion:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>      -
>>>>>>>>>
>>>>>>>>>      When any exception other than a WebApplicationException
>>>>>>>>> exception, or
>>>>>>>>>      one of its subclasses, is thrown, the runtime will check for
>>>>>>>>> an
>>>>>>>>> appropriate
>>>>>>>>>      exception mapper. An exception mapper is selected if it
>>>>>>>>> handles
>>>>>>>>> the
>>>>>>>>>      specific exception thrown. If there is not an exception mapper
>>>>>>>>> for the
>>>>>>>>>      specific exception that was thrown, the exception mapper for
>>>>>>>>> the
>>>>>>>>> nearest
>>>>>>>>>      superclass of the exception is selected.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> https://access.redhat.com/documentation/en-US/Red_Hat_
>>>>>>>>> JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/
>>>>>>>>> RESTExceptionMapper.html
>>>>>>>>>
>>>>>>>>> The reality is different for us however. In fact, if we create a
>>>>>>>>> custom
>>>>>>>>> WebApplicationExceptionMapper ClientErrorExceptions are not caught
>>>>>>>>> by the
>>>>>>>>> mapper. CXF seems to default to attempt to use whichever Mapper is
>>>>>>>>> the
>>>>>>>>> first one we registered (e.g. if we defined a FooExceptionMapper
>>>>>>>>> and
>>>>>>>>> registered it, CXF would attempt to use that and throw an error
>>>>>>>>> rather than
>>>>>>>>> try to use the WebApplicationExceptionMapper).
>>>>>>>>>
>>>>>>>>> Can someone tell me what the expected behavior is? Is my question
>>>>>>>>> clear?
>>>>>>>>>
>>>>>>>>> We are using CXF version 2.7.11.
>>>>>>>>>
>>>>>>>>> Thanks!
>>>>>>>>>
>>>>>>>>> Mike
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>> --
>>>>>> Sergey Beryozkin
>>>>>>
>>>>>> Talend Community Coders
>>>>>> http://coders.talend.com/
>>>>>>
>>>>>> Blog: http://sberyozkin.blogspot.com
>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>

Re: jax-rs exception mapping

Posted by Sergey Beryozkin <sb...@gmail.com>.
You are right, the issue was resolved as part of
https://issues.apache.org/jira/browse/CXF-6067

Many thanks for your help with identifying the issue
Please try 2.7.14-SNAPSHOT a bit later
Cheers, Sergey
On 24/10/14 15:16, Lambert, Michael wrote:
> Correction the problem method is ProviderFactory.getGenericInterfaces. Its
> not the comparator.
>
> On Thu, Oct 23, 2014 at 4:55 PM, Lambert, Michael <
> michael@michaellambert.com> wrote:
>
>> Fleshed it out a bit more with comment. It looks like the
>> ProviderFactory.Comparator will choose whichever class in the parent/child
>> lineage which implements ExceptionMapper and base its ordering on that.
>> This means that a parent class cannot implement ExceptionMapper unless the
>> child ALSO implments ExceptionMapper.
>>
>> package foo.test;
>>
>> import static org.junit.Assert.*;
>>
>> import javax.ws.rs.core.Response;
>> import javax.ws.rs.ext.ExceptionMapper;
>> import javax.ws.rs.ext.Provider;
>>
>> import org.apache.cxf.jaxrs.provider.ProviderFactory;
>> import org.apache.cxf.message.MessageImpl;
>>
>> public class ExceptionMapperTest {
>>   @org.junit.Before
>> public void setup() {
>> ProviderFactory.getInstance().clearProviders();
>> }
>>   @org.junit.Test
>> public void testBadCustomExceptionMappersHierarchyWithGenerics() throws
>> Exception {
>>   ProviderFactory pf = ProviderFactory.getInstance();
>>   BadExceptionMapperA badExceptionMapperA = new BadExceptionMapperA();
>> pf.registerUserProvider(badExceptionMapperA);
>>   BadExceptionMapperB badExceptionMapperB = new BadExceptionMapperB();
>> pf.registerUserProvider(badExceptionMapperB);
>>   Object mapperResponse1 =
>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>> assertSame(badExceptionMapperA, mapperResponse1);
>>   Object mapperResponse2 =
>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>> assertSame(badExceptionMapperB, mapperResponse2);
>>   Object mapperResponse3 =
>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>> assertSame(badExceptionMapperA, mapperResponse3);
>>   Object mapperResponse4 =
>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>> assertSame(badExceptionMapperB, mapperResponse4);
>> }
>>   /**
>>   * To fix the problem the mapper must NOT extend from a class that
>> implements the ExceptionMapper interface. The parent class should be
>>   * a normal java class and the mapper should implement the ExceptionMapper
>> interface DIRECTLY!
>>   *
>>   * @throws Exception
>>   */
>> @org.junit.Test
>> public void testFixedCustomExceptionMappersHierarchyWithGenerics() throws
>> Exception {
>>   ProviderFactory pf = ProviderFactory.getInstance();
>>   FixedExceptionMapperA exceptionMapperA = new FixedExceptionMapperA();
>> pf.registerUserProvider(exceptionMapperA);
>>   FixedExceptionMapperB exceptionMapperB = new FixedExceptionMapperB();
>> pf.registerUserProvider(exceptionMapperB);
>>   Object mapperResponse1 =
>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>> assertSame(exceptionMapperA, mapperResponse1);
>>   Object mapperResponse2 =
>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>> assertSame(exceptionMapperB, mapperResponse2);
>>   Object mapperResponse3 =
>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>> assertSame(exceptionMapperA, mapperResponse3);
>>   Object mapperResponse4 =
>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>> assertSame(exceptionMapperB, mapperResponse4);
>> }
>>
>>
>> @org.junit.Test
>> public void testGoodExceptionMappersHierarchyWithGenerics() throws
>> Exception {
>>   ProviderFactory pf = ProviderFactory.getInstance();
>>   GoodRuntimeExceptionAMapper runtimeExceptionAMapper = new
>> GoodRuntimeExceptionAMapper();
>> pf.registerUserProvider(runtimeExceptionAMapper);
>>   GoodRuntimeExceptionBMapper runtimeExceptionBMapper = new
>> GoodRuntimeExceptionBMapper();
>> pf.registerUserProvider(runtimeExceptionBMapper);
>>   Object mapperResponse1 =
>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>> assertSame(runtimeExceptionAMapper, mapperResponse1);
>>   Object mapperResponse2 =
>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>> assertSame(runtimeExceptionBMapper, mapperResponse2);
>>   Object mapperResponse3 =
>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>> assertSame(runtimeExceptionAMapper, mapperResponse3);
>>   Object mapperResponse4 =
>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>> assertSame(runtimeExceptionBMapper, mapperResponse4);
>> }
>>   private class RuntimeExceptionA extends RuntimeException {
>> private static final long serialVersionUID = 1L;
>> }
>>   private class RuntimeExceptionAA extends RuntimeExceptionA {
>> private static final long serialVersionUID = 1L;
>> }
>>   private class RuntimeExceptionB extends RuntimeException {
>> private static final long serialVersionUID = 1L;
>> }
>>   private class RuntimeExceptionBB extends RuntimeExceptionB {
>> private static final long serialVersionUID = 1L;
>> }
>>   private class GoodRuntimeExceptionAMapper implements
>> ExceptionMapper<RuntimeExceptionA> {
>>
>> @Override
>> public Response toResponse(RuntimeExceptionA exception) {
>> // TODO Auto-generated method stub
>> return null;
>> }
>> }
>>   private class GoodRuntimeExceptionBMapper implements
>> ExceptionMapper<RuntimeExceptionB> {
>>
>> @Override
>> public Response toResponse(RuntimeExceptionB exception) {
>> // TODO Auto-generated method stub
>> return null;
>> }
>> }
>>   /**
>>   * The parent implements ExceptionMapper and as a result will be what the
>> ProviderFactory.Comparator class incorrectly chooses when sort ordering
>>   * the mappers rather than its children
>>   *
>>   */
>> private abstract class BadParentExceptionMapper<T extends Throwable>
>> implements ExceptionMapper<T> {
>> }
>>   /**
>>   * This does not implement ExceptionMapper and so its parent will be
>> incorrectly selected by he ProviderFactory.Comparator class for sort
>> ordering
>>   *
>>   */
>> @Provider
>> private class BadExceptionMapperA extends
>> BadParentExceptionMapper<RuntimeExceptionA> {
>>
>> @Override
>> public Response toResponse(RuntimeExceptionA exception) {
>> return null;
>> }
>> }
>>   /**
>>   * This does not implement ExceptionMapper and so its parent will be
>> incorrectly selected by he ProviderFactory.Comparator class for sort
>> ordering
>>   *
>>   */
>> @Provider
>> private class BadExceptionMapperB extends
>> BadParentExceptionMapper<RuntimeExceptionB> {
>>
>> @Override
>> public Response toResponse(RuntimeExceptionB exception) {
>> return null;
>> }
>> }
>>   /**
>>   * This does NOT implement ExceptionMapper
>>   *
>>   */
>> private abstract class FixedParentExceptionMapper {
>> }
>>   /**
>>   * The mapper implements ExceptionMapper directly
>>   *
>>   */
>> @Provider
>> private class FixedExceptionMapperA extends FixedParentExceptionMapper
>> implements ExceptionMapper<RuntimeExceptionA> {
>>
>> @Override
>> public Response toResponse(RuntimeExceptionA exception) {
>> return null;
>> }
>> }
>>   /**
>>   * The mapper implements ExceptionMapper directly
>>   *
>>   */
>> @Provider
>> private class FixedExceptionMapperB extends FixedParentExceptionMapper
>> implements ExceptionMapper<RuntimeExceptionB> {
>>
>> @Override
>> public Response toResponse(RuntimeExceptionB exception) {
>> return null;
>> }
>> }
>> }
>>
>>
>> On Thu, Oct 23, 2014 at 4:30 PM, Lambert, Michael <
>> michael@michaellambert.com> wrote:
>>
>>> Sergei,
>>>
>>> Here is a test case that demonstrates the problem. Note that the only
>>> difference between the good test and the bad test is that the mapper itself
>>> is derived from a parent class. This test is based on cxf 2.7.11 but i
>>> presume it will also work with 3.0 by swapping out the providerfactory
>>> class with serviceproviderfactory.
>>>
>>>
>>> package foo.test;
>>>
>>> import static org.junit.Assert.*;
>>>
>>> import javax.ws.rs.core.Response;
>>> import javax.ws.rs.ext.ExceptionMapper;
>>> import javax.ws.rs.ext.Provider;
>>>
>>> import org.apache.cxf.jaxrs.provider.ProviderFactory;
>>> import org.apache.cxf.message.MessageImpl;
>>>
>>> public class ExceptionMapperTest {
>>>   @org.junit.Before
>>> public void setup() {
>>> ProviderFactory.getInstance().clearProviders();
>>> }
>>>   @org.junit.Test
>>> public void testBadCustomExceptionMappersHierarchyWithGenerics() throws
>>> Exception {
>>>   ProviderFactory pf = ProviderFactory.getInstance();
>>>   BadExceptionMapperA badExceptionMapperA = new BadExceptionMapperA();
>>> pf.registerUserProvider(badExceptionMapperA);
>>>   BadExceptionMapperB badExceptionMapperB = new BadExceptionMapperB();
>>> pf.registerUserProvider(badExceptionMapperB);
>>>   Object mapperResponse1 =
>>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>>> assertSame(badExceptionMapperA, mapperResponse1);
>>>   Object mapperResponse2 =
>>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>>> assertSame(badExceptionMapperB, mapperResponse2);
>>>   Object mapperResponse3 =
>>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>>> assertSame(badExceptionMapperA, mapperResponse3);
>>>   Object mapperResponse4 =
>>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>>> assertSame(badExceptionMapperB, mapperResponse4);
>>> }
>>>
>>> @org.junit.Test
>>> public void testGoodExceptionMappersHierarchyWithGenerics() throws
>>> Exception {
>>>   ProviderFactory pf = ProviderFactory.getInstance();
>>>   GoodRuntimeExceptionAMapper runtimeExceptionAMapper = new
>>> GoodRuntimeExceptionAMapper();
>>> pf.registerUserProvider(runtimeExceptionAMapper);
>>>   GoodRuntimeExceptionBMapper runtimeExceptionBMapper = new
>>> GoodRuntimeExceptionBMapper();
>>> pf.registerUserProvider(runtimeExceptionBMapper);
>>>   Object mapperResponse1 =
>>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>>> assertSame(runtimeExceptionAMapper, mapperResponse1);
>>>   Object mapperResponse2 =
>>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>>> assertSame(runtimeExceptionBMapper, mapperResponse2);
>>>   Object mapperResponse3 =
>>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>>> assertSame(runtimeExceptionAMapper, mapperResponse3);
>>>   Object mapperResponse4 =
>>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>>> assertSame(runtimeExceptionBMapper, mapperResponse4);
>>> }
>>>   private class RuntimeExceptionA extends RuntimeException {
>>> private static final long serialVersionUID = 1L;
>>> }
>>>   private class RuntimeExceptionAA extends RuntimeExceptionA {
>>> private static final long serialVersionUID = 1L;
>>> }
>>>   private class RuntimeExceptionB extends RuntimeException {
>>> private static final long serialVersionUID = 1L;
>>> }
>>>   private class RuntimeExceptionBB extends RuntimeExceptionB {
>>> private static final long serialVersionUID = 1L;
>>> }
>>>   private class GoodRuntimeExceptionAMapper implements
>>> ExceptionMapper<RuntimeExceptionA> {
>>>
>>> @Override
>>> public Response toResponse(RuntimeExceptionA exception) {
>>> // TODO Auto-generated method stub
>>> return null;
>>> }
>>> }
>>>   private class GoodRuntimeExceptionBMapper implements
>>> ExceptionMapper<RuntimeExceptionB> {
>>>
>>> @Override
>>> public Response toResponse(RuntimeExceptionB exception) {
>>> // TODO Auto-generated method stub
>>> return null;
>>> }
>>> }
>>>   public abstract class BadParentExceptionMapper<T extends Throwable>
>>> implements ExceptionMapper<T> {
>>> }
>>>   @Provider
>>> public class BadExceptionMapperA extends
>>> BadParentExceptionMapper<RuntimeExceptionA> {
>>>
>>> @Override
>>> public Response toResponse(RuntimeExceptionA exception) {
>>> return null;
>>> }
>>> }
>>>   @Provider
>>> public class BadExceptionMapperB extends
>>> BadParentExceptionMapper<RuntimeExceptionB> {
>>>
>>> @Override
>>> public Response toResponse(RuntimeExceptionB exception) {
>>> return null;
>>> }
>>> }
>>> }
>>>
>>>
>>>
>>> On Wed, Oct 22, 2014 at 8:06 AM, Lambert, Michael <
>>> michael@michaellambert.com> wrote:
>>>
>>>> Good to know Sergey we will look at it again today. Definitely
>>>> experiencing the behavior I described so we will look for some delta
>>>> between our code and the test
>>>> On Oct 22, 2014 5:50 AM, "Sergey Beryozkin" <sb...@gmail.com>
>>>> wrote:
>>>>
>>>>> ProviderFactoryTest has the following:
>>>>>
>>>>> private static class RuntimeExceptionMapper1
>>>>>          extends AbstractTestExceptionMapper<RuntimeException> {
>>>>>
>>>>>      }
>>>>>
>>>>>      private static class RuntimeExceptionMapper2
>>>>>          extends AbstractTestExceptionMapper<WebApplicationException> {
>>>>>
>>>>>      }
>>>>>
>>>>>      private static class AbstractTestExceptionMapper<T extends
>>>>> RuntimeException>
>>>>>          implements ExceptionMapper<T> {
>>>>>
>>>>>          public Response toResponse(T arg0) {
>>>>>              // TODO Auto-generated method stub
>>>>>              return null;
>>>>>          }
>>>>>
>>>>>      }
>>>>>
>>>>> This is identical to your example where you say the bug is expected,
>>>>> also note WebApplicationException is RuntimeException.
>>>>>
>>>>> @Test
>>>>>      public void testExceptionMappersHierarchyWithGenerics() throws
>>>>> Exception {
>>>>>          ServerProviderFactory pf = ServerProviderFactory.getInstance();
>>>>>          RuntimeExceptionMapper1 exMapper1 = new
>>>>> RuntimeExceptionMapper1();
>>>>>          pf.registerUserProvider(exMapper1);
>>>>>          RuntimeExceptionMapper2 exMapper2 = new
>>>>> RuntimeExceptionMapper2();
>>>>>          pf.registerUserProvider(exMapper2);
>>>>>          assertSame(exMapper1, pf.createExceptionMapper(RuntimeException.class,
>>>>> new MessageImpl()));
>>>>>          Object webExMapper = pf.createExceptionMapper(WebApplicationException.class,
>>>>> new MessageImpl());
>>>>>          assertSame(exMapper2, webExMapper);
>>>>>      }
>>>>>
>>>>> When RuntimeExceptionMapper2 is registered, RuntimeExceptionMapper1 is
>>>>> not picked for WebApplicationException. Updating the test not to register
>>>>> RuntimeExceptionMapper2 leads to RuntimeExceptionMapper1 being selected for
>>>>> WebApplicationException.
>>>>>
>>>>> Looks like it is all correct to me, may be the issue is there in 2.7.11
>>>>> but def not on the trunk/3.0.2
>>>>>
>>>>> Cheers, Sergey
>>>>>
>>>>> On 21/10/14 20:04, Lambert, Michael wrote:
>>>>>
>>>>>> To be clear:
>>>>>>
>>>>>> This bug will only manifest itself if two exception mapper are both
>>>>>> derived
>>>>>> from the same interface:
>>>>>>
>>>>>>       public class AbstractMapper<T extends Throwable> implements
>>>>>> ExceptionMapper<T> {
>>>>>>           ...
>>>>>>       }
>>>>>>
>>>>>>       public class FooMapper extends AbstractMapper<FooException> {
>>>>>>           ...
>>>>>>       }
>>>>>>
>>>>>>       // ProviderFactory.ClassComparator.compare will return "0" when
>>>>>> BarMapper is compared to FooMapper
>>>>>>       public class BarMapper extends AbstractMapper<BarException> {
>>>>>>           ...
>>>>>>       }
>>>>>>
>>>>>> If each exception mapper instance is derived from a DIFFERENT INTERFACE
>>>>>> everything works fine:
>>>>>>
>>>>>>       public interface IFooMapper extends ExceptionMapper<FooException>
>>>>>> {
>>>>>>           ...
>>>>>>       }
>>>>>>
>>>>>>       public class FooMapper extends implements IFooMapper  {
>>>>>>           ...
>>>>>>       }
>>>>>>
>>>>>>       public interface IBarMapper extends ExceptionMapper<BarException>
>>>>>> {
>>>>>>           ...
>>>>>>       }
>>>>>>
>>>>>>       // ProviderFactory.ClassComparator.compare will return "1" or -1
>>>>>> when
>>>>>> BarMapper is compared to FooMapper
>>>>>>       public class BarMapper extends implements IBarMapper {
>>>>>>           ...
>>>>>>       }
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Tue, Oct 21, 2014 at 2:34 PM, Lambert, Michael <
>>>>>> michael@michaellambert.com> wrote:
>>>>>>
>>>>>>   Guys... it looks like there is a bug in ProviderFactory$
>>>>>>> ClassComparator.
>>>>>>> Given two mappers it always ends up comparing them as if both mappers
>>>>>>> were
>>>>>>> ExceptionMapper<Throwable>. There must be a problem in the way the
>>>>>>> interfaces and "actual types" are derived (which is done in the
>>>>>>> InjectionUtils class).
>>>>>>>
>>>>>>> -Mike
>>>>>>>
>>>>>>> On Tue, Oct 21, 2014 at 1:24 PM, Lambert, Michael <
>>>>>>> michael@michaellambert.com> wrote:
>>>>>>>
>>>>>>>   Hello gentleman!
>>>>>>>>
>>>>>>>> My impression was that when implementing ExceptionMapper that the
>>>>>>>> mapper
>>>>>>>> of the nearest superclass of an exception would be used if an exact
>>>>>>>> exceptionmapper match to the exception didnt exist.
>>>>>>>>
>>>>>>>> For example if I created a FooException which extended BarException
>>>>>>>> I
>>>>>>>> would only have to create a BarExceptionMapper to catch and map both
>>>>>>>> types
>>>>>>>> of exceptions; the BarExceptionMapper would be used when a
>>>>>>>> FooException was
>>>>>>>> thrown.
>>>>>>>>
>>>>>>>> The red hat docs seem to reinforce this opinion:
>>>>>>>>
>>>>>>>>
>>>>>>>>      -
>>>>>>>>
>>>>>>>>      When any exception other than a WebApplicationException
>>>>>>>> exception, or
>>>>>>>>      one of its subclasses, is thrown, the runtime will check for an
>>>>>>>> appropriate
>>>>>>>>      exception mapper. An exception mapper is selected if it handles
>>>>>>>> the
>>>>>>>>      specific exception thrown. If there is not an exception mapper
>>>>>>>> for the
>>>>>>>>      specific exception that was thrown, the exception mapper for the
>>>>>>>> nearest
>>>>>>>>      superclass of the exception is selected.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> https://access.redhat.com/documentation/en-US/Red_Hat_
>>>>>>>> JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/
>>>>>>>> RESTExceptionMapper.html
>>>>>>>>
>>>>>>>> The reality is different for us however. In fact, if we create a
>>>>>>>> custom
>>>>>>>> WebApplicationExceptionMapper ClientErrorExceptions are not caught
>>>>>>>> by the
>>>>>>>> mapper. CXF seems to default to attempt to use whichever Mapper is
>>>>>>>> the
>>>>>>>> first one we registered (e.g. if we defined a FooExceptionMapper and
>>>>>>>> registered it, CXF would attempt to use that and throw an error
>>>>>>>> rather than
>>>>>>>> try to use the WebApplicationExceptionMapper).
>>>>>>>>
>>>>>>>> Can someone tell me what the expected behavior is? Is my question
>>>>>>>> clear?
>>>>>>>>
>>>>>>>> We are using CXF version 2.7.11.
>>>>>>>>
>>>>>>>> Thanks!
>>>>>>>>
>>>>>>>> Mike
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>> --
>>>>> Sergey Beryozkin
>>>>>
>>>>> Talend Community Coders
>>>>> http://coders.talend.com/
>>>>>
>>>>> Blog: http://sberyozkin.blogspot.com
>>>>>
>>>>
>>>
>>
>


Re: jax-rs exception mapping

Posted by "Lambert, Michael" <mi...@michaellambert.com>.
Correction the problem method is ProviderFactory.getGenericInterfaces. Its
not the comparator.

On Thu, Oct 23, 2014 at 4:55 PM, Lambert, Michael <
michael@michaellambert.com> wrote:

> Fleshed it out a bit more with comment. It looks like the
> ProviderFactory.Comparator will choose whichever class in the parent/child
> lineage which implements ExceptionMapper and base its ordering on that.
> This means that a parent class cannot implement ExceptionMapper unless the
> child ALSO implments ExceptionMapper.
>
> package foo.test;
>
> import static org.junit.Assert.*;
>
> import javax.ws.rs.core.Response;
> import javax.ws.rs.ext.ExceptionMapper;
> import javax.ws.rs.ext.Provider;
>
> import org.apache.cxf.jaxrs.provider.ProviderFactory;
> import org.apache.cxf.message.MessageImpl;
>
> public class ExceptionMapperTest {
>  @org.junit.Before
> public void setup() {
> ProviderFactory.getInstance().clearProviders();
> }
>  @org.junit.Test
> public void testBadCustomExceptionMappersHierarchyWithGenerics() throws
> Exception {
>  ProviderFactory pf = ProviderFactory.getInstance();
>  BadExceptionMapperA badExceptionMapperA = new BadExceptionMapperA();
> pf.registerUserProvider(badExceptionMapperA);
>  BadExceptionMapperB badExceptionMapperB = new BadExceptionMapperB();
> pf.registerUserProvider(badExceptionMapperB);
>  Object mapperResponse1 =
> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
> assertSame(badExceptionMapperA, mapperResponse1);
>  Object mapperResponse2 =
> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
> assertSame(badExceptionMapperB, mapperResponse2);
>  Object mapperResponse3 =
> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
> assertSame(badExceptionMapperA, mapperResponse3);
>  Object mapperResponse4 =
> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
> assertSame(badExceptionMapperB, mapperResponse4);
> }
>  /**
>  * To fix the problem the mapper must NOT extend from a class that
> implements the ExceptionMapper interface. The parent class should be
>  * a normal java class and the mapper should implement the ExceptionMapper
> interface DIRECTLY!
>  *
>  * @throws Exception
>  */
> @org.junit.Test
> public void testFixedCustomExceptionMappersHierarchyWithGenerics() throws
> Exception {
>  ProviderFactory pf = ProviderFactory.getInstance();
>  FixedExceptionMapperA exceptionMapperA = new FixedExceptionMapperA();
> pf.registerUserProvider(exceptionMapperA);
>  FixedExceptionMapperB exceptionMapperB = new FixedExceptionMapperB();
> pf.registerUserProvider(exceptionMapperB);
>  Object mapperResponse1 =
> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
> assertSame(exceptionMapperA, mapperResponse1);
>  Object mapperResponse2 =
> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
> assertSame(exceptionMapperB, mapperResponse2);
>  Object mapperResponse3 =
> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
> assertSame(exceptionMapperA, mapperResponse3);
>  Object mapperResponse4 =
> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
> assertSame(exceptionMapperB, mapperResponse4);
> }
>
>
> @org.junit.Test
> public void testGoodExceptionMappersHierarchyWithGenerics() throws
> Exception {
>  ProviderFactory pf = ProviderFactory.getInstance();
>  GoodRuntimeExceptionAMapper runtimeExceptionAMapper = new
> GoodRuntimeExceptionAMapper();
> pf.registerUserProvider(runtimeExceptionAMapper);
>  GoodRuntimeExceptionBMapper runtimeExceptionBMapper = new
> GoodRuntimeExceptionBMapper();
> pf.registerUserProvider(runtimeExceptionBMapper);
>  Object mapperResponse1 =
> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
> assertSame(runtimeExceptionAMapper, mapperResponse1);
>  Object mapperResponse2 =
> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
> assertSame(runtimeExceptionBMapper, mapperResponse2);
>  Object mapperResponse3 =
> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
> assertSame(runtimeExceptionAMapper, mapperResponse3);
>  Object mapperResponse4 =
> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
> assertSame(runtimeExceptionBMapper, mapperResponse4);
> }
>  private class RuntimeExceptionA extends RuntimeException {
> private static final long serialVersionUID = 1L;
> }
>  private class RuntimeExceptionAA extends RuntimeExceptionA {
> private static final long serialVersionUID = 1L;
> }
>  private class RuntimeExceptionB extends RuntimeException {
> private static final long serialVersionUID = 1L;
> }
>  private class RuntimeExceptionBB extends RuntimeExceptionB {
> private static final long serialVersionUID = 1L;
> }
>  private class GoodRuntimeExceptionAMapper implements
> ExceptionMapper<RuntimeExceptionA> {
>
> @Override
> public Response toResponse(RuntimeExceptionA exception) {
> // TODO Auto-generated method stub
> return null;
> }
> }
>  private class GoodRuntimeExceptionBMapper implements
> ExceptionMapper<RuntimeExceptionB> {
>
> @Override
> public Response toResponse(RuntimeExceptionB exception) {
> // TODO Auto-generated method stub
> return null;
> }
> }
>  /**
>  * The parent implements ExceptionMapper and as a result will be what the
> ProviderFactory.Comparator class incorrectly chooses when sort ordering
>  * the mappers rather than its children
>  *
>  */
> private abstract class BadParentExceptionMapper<T extends Throwable>
> implements ExceptionMapper<T> {
> }
>  /**
>  * This does not implement ExceptionMapper and so its parent will be
> incorrectly selected by he ProviderFactory.Comparator class for sort
> ordering
>  *
>  */
> @Provider
> private class BadExceptionMapperA extends
> BadParentExceptionMapper<RuntimeExceptionA> {
>
> @Override
> public Response toResponse(RuntimeExceptionA exception) {
> return null;
> }
> }
>  /**
>  * This does not implement ExceptionMapper and so its parent will be
> incorrectly selected by he ProviderFactory.Comparator class for sort
> ordering
>  *
>  */
> @Provider
> private class BadExceptionMapperB extends
> BadParentExceptionMapper<RuntimeExceptionB> {
>
> @Override
> public Response toResponse(RuntimeExceptionB exception) {
> return null;
> }
> }
>  /**
>  * This does NOT implement ExceptionMapper
>  *
>  */
> private abstract class FixedParentExceptionMapper {
> }
>  /**
>  * The mapper implements ExceptionMapper directly
>  *
>  */
> @Provider
> private class FixedExceptionMapperA extends FixedParentExceptionMapper
> implements ExceptionMapper<RuntimeExceptionA> {
>
> @Override
> public Response toResponse(RuntimeExceptionA exception) {
> return null;
> }
> }
>  /**
>  * The mapper implements ExceptionMapper directly
>  *
>  */
> @Provider
> private class FixedExceptionMapperB extends FixedParentExceptionMapper
> implements ExceptionMapper<RuntimeExceptionB> {
>
> @Override
> public Response toResponse(RuntimeExceptionB exception) {
> return null;
> }
> }
> }
>
>
> On Thu, Oct 23, 2014 at 4:30 PM, Lambert, Michael <
> michael@michaellambert.com> wrote:
>
>> Sergei,
>>
>> Here is a test case that demonstrates the problem. Note that the only
>> difference between the good test and the bad test is that the mapper itself
>> is derived from a parent class. This test is based on cxf 2.7.11 but i
>> presume it will also work with 3.0 by swapping out the providerfactory
>> class with serviceproviderfactory.
>>
>>
>> package foo.test;
>>
>> import static org.junit.Assert.*;
>>
>> import javax.ws.rs.core.Response;
>> import javax.ws.rs.ext.ExceptionMapper;
>> import javax.ws.rs.ext.Provider;
>>
>> import org.apache.cxf.jaxrs.provider.ProviderFactory;
>> import org.apache.cxf.message.MessageImpl;
>>
>> public class ExceptionMapperTest {
>>  @org.junit.Before
>> public void setup() {
>> ProviderFactory.getInstance().clearProviders();
>> }
>>  @org.junit.Test
>> public void testBadCustomExceptionMappersHierarchyWithGenerics() throws
>> Exception {
>>  ProviderFactory pf = ProviderFactory.getInstance();
>>  BadExceptionMapperA badExceptionMapperA = new BadExceptionMapperA();
>> pf.registerUserProvider(badExceptionMapperA);
>>  BadExceptionMapperB badExceptionMapperB = new BadExceptionMapperB();
>> pf.registerUserProvider(badExceptionMapperB);
>>  Object mapperResponse1 =
>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>> assertSame(badExceptionMapperA, mapperResponse1);
>>  Object mapperResponse2 =
>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>> assertSame(badExceptionMapperB, mapperResponse2);
>>  Object mapperResponse3 =
>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>> assertSame(badExceptionMapperA, mapperResponse3);
>>  Object mapperResponse4 =
>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>> assertSame(badExceptionMapperB, mapperResponse4);
>> }
>>
>> @org.junit.Test
>> public void testGoodExceptionMappersHierarchyWithGenerics() throws
>> Exception {
>>  ProviderFactory pf = ProviderFactory.getInstance();
>>  GoodRuntimeExceptionAMapper runtimeExceptionAMapper = new
>> GoodRuntimeExceptionAMapper();
>> pf.registerUserProvider(runtimeExceptionAMapper);
>>  GoodRuntimeExceptionBMapper runtimeExceptionBMapper = new
>> GoodRuntimeExceptionBMapper();
>> pf.registerUserProvider(runtimeExceptionBMapper);
>>  Object mapperResponse1 =
>> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
>> assertSame(runtimeExceptionAMapper, mapperResponse1);
>>  Object mapperResponse2 =
>> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
>> assertSame(runtimeExceptionBMapper, mapperResponse2);
>>  Object mapperResponse3 =
>> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
>> assertSame(runtimeExceptionAMapper, mapperResponse3);
>>  Object mapperResponse4 =
>> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
>> assertSame(runtimeExceptionBMapper, mapperResponse4);
>> }
>>  private class RuntimeExceptionA extends RuntimeException {
>> private static final long serialVersionUID = 1L;
>> }
>>  private class RuntimeExceptionAA extends RuntimeExceptionA {
>> private static final long serialVersionUID = 1L;
>> }
>>  private class RuntimeExceptionB extends RuntimeException {
>> private static final long serialVersionUID = 1L;
>> }
>>  private class RuntimeExceptionBB extends RuntimeExceptionB {
>> private static final long serialVersionUID = 1L;
>> }
>>  private class GoodRuntimeExceptionAMapper implements
>> ExceptionMapper<RuntimeExceptionA> {
>>
>> @Override
>> public Response toResponse(RuntimeExceptionA exception) {
>> // TODO Auto-generated method stub
>> return null;
>> }
>> }
>>  private class GoodRuntimeExceptionBMapper implements
>> ExceptionMapper<RuntimeExceptionB> {
>>
>> @Override
>> public Response toResponse(RuntimeExceptionB exception) {
>> // TODO Auto-generated method stub
>> return null;
>> }
>> }
>>  public abstract class BadParentExceptionMapper<T extends Throwable>
>> implements ExceptionMapper<T> {
>> }
>>  @Provider
>> public class BadExceptionMapperA extends
>> BadParentExceptionMapper<RuntimeExceptionA> {
>>
>> @Override
>> public Response toResponse(RuntimeExceptionA exception) {
>> return null;
>> }
>> }
>>  @Provider
>> public class BadExceptionMapperB extends
>> BadParentExceptionMapper<RuntimeExceptionB> {
>>
>> @Override
>> public Response toResponse(RuntimeExceptionB exception) {
>> return null;
>> }
>> }
>> }
>>
>>
>>
>> On Wed, Oct 22, 2014 at 8:06 AM, Lambert, Michael <
>> michael@michaellambert.com> wrote:
>>
>>> Good to know Sergey we will look at it again today. Definitely
>>> experiencing the behavior I described so we will look for some delta
>>> between our code and the test
>>> On Oct 22, 2014 5:50 AM, "Sergey Beryozkin" <sb...@gmail.com>
>>> wrote:
>>>
>>>> ProviderFactoryTest has the following:
>>>>
>>>> private static class RuntimeExceptionMapper1
>>>>         extends AbstractTestExceptionMapper<RuntimeException> {
>>>>
>>>>     }
>>>>
>>>>     private static class RuntimeExceptionMapper2
>>>>         extends AbstractTestExceptionMapper<WebApplicationException> {
>>>>
>>>>     }
>>>>
>>>>     private static class AbstractTestExceptionMapper<T extends
>>>> RuntimeException>
>>>>         implements ExceptionMapper<T> {
>>>>
>>>>         public Response toResponse(T arg0) {
>>>>             // TODO Auto-generated method stub
>>>>             return null;
>>>>         }
>>>>
>>>>     }
>>>>
>>>> This is identical to your example where you say the bug is expected,
>>>> also note WebApplicationException is RuntimeException.
>>>>
>>>> @Test
>>>>     public void testExceptionMappersHierarchyWithGenerics() throws
>>>> Exception {
>>>>         ServerProviderFactory pf = ServerProviderFactory.getInstance();
>>>>         RuntimeExceptionMapper1 exMapper1 = new
>>>> RuntimeExceptionMapper1();
>>>>         pf.registerUserProvider(exMapper1);
>>>>         RuntimeExceptionMapper2 exMapper2 = new
>>>> RuntimeExceptionMapper2();
>>>>         pf.registerUserProvider(exMapper2);
>>>>         assertSame(exMapper1, pf.createExceptionMapper(RuntimeException.class,
>>>> new MessageImpl()));
>>>>         Object webExMapper = pf.createExceptionMapper(WebApplicationException.class,
>>>> new MessageImpl());
>>>>         assertSame(exMapper2, webExMapper);
>>>>     }
>>>>
>>>> When RuntimeExceptionMapper2 is registered, RuntimeExceptionMapper1 is
>>>> not picked for WebApplicationException. Updating the test not to register
>>>> RuntimeExceptionMapper2 leads to RuntimeExceptionMapper1 being selected for
>>>> WebApplicationException.
>>>>
>>>> Looks like it is all correct to me, may be the issue is there in 2.7.11
>>>> but def not on the trunk/3.0.2
>>>>
>>>> Cheers, Sergey
>>>>
>>>> On 21/10/14 20:04, Lambert, Michael wrote:
>>>>
>>>>> To be clear:
>>>>>
>>>>> This bug will only manifest itself if two exception mapper are both
>>>>> derived
>>>>> from the same interface:
>>>>>
>>>>>      public class AbstractMapper<T extends Throwable> implements
>>>>> ExceptionMapper<T> {
>>>>>          ...
>>>>>      }
>>>>>
>>>>>      public class FooMapper extends AbstractMapper<FooException> {
>>>>>          ...
>>>>>      }
>>>>>
>>>>>      // ProviderFactory.ClassComparator.compare will return "0" when
>>>>> BarMapper is compared to FooMapper
>>>>>      public class BarMapper extends AbstractMapper<BarException> {
>>>>>          ...
>>>>>      }
>>>>>
>>>>> If each exception mapper instance is derived from a DIFFERENT INTERFACE
>>>>> everything works fine:
>>>>>
>>>>>      public interface IFooMapper extends ExceptionMapper<FooException>
>>>>> {
>>>>>          ...
>>>>>      }
>>>>>
>>>>>      public class FooMapper extends implements IFooMapper  {
>>>>>          ...
>>>>>      }
>>>>>
>>>>>      public interface IBarMapper extends ExceptionMapper<BarException>
>>>>> {
>>>>>          ...
>>>>>      }
>>>>>
>>>>>      // ProviderFactory.ClassComparator.compare will return "1" or -1
>>>>> when
>>>>> BarMapper is compared to FooMapper
>>>>>      public class BarMapper extends implements IBarMapper {
>>>>>          ...
>>>>>      }
>>>>>
>>>>>
>>>>>
>>>>> On Tue, Oct 21, 2014 at 2:34 PM, Lambert, Michael <
>>>>> michael@michaellambert.com> wrote:
>>>>>
>>>>>  Guys... it looks like there is a bug in ProviderFactory$
>>>>>> ClassComparator.
>>>>>> Given two mappers it always ends up comparing them as if both mappers
>>>>>> were
>>>>>> ExceptionMapper<Throwable>. There must be a problem in the way the
>>>>>> interfaces and "actual types" are derived (which is done in the
>>>>>> InjectionUtils class).
>>>>>>
>>>>>> -Mike
>>>>>>
>>>>>> On Tue, Oct 21, 2014 at 1:24 PM, Lambert, Michael <
>>>>>> michael@michaellambert.com> wrote:
>>>>>>
>>>>>>  Hello gentleman!
>>>>>>>
>>>>>>> My impression was that when implementing ExceptionMapper that the
>>>>>>> mapper
>>>>>>> of the nearest superclass of an exception would be used if an exact
>>>>>>> exceptionmapper match to the exception didnt exist.
>>>>>>>
>>>>>>> For example if I created a FooException which extended BarException
>>>>>>> I
>>>>>>> would only have to create a BarExceptionMapper to catch and map both
>>>>>>> types
>>>>>>> of exceptions; the BarExceptionMapper would be used when a
>>>>>>> FooException was
>>>>>>> thrown.
>>>>>>>
>>>>>>> The red hat docs seem to reinforce this opinion:
>>>>>>>
>>>>>>>
>>>>>>>     -
>>>>>>>
>>>>>>>     When any exception other than a WebApplicationException
>>>>>>> exception, or
>>>>>>>     one of its subclasses, is thrown, the runtime will check for an
>>>>>>> appropriate
>>>>>>>     exception mapper. An exception mapper is selected if it handles
>>>>>>> the
>>>>>>>     specific exception thrown. If there is not an exception mapper
>>>>>>> for the
>>>>>>>     specific exception that was thrown, the exception mapper for the
>>>>>>> nearest
>>>>>>>     superclass of the exception is selected.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> https://access.redhat.com/documentation/en-US/Red_Hat_
>>>>>>> JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/
>>>>>>> RESTExceptionMapper.html
>>>>>>>
>>>>>>> The reality is different for us however. In fact, if we create a
>>>>>>> custom
>>>>>>> WebApplicationExceptionMapper ClientErrorExceptions are not caught
>>>>>>> by the
>>>>>>> mapper. CXF seems to default to attempt to use whichever Mapper is
>>>>>>> the
>>>>>>> first one we registered (e.g. if we defined a FooExceptionMapper and
>>>>>>> registered it, CXF would attempt to use that and throw an error
>>>>>>> rather than
>>>>>>> try to use the WebApplicationExceptionMapper).
>>>>>>>
>>>>>>> Can someone tell me what the expected behavior is? Is my question
>>>>>>> clear?
>>>>>>>
>>>>>>> We are using CXF version 2.7.11.
>>>>>>>
>>>>>>> Thanks!
>>>>>>>
>>>>>>> Mike
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>> --
>>>> Sergey Beryozkin
>>>>
>>>> Talend Community Coders
>>>> http://coders.talend.com/
>>>>
>>>> Blog: http://sberyozkin.blogspot.com
>>>>
>>>
>>
>

Re: jax-rs exception mapping

Posted by "Lambert, Michael" <mi...@michaellambert.com>.
Fleshed it out a bit more with comment. It looks like the
ProviderFactory.Comparator will choose whichever class in the parent/child
lineage which implements ExceptionMapper and base its ordering on that.
This means that a parent class cannot implement ExceptionMapper unless the
child ALSO implments ExceptionMapper.

package foo.test;

import static org.junit.Assert.*;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

import org.apache.cxf.jaxrs.provider.ProviderFactory;
import org.apache.cxf.message.MessageImpl;

public class ExceptionMapperTest {
 @org.junit.Before
public void setup() {
ProviderFactory.getInstance().clearProviders();
}
 @org.junit.Test
public void testBadCustomExceptionMappersHierarchyWithGenerics() throws
Exception {
 ProviderFactory pf = ProviderFactory.getInstance();
 BadExceptionMapperA badExceptionMapperA = new BadExceptionMapperA();
pf.registerUserProvider(badExceptionMapperA);
 BadExceptionMapperB badExceptionMapperB = new BadExceptionMapperB();
pf.registerUserProvider(badExceptionMapperB);
 Object mapperResponse1 = pf.createExceptionMapper(RuntimeExceptionA.class,
new MessageImpl());
assertSame(badExceptionMapperA, mapperResponse1);
 Object mapperResponse2 = pf.createExceptionMapper(RuntimeExceptionB.class,
new MessageImpl());
assertSame(badExceptionMapperB, mapperResponse2);
 Object mapperResponse3 =
pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
assertSame(badExceptionMapperA, mapperResponse3);
 Object mapperResponse4 =
pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
assertSame(badExceptionMapperB, mapperResponse4);
}
 /**
 * To fix the problem the mapper must NOT extend from a class that
implements the ExceptionMapper interface. The parent class should be
 * a normal java class and the mapper should implement the ExceptionMapper
interface DIRECTLY!
 *
 * @throws Exception
 */
@org.junit.Test
public void testFixedCustomExceptionMappersHierarchyWithGenerics() throws
Exception {
 ProviderFactory pf = ProviderFactory.getInstance();
 FixedExceptionMapperA exceptionMapperA = new FixedExceptionMapperA();
pf.registerUserProvider(exceptionMapperA);
 FixedExceptionMapperB exceptionMapperB = new FixedExceptionMapperB();
pf.registerUserProvider(exceptionMapperB);
 Object mapperResponse1 = pf.createExceptionMapper(RuntimeExceptionA.class,
new MessageImpl());
assertSame(exceptionMapperA, mapperResponse1);
 Object mapperResponse2 = pf.createExceptionMapper(RuntimeExceptionB.class,
new MessageImpl());
assertSame(exceptionMapperB, mapperResponse2);
 Object mapperResponse3 =
pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
assertSame(exceptionMapperA, mapperResponse3);
 Object mapperResponse4 =
pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
assertSame(exceptionMapperB, mapperResponse4);
}


@org.junit.Test
public void testGoodExceptionMappersHierarchyWithGenerics() throws
Exception {
 ProviderFactory pf = ProviderFactory.getInstance();
 GoodRuntimeExceptionAMapper runtimeExceptionAMapper = new
GoodRuntimeExceptionAMapper();
pf.registerUserProvider(runtimeExceptionAMapper);
 GoodRuntimeExceptionBMapper runtimeExceptionBMapper = new
GoodRuntimeExceptionBMapper();
pf.registerUserProvider(runtimeExceptionBMapper);
 Object mapperResponse1 = pf.createExceptionMapper(RuntimeExceptionA.class,
new MessageImpl());
assertSame(runtimeExceptionAMapper, mapperResponse1);
 Object mapperResponse2 = pf.createExceptionMapper(RuntimeExceptionB.class,
new MessageImpl());
assertSame(runtimeExceptionBMapper, mapperResponse2);
 Object mapperResponse3 =
pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
assertSame(runtimeExceptionAMapper, mapperResponse3);
 Object mapperResponse4 =
pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
assertSame(runtimeExceptionBMapper, mapperResponse4);
}
 private class RuntimeExceptionA extends RuntimeException {
private static final long serialVersionUID = 1L;
}
 private class RuntimeExceptionAA extends RuntimeExceptionA {
private static final long serialVersionUID = 1L;
}
 private class RuntimeExceptionB extends RuntimeException {
private static final long serialVersionUID = 1L;
}
 private class RuntimeExceptionBB extends RuntimeExceptionB {
private static final long serialVersionUID = 1L;
}
 private class GoodRuntimeExceptionAMapper implements
ExceptionMapper<RuntimeExceptionA> {

@Override
public Response toResponse(RuntimeExceptionA exception) {
// TODO Auto-generated method stub
return null;
}
}
 private class GoodRuntimeExceptionBMapper implements
ExceptionMapper<RuntimeExceptionB> {

@Override
public Response toResponse(RuntimeExceptionB exception) {
// TODO Auto-generated method stub
return null;
}
}
 /**
 * The parent implements ExceptionMapper and as a result will be what the
ProviderFactory.Comparator class incorrectly chooses when sort ordering
 * the mappers rather than its children
 *
 */
private abstract class BadParentExceptionMapper<T extends Throwable>
implements ExceptionMapper<T> {
}
 /**
 * This does not implement ExceptionMapper and so its parent will be
incorrectly selected by he ProviderFactory.Comparator class for sort
ordering
 *
 */
@Provider
private class BadExceptionMapperA extends
BadParentExceptionMapper<RuntimeExceptionA> {

@Override
public Response toResponse(RuntimeExceptionA exception) {
return null;
}
}
 /**
 * This does not implement ExceptionMapper and so its parent will be
incorrectly selected by he ProviderFactory.Comparator class for sort
ordering
 *
 */
@Provider
private class BadExceptionMapperB extends
BadParentExceptionMapper<RuntimeExceptionB> {

@Override
public Response toResponse(RuntimeExceptionB exception) {
return null;
}
}
 /**
 * This does NOT implement ExceptionMapper
 *
 */
private abstract class FixedParentExceptionMapper {
}
 /**
 * The mapper implements ExceptionMapper directly
 *
 */
@Provider
private class FixedExceptionMapperA extends FixedParentExceptionMapper
implements ExceptionMapper<RuntimeExceptionA> {

@Override
public Response toResponse(RuntimeExceptionA exception) {
return null;
}
}
 /**
 * The mapper implements ExceptionMapper directly
 *
 */
@Provider
private class FixedExceptionMapperB extends FixedParentExceptionMapper
implements ExceptionMapper<RuntimeExceptionB> {

@Override
public Response toResponse(RuntimeExceptionB exception) {
return null;
}
}
}


On Thu, Oct 23, 2014 at 4:30 PM, Lambert, Michael <
michael@michaellambert.com> wrote:

> Sergei,
>
> Here is a test case that demonstrates the problem. Note that the only
> difference between the good test and the bad test is that the mapper itself
> is derived from a parent class. This test is based on cxf 2.7.11 but i
> presume it will also work with 3.0 by swapping out the providerfactory
> class with serviceproviderfactory.
>
>
> package foo.test;
>
> import static org.junit.Assert.*;
>
> import javax.ws.rs.core.Response;
> import javax.ws.rs.ext.ExceptionMapper;
> import javax.ws.rs.ext.Provider;
>
> import org.apache.cxf.jaxrs.provider.ProviderFactory;
> import org.apache.cxf.message.MessageImpl;
>
> public class ExceptionMapperTest {
>  @org.junit.Before
> public void setup() {
> ProviderFactory.getInstance().clearProviders();
> }
>  @org.junit.Test
> public void testBadCustomExceptionMappersHierarchyWithGenerics() throws
> Exception {
>  ProviderFactory pf = ProviderFactory.getInstance();
>  BadExceptionMapperA badExceptionMapperA = new BadExceptionMapperA();
> pf.registerUserProvider(badExceptionMapperA);
>  BadExceptionMapperB badExceptionMapperB = new BadExceptionMapperB();
> pf.registerUserProvider(badExceptionMapperB);
>  Object mapperResponse1 =
> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
> assertSame(badExceptionMapperA, mapperResponse1);
>  Object mapperResponse2 =
> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
> assertSame(badExceptionMapperB, mapperResponse2);
>  Object mapperResponse3 =
> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
> assertSame(badExceptionMapperA, mapperResponse3);
>  Object mapperResponse4 =
> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
> assertSame(badExceptionMapperB, mapperResponse4);
> }
>
> @org.junit.Test
> public void testGoodExceptionMappersHierarchyWithGenerics() throws
> Exception {
>  ProviderFactory pf = ProviderFactory.getInstance();
>  GoodRuntimeExceptionAMapper runtimeExceptionAMapper = new
> GoodRuntimeExceptionAMapper();
> pf.registerUserProvider(runtimeExceptionAMapper);
>  GoodRuntimeExceptionBMapper runtimeExceptionBMapper = new
> GoodRuntimeExceptionBMapper();
> pf.registerUserProvider(runtimeExceptionBMapper);
>  Object mapperResponse1 =
> pf.createExceptionMapper(RuntimeExceptionA.class, new MessageImpl());
> assertSame(runtimeExceptionAMapper, mapperResponse1);
>  Object mapperResponse2 =
> pf.createExceptionMapper(RuntimeExceptionB.class, new MessageImpl());
> assertSame(runtimeExceptionBMapper, mapperResponse2);
>  Object mapperResponse3 =
> pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
> assertSame(runtimeExceptionAMapper, mapperResponse3);
>  Object mapperResponse4 =
> pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
> assertSame(runtimeExceptionBMapper, mapperResponse4);
> }
>  private class RuntimeExceptionA extends RuntimeException {
> private static final long serialVersionUID = 1L;
> }
>  private class RuntimeExceptionAA extends RuntimeExceptionA {
> private static final long serialVersionUID = 1L;
> }
>  private class RuntimeExceptionB extends RuntimeException {
> private static final long serialVersionUID = 1L;
> }
>  private class RuntimeExceptionBB extends RuntimeExceptionB {
> private static final long serialVersionUID = 1L;
> }
>  private class GoodRuntimeExceptionAMapper implements
> ExceptionMapper<RuntimeExceptionA> {
>
> @Override
> public Response toResponse(RuntimeExceptionA exception) {
> // TODO Auto-generated method stub
> return null;
> }
> }
>  private class GoodRuntimeExceptionBMapper implements
> ExceptionMapper<RuntimeExceptionB> {
>
> @Override
> public Response toResponse(RuntimeExceptionB exception) {
> // TODO Auto-generated method stub
> return null;
> }
> }
>  public abstract class BadParentExceptionMapper<T extends Throwable>
> implements ExceptionMapper<T> {
> }
>  @Provider
> public class BadExceptionMapperA extends
> BadParentExceptionMapper<RuntimeExceptionA> {
>
> @Override
> public Response toResponse(RuntimeExceptionA exception) {
> return null;
> }
> }
>  @Provider
> public class BadExceptionMapperB extends
> BadParentExceptionMapper<RuntimeExceptionB> {
>
> @Override
> public Response toResponse(RuntimeExceptionB exception) {
> return null;
> }
> }
> }
>
>
>
> On Wed, Oct 22, 2014 at 8:06 AM, Lambert, Michael <
> michael@michaellambert.com> wrote:
>
>> Good to know Sergey we will look at it again today. Definitely
>> experiencing the behavior I described so we will look for some delta
>> between our code and the test
>> On Oct 22, 2014 5:50 AM, "Sergey Beryozkin" <sb...@gmail.com> wrote:
>>
>>> ProviderFactoryTest has the following:
>>>
>>> private static class RuntimeExceptionMapper1
>>>         extends AbstractTestExceptionMapper<RuntimeException> {
>>>
>>>     }
>>>
>>>     private static class RuntimeExceptionMapper2
>>>         extends AbstractTestExceptionMapper<WebApplicationException> {
>>>
>>>     }
>>>
>>>     private static class AbstractTestExceptionMapper<T extends
>>> RuntimeException>
>>>         implements ExceptionMapper<T> {
>>>
>>>         public Response toResponse(T arg0) {
>>>             // TODO Auto-generated method stub
>>>             return null;
>>>         }
>>>
>>>     }
>>>
>>> This is identical to your example where you say the bug is expected,
>>> also note WebApplicationException is RuntimeException.
>>>
>>> @Test
>>>     public void testExceptionMappersHierarchyWithGenerics() throws
>>> Exception {
>>>         ServerProviderFactory pf = ServerProviderFactory.getInstance();
>>>         RuntimeExceptionMapper1 exMapper1 = new
>>> RuntimeExceptionMapper1();
>>>         pf.registerUserProvider(exMapper1);
>>>         RuntimeExceptionMapper2 exMapper2 = new
>>> RuntimeExceptionMapper2();
>>>         pf.registerUserProvider(exMapper2);
>>>         assertSame(exMapper1, pf.createExceptionMapper(RuntimeException.class,
>>> new MessageImpl()));
>>>         Object webExMapper = pf.createExceptionMapper(WebApplicationException.class,
>>> new MessageImpl());
>>>         assertSame(exMapper2, webExMapper);
>>>     }
>>>
>>> When RuntimeExceptionMapper2 is registered, RuntimeExceptionMapper1 is
>>> not picked for WebApplicationException. Updating the test not to register
>>> RuntimeExceptionMapper2 leads to RuntimeExceptionMapper1 being selected for
>>> WebApplicationException.
>>>
>>> Looks like it is all correct to me, may be the issue is there in 2.7.11
>>> but def not on the trunk/3.0.2
>>>
>>> Cheers, Sergey
>>>
>>> On 21/10/14 20:04, Lambert, Michael wrote:
>>>
>>>> To be clear:
>>>>
>>>> This bug will only manifest itself if two exception mapper are both
>>>> derived
>>>> from the same interface:
>>>>
>>>>      public class AbstractMapper<T extends Throwable> implements
>>>> ExceptionMapper<T> {
>>>>          ...
>>>>      }
>>>>
>>>>      public class FooMapper extends AbstractMapper<FooException> {
>>>>          ...
>>>>      }
>>>>
>>>>      // ProviderFactory.ClassComparator.compare will return "0" when
>>>> BarMapper is compared to FooMapper
>>>>      public class BarMapper extends AbstractMapper<BarException> {
>>>>          ...
>>>>      }
>>>>
>>>> If each exception mapper instance is derived from a DIFFERENT INTERFACE
>>>> everything works fine:
>>>>
>>>>      public interface IFooMapper extends ExceptionMapper<FooException> {
>>>>          ...
>>>>      }
>>>>
>>>>      public class FooMapper extends implements IFooMapper  {
>>>>          ...
>>>>      }
>>>>
>>>>      public interface IBarMapper extends ExceptionMapper<BarException> {
>>>>          ...
>>>>      }
>>>>
>>>>      // ProviderFactory.ClassComparator.compare will return "1" or -1
>>>> when
>>>> BarMapper is compared to FooMapper
>>>>      public class BarMapper extends implements IBarMapper {
>>>>          ...
>>>>      }
>>>>
>>>>
>>>>
>>>> On Tue, Oct 21, 2014 at 2:34 PM, Lambert, Michael <
>>>> michael@michaellambert.com> wrote:
>>>>
>>>>  Guys... it looks like there is a bug in ProviderFactory$
>>>>> ClassComparator.
>>>>> Given two mappers it always ends up comparing them as if both mappers
>>>>> were
>>>>> ExceptionMapper<Throwable>. There must be a problem in the way the
>>>>> interfaces and "actual types" are derived (which is done in the
>>>>> InjectionUtils class).
>>>>>
>>>>> -Mike
>>>>>
>>>>> On Tue, Oct 21, 2014 at 1:24 PM, Lambert, Michael <
>>>>> michael@michaellambert.com> wrote:
>>>>>
>>>>>  Hello gentleman!
>>>>>>
>>>>>> My impression was that when implementing ExceptionMapper that the
>>>>>> mapper
>>>>>> of the nearest superclass of an exception would be used if an exact
>>>>>> exceptionmapper match to the exception didnt exist.
>>>>>>
>>>>>> For example if I created a FooException which extended BarException  I
>>>>>> would only have to create a BarExceptionMapper to catch and map both
>>>>>> types
>>>>>> of exceptions; the BarExceptionMapper would be used when a
>>>>>> FooException was
>>>>>> thrown.
>>>>>>
>>>>>> The red hat docs seem to reinforce this opinion:
>>>>>>
>>>>>>
>>>>>>     -
>>>>>>
>>>>>>     When any exception other than a WebApplicationException
>>>>>> exception, or
>>>>>>     one of its subclasses, is thrown, the runtime will check for an
>>>>>> appropriate
>>>>>>     exception mapper. An exception mapper is selected if it handles
>>>>>> the
>>>>>>     specific exception thrown. If there is not an exception mapper
>>>>>> for the
>>>>>>     specific exception that was thrown, the exception mapper for the
>>>>>> nearest
>>>>>>     superclass of the exception is selected.
>>>>>>
>>>>>>
>>>>>>
>>>>>> https://access.redhat.com/documentation/en-US/Red_Hat_
>>>>>> JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/
>>>>>> RESTExceptionMapper.html
>>>>>>
>>>>>> The reality is different for us however. In fact, if we create a
>>>>>> custom
>>>>>> WebApplicationExceptionMapper ClientErrorExceptions are not caught by
>>>>>> the
>>>>>> mapper. CXF seems to default to attempt to use whichever Mapper is the
>>>>>> first one we registered (e.g. if we defined a FooExceptionMapper and
>>>>>> registered it, CXF would attempt to use that and throw an error
>>>>>> rather than
>>>>>> try to use the WebApplicationExceptionMapper).
>>>>>>
>>>>>> Can someone tell me what the expected behavior is? Is my question
>>>>>> clear?
>>>>>>
>>>>>> We are using CXF version 2.7.11.
>>>>>>
>>>>>> Thanks!
>>>>>>
>>>>>> Mike
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>> --
>>> Sergey Beryozkin
>>>
>>> Talend Community Coders
>>> http://coders.talend.com/
>>>
>>> Blog: http://sberyozkin.blogspot.com
>>>
>>
>

Re: jax-rs exception mapping

Posted by "Lambert, Michael" <mi...@michaellambert.com>.
Sergei,

Here is a test case that demonstrates the problem. Note that the only
difference between the good test and the bad test is that the mapper itself
is derived from a parent class. This test is based on cxf 2.7.11 but i
presume it will also work with 3.0 by swapping out the providerfactory
class with serviceproviderfactory.


package foo.test;

import static org.junit.Assert.*;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

import org.apache.cxf.jaxrs.provider.ProviderFactory;
import org.apache.cxf.message.MessageImpl;

public class ExceptionMapperTest {
 @org.junit.Before
public void setup() {
ProviderFactory.getInstance().clearProviders();
}
 @org.junit.Test
public void testBadCustomExceptionMappersHierarchyWithGenerics() throws
Exception {
 ProviderFactory pf = ProviderFactory.getInstance();
 BadExceptionMapperA badExceptionMapperA = new BadExceptionMapperA();
pf.registerUserProvider(badExceptionMapperA);
 BadExceptionMapperB badExceptionMapperB = new BadExceptionMapperB();
pf.registerUserProvider(badExceptionMapperB);
 Object mapperResponse1 = pf.createExceptionMapper(RuntimeExceptionA.class,
new MessageImpl());
assertSame(badExceptionMapperA, mapperResponse1);
 Object mapperResponse2 = pf.createExceptionMapper(RuntimeExceptionB.class,
new MessageImpl());
assertSame(badExceptionMapperB, mapperResponse2);
 Object mapperResponse3 =
pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
assertSame(badExceptionMapperA, mapperResponse3);
 Object mapperResponse4 =
pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
assertSame(badExceptionMapperB, mapperResponse4);
}

@org.junit.Test
public void testGoodExceptionMappersHierarchyWithGenerics() throws
Exception {
 ProviderFactory pf = ProviderFactory.getInstance();
 GoodRuntimeExceptionAMapper runtimeExceptionAMapper = new
GoodRuntimeExceptionAMapper();
pf.registerUserProvider(runtimeExceptionAMapper);
 GoodRuntimeExceptionBMapper runtimeExceptionBMapper = new
GoodRuntimeExceptionBMapper();
pf.registerUserProvider(runtimeExceptionBMapper);
 Object mapperResponse1 = pf.createExceptionMapper(RuntimeExceptionA.class,
new MessageImpl());
assertSame(runtimeExceptionAMapper, mapperResponse1);
 Object mapperResponse2 = pf.createExceptionMapper(RuntimeExceptionB.class,
new MessageImpl());
assertSame(runtimeExceptionBMapper, mapperResponse2);
 Object mapperResponse3 =
pf.createExceptionMapper(RuntimeExceptionAA.class, new MessageImpl());
assertSame(runtimeExceptionAMapper, mapperResponse3);
 Object mapperResponse4 =
pf.createExceptionMapper(RuntimeExceptionBB.class, new MessageImpl());
assertSame(runtimeExceptionBMapper, mapperResponse4);
}
 private class RuntimeExceptionA extends RuntimeException {
private static final long serialVersionUID = 1L;
}
 private class RuntimeExceptionAA extends RuntimeExceptionA {
private static final long serialVersionUID = 1L;
}
 private class RuntimeExceptionB extends RuntimeException {
private static final long serialVersionUID = 1L;
}
 private class RuntimeExceptionBB extends RuntimeExceptionB {
private static final long serialVersionUID = 1L;
}
 private class GoodRuntimeExceptionAMapper implements
ExceptionMapper<RuntimeExceptionA> {

@Override
public Response toResponse(RuntimeExceptionA exception) {
// TODO Auto-generated method stub
return null;
}
}
 private class GoodRuntimeExceptionBMapper implements
ExceptionMapper<RuntimeExceptionB> {

@Override
public Response toResponse(RuntimeExceptionB exception) {
// TODO Auto-generated method stub
return null;
}
}
 public abstract class BadParentExceptionMapper<T extends Throwable>
implements ExceptionMapper<T> {
}
 @Provider
public class BadExceptionMapperA extends
BadParentExceptionMapper<RuntimeExceptionA> {

@Override
public Response toResponse(RuntimeExceptionA exception) {
return null;
}
}
 @Provider
public class BadExceptionMapperB extends
BadParentExceptionMapper<RuntimeExceptionB> {

@Override
public Response toResponse(RuntimeExceptionB exception) {
return null;
}
}
}



On Wed, Oct 22, 2014 at 8:06 AM, Lambert, Michael <
michael@michaellambert.com> wrote:

> Good to know Sergey we will look at it again today. Definitely
> experiencing the behavior I described so we will look for some delta
> between our code and the test
> On Oct 22, 2014 5:50 AM, "Sergey Beryozkin" <sb...@gmail.com> wrote:
>
>> ProviderFactoryTest has the following:
>>
>> private static class RuntimeExceptionMapper1
>>         extends AbstractTestExceptionMapper<RuntimeException> {
>>
>>     }
>>
>>     private static class RuntimeExceptionMapper2
>>         extends AbstractTestExceptionMapper<WebApplicationException> {
>>
>>     }
>>
>>     private static class AbstractTestExceptionMapper<T extends
>> RuntimeException>
>>         implements ExceptionMapper<T> {
>>
>>         public Response toResponse(T arg0) {
>>             // TODO Auto-generated method stub
>>             return null;
>>         }
>>
>>     }
>>
>> This is identical to your example where you say the bug is expected, also
>> note WebApplicationException is RuntimeException.
>>
>> @Test
>>     public void testExceptionMappersHierarchyWithGenerics() throws
>> Exception {
>>         ServerProviderFactory pf = ServerProviderFactory.getInstance();
>>         RuntimeExceptionMapper1 exMapper1 = new RuntimeExceptionMapper1();
>>         pf.registerUserProvider(exMapper1);
>>         RuntimeExceptionMapper2 exMapper2 = new RuntimeExceptionMapper2();
>>         pf.registerUserProvider(exMapper2);
>>         assertSame(exMapper1, pf.createExceptionMapper(RuntimeException.class,
>> new MessageImpl()));
>>         Object webExMapper = pf.createExceptionMapper(WebApplicationException.class,
>> new MessageImpl());
>>         assertSame(exMapper2, webExMapper);
>>     }
>>
>> When RuntimeExceptionMapper2 is registered, RuntimeExceptionMapper1 is
>> not picked for WebApplicationException. Updating the test not to register
>> RuntimeExceptionMapper2 leads to RuntimeExceptionMapper1 being selected for
>> WebApplicationException.
>>
>> Looks like it is all correct to me, may be the issue is there in 2.7.11
>> but def not on the trunk/3.0.2
>>
>> Cheers, Sergey
>>
>> On 21/10/14 20:04, Lambert, Michael wrote:
>>
>>> To be clear:
>>>
>>> This bug will only manifest itself if two exception mapper are both
>>> derived
>>> from the same interface:
>>>
>>>      public class AbstractMapper<T extends Throwable> implements
>>> ExceptionMapper<T> {
>>>          ...
>>>      }
>>>
>>>      public class FooMapper extends AbstractMapper<FooException> {
>>>          ...
>>>      }
>>>
>>>      // ProviderFactory.ClassComparator.compare will return "0" when
>>> BarMapper is compared to FooMapper
>>>      public class BarMapper extends AbstractMapper<BarException> {
>>>          ...
>>>      }
>>>
>>> If each exception mapper instance is derived from a DIFFERENT INTERFACE
>>> everything works fine:
>>>
>>>      public interface IFooMapper extends ExceptionMapper<FooException> {
>>>          ...
>>>      }
>>>
>>>      public class FooMapper extends implements IFooMapper  {
>>>          ...
>>>      }
>>>
>>>      public interface IBarMapper extends ExceptionMapper<BarException> {
>>>          ...
>>>      }
>>>
>>>      // ProviderFactory.ClassComparator.compare will return "1" or -1
>>> when
>>> BarMapper is compared to FooMapper
>>>      public class BarMapper extends implements IBarMapper {
>>>          ...
>>>      }
>>>
>>>
>>>
>>> On Tue, Oct 21, 2014 at 2:34 PM, Lambert, Michael <
>>> michael@michaellambert.com> wrote:
>>>
>>>  Guys... it looks like there is a bug in ProviderFactory$
>>>> ClassComparator.
>>>> Given two mappers it always ends up comparing them as if both mappers
>>>> were
>>>> ExceptionMapper<Throwable>. There must be a problem in the way the
>>>> interfaces and "actual types" are derived (which is done in the
>>>> InjectionUtils class).
>>>>
>>>> -Mike
>>>>
>>>> On Tue, Oct 21, 2014 at 1:24 PM, Lambert, Michael <
>>>> michael@michaellambert.com> wrote:
>>>>
>>>>  Hello gentleman!
>>>>>
>>>>> My impression was that when implementing ExceptionMapper that the
>>>>> mapper
>>>>> of the nearest superclass of an exception would be used if an exact
>>>>> exceptionmapper match to the exception didnt exist.
>>>>>
>>>>> For example if I created a FooException which extended BarException  I
>>>>> would only have to create a BarExceptionMapper to catch and map both
>>>>> types
>>>>> of exceptions; the BarExceptionMapper would be used when a
>>>>> FooException was
>>>>> thrown.
>>>>>
>>>>> The red hat docs seem to reinforce this opinion:
>>>>>
>>>>>
>>>>>     -
>>>>>
>>>>>     When any exception other than a WebApplicationException exception,
>>>>> or
>>>>>     one of its subclasses, is thrown, the runtime will check for an
>>>>> appropriate
>>>>>     exception mapper. An exception mapper is selected if it handles the
>>>>>     specific exception thrown. If there is not an exception mapper for
>>>>> the
>>>>>     specific exception that was thrown, the exception mapper for the
>>>>> nearest
>>>>>     superclass of the exception is selected.
>>>>>
>>>>>
>>>>>
>>>>> https://access.redhat.com/documentation/en-US/Red_Hat_
>>>>> JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/
>>>>> RESTExceptionMapper.html
>>>>>
>>>>> The reality is different for us however. In fact, if we create a custom
>>>>> WebApplicationExceptionMapper ClientErrorExceptions are not caught by
>>>>> the
>>>>> mapper. CXF seems to default to attempt to use whichever Mapper is the
>>>>> first one we registered (e.g. if we defined a FooExceptionMapper and
>>>>> registered it, CXF would attempt to use that and throw an error rather
>>>>> than
>>>>> try to use the WebApplicationExceptionMapper).
>>>>>
>>>>> Can someone tell me what the expected behavior is? Is my question
>>>>> clear?
>>>>>
>>>>> We are using CXF version 2.7.11.
>>>>>
>>>>> Thanks!
>>>>>
>>>>> Mike
>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>> --
>> Sergey Beryozkin
>>
>> Talend Community Coders
>> http://coders.talend.com/
>>
>> Blog: http://sberyozkin.blogspot.com
>>
>

Re: jax-rs exception mapping

Posted by "Lambert, Michael" <mi...@michaellambert.com>.
Good to know Sergey we will look at it again today. Definitely experiencing
the behavior I described so we will look for some delta between our code
and the test
On Oct 22, 2014 5:50 AM, "Sergey Beryozkin" <sb...@gmail.com> wrote:

> ProviderFactoryTest has the following:
>
> private static class RuntimeExceptionMapper1
>         extends AbstractTestExceptionMapper<RuntimeException> {
>
>     }
>
>     private static class RuntimeExceptionMapper2
>         extends AbstractTestExceptionMapper<WebApplicationException> {
>
>     }
>
>     private static class AbstractTestExceptionMapper<T extends
> RuntimeException>
>         implements ExceptionMapper<T> {
>
>         public Response toResponse(T arg0) {
>             // TODO Auto-generated method stub
>             return null;
>         }
>
>     }
>
> This is identical to your example where you say the bug is expected, also
> note WebApplicationException is RuntimeException.
>
> @Test
>     public void testExceptionMappersHierarchyWithGenerics() throws
> Exception {
>         ServerProviderFactory pf = ServerProviderFactory.getInstance();
>         RuntimeExceptionMapper1 exMapper1 = new RuntimeExceptionMapper1();
>         pf.registerUserProvider(exMapper1);
>         RuntimeExceptionMapper2 exMapper2 = new RuntimeExceptionMapper2();
>         pf.registerUserProvider(exMapper2);
>         assertSame(exMapper1, pf.createExceptionMapper(RuntimeException.class,
> new MessageImpl()));
>         Object webExMapper = pf.createExceptionMapper(WebApplicationException.class,
> new MessageImpl());
>         assertSame(exMapper2, webExMapper);
>     }
>
> When RuntimeExceptionMapper2 is registered, RuntimeExceptionMapper1 is not
> picked for WebApplicationException. Updating the test not to register
> RuntimeExceptionMapper2 leads to RuntimeExceptionMapper1 being selected for
> WebApplicationException.
>
> Looks like it is all correct to me, may be the issue is there in 2.7.11
> but def not on the trunk/3.0.2
>
> Cheers, Sergey
>
> On 21/10/14 20:04, Lambert, Michael wrote:
>
>> To be clear:
>>
>> This bug will only manifest itself if two exception mapper are both
>> derived
>> from the same interface:
>>
>>      public class AbstractMapper<T extends Throwable> implements
>> ExceptionMapper<T> {
>>          ...
>>      }
>>
>>      public class FooMapper extends AbstractMapper<FooException> {
>>          ...
>>      }
>>
>>      // ProviderFactory.ClassComparator.compare will return "0" when
>> BarMapper is compared to FooMapper
>>      public class BarMapper extends AbstractMapper<BarException> {
>>          ...
>>      }
>>
>> If each exception mapper instance is derived from a DIFFERENT INTERFACE
>> everything works fine:
>>
>>      public interface IFooMapper extends ExceptionMapper<FooException> {
>>          ...
>>      }
>>
>>      public class FooMapper extends implements IFooMapper  {
>>          ...
>>      }
>>
>>      public interface IBarMapper extends ExceptionMapper<BarException> {
>>          ...
>>      }
>>
>>      // ProviderFactory.ClassComparator.compare will return "1" or -1
>> when
>> BarMapper is compared to FooMapper
>>      public class BarMapper extends implements IBarMapper {
>>          ...
>>      }
>>
>>
>>
>> On Tue, Oct 21, 2014 at 2:34 PM, Lambert, Michael <
>> michael@michaellambert.com> wrote:
>>
>>  Guys... it looks like there is a bug in ProviderFactory$ClassComparator.
>>> Given two mappers it always ends up comparing them as if both mappers
>>> were
>>> ExceptionMapper<Throwable>. There must be a problem in the way the
>>> interfaces and "actual types" are derived (which is done in the
>>> InjectionUtils class).
>>>
>>> -Mike
>>>
>>> On Tue, Oct 21, 2014 at 1:24 PM, Lambert, Michael <
>>> michael@michaellambert.com> wrote:
>>>
>>>  Hello gentleman!
>>>>
>>>> My impression was that when implementing ExceptionMapper that the mapper
>>>> of the nearest superclass of an exception would be used if an exact
>>>> exceptionmapper match to the exception didnt exist.
>>>>
>>>> For example if I created a FooException which extended BarException  I
>>>> would only have to create a BarExceptionMapper to catch and map both
>>>> types
>>>> of exceptions; the BarExceptionMapper would be used when a FooException
>>>> was
>>>> thrown.
>>>>
>>>> The red hat docs seem to reinforce this opinion:
>>>>
>>>>
>>>>     -
>>>>
>>>>     When any exception other than a WebApplicationException exception,
>>>> or
>>>>     one of its subclasses, is thrown, the runtime will check for an
>>>> appropriate
>>>>     exception mapper. An exception mapper is selected if it handles the
>>>>     specific exception thrown. If there is not an exception mapper for
>>>> the
>>>>     specific exception that was thrown, the exception mapper for the
>>>> nearest
>>>>     superclass of the exception is selected.
>>>>
>>>>
>>>>
>>>> https://access.redhat.com/documentation/en-US/Red_Hat_
>>>> JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/
>>>> RESTExceptionMapper.html
>>>>
>>>> The reality is different for us however. In fact, if we create a custom
>>>> WebApplicationExceptionMapper ClientErrorExceptions are not caught by
>>>> the
>>>> mapper. CXF seems to default to attempt to use whichever Mapper is the
>>>> first one we registered (e.g. if we defined a FooExceptionMapper and
>>>> registered it, CXF would attempt to use that and throw an error rather
>>>> than
>>>> try to use the WebApplicationExceptionMapper).
>>>>
>>>> Can someone tell me what the expected behavior is? Is my question clear?
>>>>
>>>> We are using CXF version 2.7.11.
>>>>
>>>> Thanks!
>>>>
>>>> Mike
>>>>
>>>>
>>>
>>>
>>
>
> --
> Sergey Beryozkin
>
> Talend Community Coders
> http://coders.talend.com/
>
> Blog: http://sberyozkin.blogspot.com
>

Re: jax-rs exception mapping

Posted by Sergey Beryozkin <sb...@gmail.com>.
ProviderFactoryTest has the following:

private static class RuntimeExceptionMapper1
         extends AbstractTestExceptionMapper<RuntimeException> {

     }

     private static class RuntimeExceptionMapper2
         extends AbstractTestExceptionMapper<WebApplicationException> {

     }

     private static class AbstractTestExceptionMapper<T extends 
RuntimeException>
         implements ExceptionMapper<T> {

         public Response toResponse(T arg0) {
             // TODO Auto-generated method stub
             return null;
         }

     }

This is identical to your example where you say the bug is expected, 
also note WebApplicationException is RuntimeException.

@Test
     public void testExceptionMappersHierarchyWithGenerics() throws 
Exception {
         ServerProviderFactory pf = ServerProviderFactory.getInstance();
         RuntimeExceptionMapper1 exMapper1 = new RuntimeExceptionMapper1();
         pf.registerUserProvider(exMapper1);
         RuntimeExceptionMapper2 exMapper2 = new RuntimeExceptionMapper2();
         pf.registerUserProvider(exMapper2);
         assertSame(exMapper1, 
pf.createExceptionMapper(RuntimeException.class, new MessageImpl()));
         Object webExMapper = 
pf.createExceptionMapper(WebApplicationException.class, new MessageImpl());
         assertSame(exMapper2, webExMapper);
     }

When RuntimeExceptionMapper2 is registered, RuntimeExceptionMapper1 is 
not picked for WebApplicationException. Updating the test not to 
register RuntimeExceptionMapper2 leads to RuntimeExceptionMapper1 being 
selected for WebApplicationException.

Looks like it is all correct to me, may be the issue is there in 2.7.11 
but def not on the trunk/3.0.2

Cheers, Sergey

On 21/10/14 20:04, Lambert, Michael wrote:
> To be clear:
>
> This bug will only manifest itself if two exception mapper are both derived
> from the same interface:
>
>      public class AbstractMapper<T extends Throwable> implements
> ExceptionMapper<T> {
>          ...
>      }
>
>      public class FooMapper extends AbstractMapper<FooException> {
>          ...
>      }
>
>      // ProviderFactory.ClassComparator.compare will return "0" when
> BarMapper is compared to FooMapper
>      public class BarMapper extends AbstractMapper<BarException> {
>          ...
>      }
>
> If each exception mapper instance is derived from a DIFFERENT INTERFACE
> everything works fine:
>
>      public interface IFooMapper extends ExceptionMapper<FooException> {
>          ...
>      }
>
>      public class FooMapper extends implements IFooMapper  {
>          ...
>      }
>
>      public interface IBarMapper extends ExceptionMapper<BarException> {
>          ...
>      }
>
>      // ProviderFactory.ClassComparator.compare will return "1" or -1 when
> BarMapper is compared to FooMapper
>      public class BarMapper extends implements IBarMapper {
>          ...
>      }
>
>
>
> On Tue, Oct 21, 2014 at 2:34 PM, Lambert, Michael <
> michael@michaellambert.com> wrote:
>
>> Guys... it looks like there is a bug in ProviderFactory$ClassComparator.
>> Given two mappers it always ends up comparing them as if both mappers were
>> ExceptionMapper<Throwable>. There must be a problem in the way the
>> interfaces and "actual types" are derived (which is done in the
>> InjectionUtils class).
>>
>> -Mike
>>
>> On Tue, Oct 21, 2014 at 1:24 PM, Lambert, Michael <
>> michael@michaellambert.com> wrote:
>>
>>> Hello gentleman!
>>>
>>> My impression was that when implementing ExceptionMapper that the mapper
>>> of the nearest superclass of an exception would be used if an exact
>>> exceptionmapper match to the exception didnt exist.
>>>
>>> For example if I created a FooException which extended BarException  I
>>> would only have to create a BarExceptionMapper to catch and map both types
>>> of exceptions; the BarExceptionMapper would be used when a FooException was
>>> thrown.
>>>
>>> The red hat docs seem to reinforce this opinion:
>>>
>>>
>>>     -
>>>
>>>     When any exception other than a WebApplicationException exception, or
>>>     one of its subclasses, is thrown, the runtime will check for an appropriate
>>>     exception mapper. An exception mapper is selected if it handles the
>>>     specific exception thrown. If there is not an exception mapper for the
>>>     specific exception that was thrown, the exception mapper for the nearest
>>>     superclass of the exception is selected.
>>>
>>>
>>>
>>> https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/RESTExceptionMapper.html
>>>
>>> The reality is different for us however. In fact, if we create a custom
>>> WebApplicationExceptionMapper ClientErrorExceptions are not caught by the
>>> mapper. CXF seems to default to attempt to use whichever Mapper is the
>>> first one we registered (e.g. if we defined a FooExceptionMapper and
>>> registered it, CXF would attempt to use that and throw an error rather than
>>> try to use the WebApplicationExceptionMapper).
>>>
>>> Can someone tell me what the expected behavior is? Is my question clear?
>>>
>>> We are using CXF version 2.7.11.
>>>
>>> Thanks!
>>>
>>> Mike
>>>
>>
>>
>


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Re: jax-rs exception mapping

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi

Can you please try CXF 2.7.13 ?

Cheers. Sergey
On 21/10/14 20:04, Lambert, Michael wrote:
> To be clear:
>
> This bug will only manifest itself if two exception mapper are both derived
> from the same interface:
>
>      public class AbstractMapper<T extends Throwable> implements
> ExceptionMapper<T> {
>          ...
>      }
>
>      public class FooMapper extends AbstractMapper<FooException> {
>          ...
>      }
>
>      // ProviderFactory.ClassComparator.compare will return "0" when
> BarMapper is compared to FooMapper
>      public class BarMapper extends AbstractMapper<BarException> {
>          ...
>      }
>
> If each exception mapper instance is derived from a DIFFERENT INTERFACE
> everything works fine:
>
>      public interface IFooMapper extends ExceptionMapper<FooException> {
>          ...
>      }
>
>      public class FooMapper extends implements IFooMapper  {
>          ...
>      }
>
>      public interface IBarMapper extends ExceptionMapper<BarException> {
>          ...
>      }
>
>      // ProviderFactory.ClassComparator.compare will return "1" or -1 when
> BarMapper is compared to FooMapper
>      public class BarMapper extends implements IBarMapper {
>          ...
>      }
>
>
>
> On Tue, Oct 21, 2014 at 2:34 PM, Lambert, Michael <
> michael@michaellambert.com> wrote:
>
>> Guys... it looks like there is a bug in ProviderFactory$ClassComparator.
>> Given two mappers it always ends up comparing them as if both mappers were
>> ExceptionMapper<Throwable>. There must be a problem in the way the
>> interfaces and "actual types" are derived (which is done in the
>> InjectionUtils class).
>>
>> -Mike
>>
>> On Tue, Oct 21, 2014 at 1:24 PM, Lambert, Michael <
>> michael@michaellambert.com> wrote:
>>
>>> Hello gentleman!
>>>
>>> My impression was that when implementing ExceptionMapper that the mapper
>>> of the nearest superclass of an exception would be used if an exact
>>> exceptionmapper match to the exception didnt exist.
>>>
>>> For example if I created a FooException which extended BarException  I
>>> would only have to create a BarExceptionMapper to catch and map both types
>>> of exceptions; the BarExceptionMapper would be used when a FooException was
>>> thrown.
>>>
>>> The red hat docs seem to reinforce this opinion:
>>>
>>>
>>>     -
>>>
>>>     When any exception other than a WebApplicationException exception, or
>>>     one of its subclasses, is thrown, the runtime will check for an appropriate
>>>     exception mapper. An exception mapper is selected if it handles the
>>>     specific exception thrown. If there is not an exception mapper for the
>>>     specific exception that was thrown, the exception mapper for the nearest
>>>     superclass of the exception is selected.
>>>
>>>
>>>
>>> https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/RESTExceptionMapper.html
>>>
>>> The reality is different for us however. In fact, if we create a custom
>>> WebApplicationExceptionMapper ClientErrorExceptions are not caught by the
>>> mapper. CXF seems to default to attempt to use whichever Mapper is the
>>> first one we registered (e.g. if we defined a FooExceptionMapper and
>>> registered it, CXF would attempt to use that and throw an error rather than
>>> try to use the WebApplicationExceptionMapper).
>>>
>>> Can someone tell me what the expected behavior is? Is my question clear?
>>>
>>> We are using CXF version 2.7.11.
>>>
>>> Thanks!
>>>
>>> Mike
>>>
>>
>>
>


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Re: jax-rs exception mapping

Posted by "Lambert, Michael" <mi...@michaellambert.com>.
To be clear:

This bug will only manifest itself if two exception mapper are both derived
from the same interface:

    public class AbstractMapper<T extends Throwable> implements
ExceptionMapper<T> {
        ...
    }

    public class FooMapper extends AbstractMapper<FooException> {
        ...
    }

    // ProviderFactory.ClassComparator.compare will return "0" when
BarMapper is compared to FooMapper
    public class BarMapper extends AbstractMapper<BarException> {
        ...
    }

If each exception mapper instance is derived from a DIFFERENT INTERFACE
everything works fine:

    public interface IFooMapper extends ExceptionMapper<FooException> {
        ...
    }

    public class FooMapper extends implements IFooMapper  {
        ...
    }

    public interface IBarMapper extends ExceptionMapper<BarException> {
        ...
    }

    // ProviderFactory.ClassComparator.compare will return "1" or -1 when
BarMapper is compared to FooMapper
    public class BarMapper extends implements IBarMapper {
        ...
    }



On Tue, Oct 21, 2014 at 2:34 PM, Lambert, Michael <
michael@michaellambert.com> wrote:

> Guys... it looks like there is a bug in ProviderFactory$ClassComparator.
> Given two mappers it always ends up comparing them as if both mappers were
> ExceptionMapper<Throwable>. There must be a problem in the way the
> interfaces and "actual types" are derived (which is done in the
> InjectionUtils class).
>
> -Mike
>
> On Tue, Oct 21, 2014 at 1:24 PM, Lambert, Michael <
> michael@michaellambert.com> wrote:
>
>> Hello gentleman!
>>
>> My impression was that when implementing ExceptionMapper that the mapper
>> of the nearest superclass of an exception would be used if an exact
>> exceptionmapper match to the exception didnt exist.
>>
>> For example if I created a FooException which extended BarException  I
>> would only have to create a BarExceptionMapper to catch and map both types
>> of exceptions; the BarExceptionMapper would be used when a FooException was
>> thrown.
>>
>> The red hat docs seem to reinforce this opinion:
>>
>>
>>    -
>>
>>    When any exception other than a WebApplicationException exception, or
>>    one of its subclasses, is thrown, the runtime will check for an appropriate
>>    exception mapper. An exception mapper is selected if it handles the
>>    specific exception thrown. If there is not an exception mapper for the
>>    specific exception that was thrown, the exception mapper for the nearest
>>    superclass of the exception is selected.
>>
>>
>>
>> https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/RESTExceptionMapper.html
>>
>> The reality is different for us however. In fact, if we create a custom
>> WebApplicationExceptionMapper ClientErrorExceptions are not caught by the
>> mapper. CXF seems to default to attempt to use whichever Mapper is the
>> first one we registered (e.g. if we defined a FooExceptionMapper and
>> registered it, CXF would attempt to use that and throw an error rather than
>> try to use the WebApplicationExceptionMapper).
>>
>> Can someone tell me what the expected behavior is? Is my question clear?
>>
>> We are using CXF version 2.7.11.
>>
>> Thanks!
>>
>> Mike
>>
>
>

Re: jax-rs exception mapping

Posted by "Lambert, Michael" <mi...@michaellambert.com>.
Guys... it looks like there is a bug in ProviderFactory$ClassComparator.
Given two mappers it always ends up comparing them as if both mappers were
ExceptionMapper<Throwable>. There must be a problem in the way the
interfaces and "actual types" are derived (which is done in the
InjectionUtils class).

-Mike

On Tue, Oct 21, 2014 at 1:24 PM, Lambert, Michael <
michael@michaellambert.com> wrote:

> Hello gentleman!
>
> My impression was that when implementing ExceptionMapper that the mapper
> of the nearest superclass of an exception would be used if an exact
> exceptionmapper match to the exception didnt exist.
>
> For example if I created a FooException which extended BarException  I
> would only have to create a BarExceptionMapper to catch and map both types
> of exceptions; the BarExceptionMapper would be used when a FooException was
> thrown.
>
> The red hat docs seem to reinforce this opinion:
>
>
>    -
>
>    When any exception other than a WebApplicationException exception, or
>    one of its subclasses, is thrown, the runtime will check for an appropriate
>    exception mapper. An exception mapper is selected if it handles the
>    specific exception thrown. If there is not an exception mapper for the
>    specific exception that was thrown, the exception mapper for the nearest
>    superclass of the exception is selected.
>
>
>
> https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Fuse/6.1/html/Apache_CXF_Development_Guide/files/RESTExceptionMapper.html
>
> The reality is different for us however. In fact, if we create a custom
> WebApplicationExceptionMapper ClientErrorExceptions are not caught by the
> mapper. CXF seems to default to attempt to use whichever Mapper is the
> first one we registered (e.g. if we defined a FooExceptionMapper and
> registered it, CXF would attempt to use that and throw an error rather than
> try to use the WebApplicationExceptionMapper).
>
> Can someone tell me what the expected behavior is? Is my question clear?
>
> We are using CXF version 2.7.11.
>
> Thanks!
>
> Mike
>