[Camel 2.24.x] Custom type converters for Enums

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

[Camel 2.24.x] Custom type converters for Enums

Claussnitzer, Ralf
Dear list,

I noticed a problem in Camel 2.x with type conversion of Enums. It
cannot be used with constructor type Enums. The conversion of Strings to
Enum types is hard coded to fail with an Exception if the EnumConverter
cannot instantiate an Enum value.

Given the Enum:

    enum Toggle {
             On(true), Off(false);

             private final boolean b;

             Toggle(boolean b) {
                 this.b = b;
             }

             @Override
             public String toString() {
                 return String.format("%s(%b)", name(), b);
             }
    }

A call to convertTo() can only find the appropriate Enum object by name:

    CamelContext context = new DefaultCamelContext();
    Toggle toggle = context.getTypeConverter().convertTo(Toggle.class,
    "On");
    System.out.println(toggle); // ...On(true)

However, I cannot introduce a custom TypeConverter for converting the
String "On(true)" into an instance of Toggle. The reason is that
org.apache.camel.impl.converter.EnumTypeConverter tries to call the
built-in valueOf(String) method which will end the program with a
RuntimeException:

    Exception in thread "main" org.apache.camel.TypeConversionException:
    Error during type conversion from type: java.lang.String to the
    required type: EnumConversionExperiment.Toggle with value On(true)
    due java.lang.IllegalAccessException: Class
    org.apache.camel.util.ObjectHelper can not access a member of class
    EnumConversionExperiment$Toggle with modifiers "public static"
         at
    org.apache.camel.impl.converter.BaseTypeConverterRegistry.createTypeConversionException(BaseTypeConverterRegistry.java:667)
         at
    org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:158)
         at
    org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:129)
         at EnumConversionExperiment.main(EnumConversionExperiment.java:8)
    Caused by: org.apache.camel.RuntimeCamelException:
    java.lang.IllegalAccessException: Class
    org.apache.camel.util.ObjectHelper can not access a member of class
    EnumConversionExperiment$Toggle with modifiers "public static"
         at
    org.apache.camel.util.ObjectHelper.invokeMethod(ObjectHelper.java:1407)
         at
    org.apache.camel.impl.converter.EnumTypeConverter.convertTo(EnumTypeConverter.java:51)
         at
    org.apache.camel.impl.converter.OptimisedTypeConverter.convertTo(OptimisedTypeConverter.java:71)
         at
    org.apache.camel.impl.converter.BaseTypeConverterRegistry.doConvertTo(BaseTypeConverterRegistry.java:300)
         at
    org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:141)
         ... 2 more
    Caused by: java.lang.IllegalAccessException: Class
    org.apache.camel.util.ObjectHelper can not access a member of class
    EnumConversionExperiment$Toggle with modifiers "public static"
         at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
         at
    java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
         at
    java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
         at java.lang.reflect.Method.invoke(Method.java:491)
         at
    org.apache.camel.util.ObjectHelper.invokeMethod(ObjectHelper.java:1405)
         ... 6 more

The type conversion process stops here instead of looking for custom
type converters. Line 53: return null; of EnumTypeConverter is never
reached. Would EnumTypeConverter indeed return null, the process would
continue and a custom converter would finally be called.

I'm pretty sure this is an issue. What do you think?

Regards,
Ralf

Reply | Threaded
Open this post in threaded view
|

Re: [Camel 2.24.x] Custom type converters for Enums

Claus Ibsen-2
Hi

You can make the enum compute the boolean based on its name. Or is
your On|Off enum just some sample enum and not your real enum?

Camel 2.x is EOL and we wont do changes there.
Only CVEs and production bug fixes.




On Wed, Feb 26, 2020 at 2:54 PM Ralf Claussnitzer
<[hidden email]> wrote:

>
> Dear list,
>
> I noticed a problem in Camel 2.x with type conversion of Enums. It
> cannot be used with constructor type Enums. The conversion of Strings to
> Enum types is hard coded to fail with an Exception if the EnumConverter
> cannot instantiate an Enum value.
>
> Given the Enum:
>
>     enum Toggle {
>              On(true), Off(false);
>
>              private final boolean b;
>
>              Toggle(boolean b) {
>                  this.b = b;
>              }
>
>              @Override
>              public String toString() {
>                  return String.format("%s(%b)", name(), b);
>              }
>     }
>
> A call to convertTo() can only find the appropriate Enum object by name:
>
>     CamelContext context = new DefaultCamelContext();
>     Toggle toggle = context.getTypeConverter().convertTo(Toggle.class,
>     "On");
>     System.out.println(toggle); // ...On(true)
>
> However, I cannot introduce a custom TypeConverter for converting the
> String "On(true)" into an instance of Toggle. The reason is that
> org.apache.camel.impl.converter.EnumTypeConverter tries to call the
> built-in valueOf(String) method which will end the program with a
> RuntimeException:
>
>     Exception in thread "main" org.apache.camel.TypeConversionException:
>     Error during type conversion from type: java.lang.String to the
>     required type: EnumConversionExperiment.Toggle with value On(true)
>     due java.lang.IllegalAccessException: Class
>     org.apache.camel.util.ObjectHelper can not access a member of class
>     EnumConversionExperiment$Toggle with modifiers "public static"
>          at
>     org.apache.camel.impl.converter.BaseTypeConverterRegistry.createTypeConversionException(BaseTypeConverterRegistry.java:667)
>          at
>     org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:158)
>          at
>     org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:129)
>          at EnumConversionExperiment.main(EnumConversionExperiment.java:8)
>     Caused by: org.apache.camel.RuntimeCamelException:
>     java.lang.IllegalAccessException: Class
>     org.apache.camel.util.ObjectHelper can not access a member of class
>     EnumConversionExperiment$Toggle with modifiers "public static"
>          at
>     org.apache.camel.util.ObjectHelper.invokeMethod(ObjectHelper.java:1407)
>          at
>     org.apache.camel.impl.converter.EnumTypeConverter.convertTo(EnumTypeConverter.java:51)
>          at
>     org.apache.camel.impl.converter.OptimisedTypeConverter.convertTo(OptimisedTypeConverter.java:71)
>          at
>     org.apache.camel.impl.converter.BaseTypeConverterRegistry.doConvertTo(BaseTypeConverterRegistry.java:300)
>          at
>     org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:141)
>          ... 2 more
>     Caused by: java.lang.IllegalAccessException: Class
>     org.apache.camel.util.ObjectHelper can not access a member of class
>     EnumConversionExperiment$Toggle with modifiers "public static"
>          at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
>          at
>     java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
>          at
>     java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
>          at java.lang.reflect.Method.invoke(Method.java:491)
>          at
>     org.apache.camel.util.ObjectHelper.invokeMethod(ObjectHelper.java:1405)
>          ... 6 more
>
> The type conversion process stops here instead of looking for custom
> type converters. Line 53: return null; of EnumTypeConverter is never
> reached. Would EnumTypeConverter indeed return null, the process would
> continue and a custom converter would finally be called.
>
> I'm pretty sure this is an issue. What do you think?
>
> Regards,
> Ralf
>


--
Claus Ibsen
-----------------
http://davsclaus.com @davsclaus
Camel in Action 2: https://www.manning.com/ibsen2
Reply | Threaded
Open this post in threaded view
|

Re: [Camel 2.24.x] Custom type converters for Enums

Claussnitzer, Ralf
Hi Claus,

> You can make the enum compute the boolean based on its name. Or is
> your On|Off enum just some sample enum and not your real enum?

It's just a sample Enum to describe the general problem.

> Camel 2.x is EOL and we wont do changes there.
> Only CVEs and production bug fixes.

Do you think it's a design problem? And is it the same in Camel 3.x?

-Ralf

On 2/28/20 7:43 AM, Claus Ibsen wrote:

> Hi
>
> You can make the enum compute the boolean based on its name. Or is
> your On|Off enum just some sample enum and not your real enum?
>
> Camel 2.x is EOL and we wont do changes there.
> Only CVEs and production bug fixes.
>
>
>
>
> On Wed, Feb 26, 2020 at 2:54 PM Ralf Claussnitzer
> <[hidden email]> wrote:
>> Dear list,
>>
>> I noticed a problem in Camel 2.x with type conversion of Enums. It
>> cannot be used with constructor type Enums. The conversion of Strings to
>> Enum types is hard coded to fail with an Exception if the EnumConverter
>> cannot instantiate an Enum value.
>>
>> Given the Enum:
>>
>>      enum Toggle {
>>               On(true), Off(false);
>>
>>               private final boolean b;
>>
>>               Toggle(boolean b) {
>>                   this.b = b;
>>               }
>>
>>               @Override
>>               public String toString() {
>>                   return String.format("%s(%b)", name(), b);
>>               }
>>      }
>>
>> A call to convertTo() can only find the appropriate Enum object by name:
>>
>>      CamelContext context = new DefaultCamelContext();
>>      Toggle toggle = context.getTypeConverter().convertTo(Toggle.class,
>>      "On");
>>      System.out.println(toggle); // ...On(true)
>>
>> However, I cannot introduce a custom TypeConverter for converting the
>> String "On(true)" into an instance of Toggle. The reason is that
>> org.apache.camel.impl.converter.EnumTypeConverter tries to call the
>> built-in valueOf(String) method which will end the program with a
>> RuntimeException:
>>
>>      Exception in thread "main" org.apache.camel.TypeConversionException:
>>      Error during type conversion from type: java.lang.String to the
>>      required type: EnumConversionExperiment.Toggle with value On(true)
>>      due java.lang.IllegalAccessException: Class
>>      org.apache.camel.util.ObjectHelper can not access a member of class
>>      EnumConversionExperiment$Toggle with modifiers "public static"
>>           at
>>      org.apache.camel.impl.converter.BaseTypeConverterRegistry.createTypeConversionException(BaseTypeConverterRegistry.java:667)
>>           at
>>      org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:158)
>>           at
>>      org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:129)
>>           at EnumConversionExperiment.main(EnumConversionExperiment.java:8)
>>      Caused by: org.apache.camel.RuntimeCamelException:
>>      java.lang.IllegalAccessException: Class
>>      org.apache.camel.util.ObjectHelper can not access a member of class
>>      EnumConversionExperiment$Toggle with modifiers "public static"
>>           at
>>      org.apache.camel.util.ObjectHelper.invokeMethod(ObjectHelper.java:1407)
>>           at
>>      org.apache.camel.impl.converter.EnumTypeConverter.convertTo(EnumTypeConverter.java:51)
>>           at
>>      org.apache.camel.impl.converter.OptimisedTypeConverter.convertTo(OptimisedTypeConverter.java:71)
>>           at
>>      org.apache.camel.impl.converter.BaseTypeConverterRegistry.doConvertTo(BaseTypeConverterRegistry.java:300)
>>           at
>>      org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:141)
>>           ... 2 more
>>      Caused by: java.lang.IllegalAccessException: Class
>>      org.apache.camel.util.ObjectHelper can not access a member of class
>>      EnumConversionExperiment$Toggle with modifiers "public static"
>>           at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
>>           at
>>      java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
>>           at
>>      java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
>>           at java.lang.reflect.Method.invoke(Method.java:491)
>>           at
>>      org.apache.camel.util.ObjectHelper.invokeMethod(ObjectHelper.java:1405)
>>           ... 6 more
>>
>> The type conversion process stops here instead of looking for custom
>> type converters. Line 53: return null; of EnumTypeConverter is never
>> reached. Would EnumTypeConverter indeed return null, the process would
>> continue and a custom converter would finally be called.
>>
>> I'm pretty sure this is an issue. What do you think?
>>
>> Regards,
>> Ralf
>>
>
Reply | Threaded
Open this post in threaded view
|

Re: [Camel 2.24.x] Custom type converters for Enums

Claus Ibsen-2
On Fri, Feb 28, 2020 at 8:55 AM Ralf Claussnitzer
<[hidden email]> wrote:

>
> Hi Claus,
>
> > You can make the enum compute the boolean based on its name. Or is
> > your On|Off enum just some sample enum and not your real enum?
>
> It's just a sample Enum to describe the general problem.
>
> > Camel 2.x is EOL and we wont do changes there.
> > Only CVEs and production bug fixes.
>
> Do you think it's a design problem? And is it the same in Camel 3.x?
>

You are the first to come up with this, and 2.x has been out for over a decade.

The type converter system is a critical execution path, and if we open
up for continued discovery then we need to ensure that it wont affect
performance negatively for regular type converters. But at first you
can create a JIRA and then we can look at this for 3.x.



> -Ralf
>
> On 2/28/20 7:43 AM, Claus Ibsen wrote:
> > Hi
> >
> > You can make the enum compute the boolean based on its name. Or is
> > your On|Off enum just some sample enum and not your real enum?
> >
> > Camel 2.x is EOL and we wont do changes there.
> > Only CVEs and production bug fixes.
> >
> >
> >
> >
> > On Wed, Feb 26, 2020 at 2:54 PM Ralf Claussnitzer
> > <[hidden email]> wrote:
> >> Dear list,
> >>
> >> I noticed a problem in Camel 2.x with type conversion of Enums. It
> >> cannot be used with constructor type Enums. The conversion of Strings to
> >> Enum types is hard coded to fail with an Exception if the EnumConverter
> >> cannot instantiate an Enum value.
> >>
> >> Given the Enum:
> >>
> >>      enum Toggle {
> >>               On(true), Off(false);
> >>
> >>               private final boolean b;
> >>
> >>               Toggle(boolean b) {
> >>                   this.b = b;
> >>               }
> >>
> >>               @Override
> >>               public String toString() {
> >>                   return String.format("%s(%b)", name(), b);
> >>               }
> >>      }
> >>
> >> A call to convertTo() can only find the appropriate Enum object by name:
> >>
> >>      CamelContext context = new DefaultCamelContext();
> >>      Toggle toggle = context.getTypeConverter().convertTo(Toggle.class,
> >>      "On");
> >>      System.out.println(toggle); // ...On(true)
> >>
> >> However, I cannot introduce a custom TypeConverter for converting the
> >> String "On(true)" into an instance of Toggle. The reason is that
> >> org.apache.camel.impl.converter.EnumTypeConverter tries to call the
> >> built-in valueOf(String) method which will end the program with a
> >> RuntimeException:
> >>
> >>      Exception in thread "main" org.apache.camel.TypeConversionException:
> >>      Error during type conversion from type: java.lang.String to the
> >>      required type: EnumConversionExperiment.Toggle with value On(true)
> >>      due java.lang.IllegalAccessException: Class
> >>      org.apache.camel.util.ObjectHelper can not access a member of class
> >>      EnumConversionExperiment$Toggle with modifiers "public static"
> >>           at
> >>      org.apache.camel.impl.converter.BaseTypeConverterRegistry.createTypeConversionException(BaseTypeConverterRegistry.java:667)
> >>           at
> >>      org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:158)
> >>           at
> >>      org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:129)
> >>           at EnumConversionExperiment.main(EnumConversionExperiment.java:8)
> >>      Caused by: org.apache.camel.RuntimeCamelException:
> >>      java.lang.IllegalAccessException: Class
> >>      org.apache.camel.util.ObjectHelper can not access a member of class
> >>      EnumConversionExperiment$Toggle with modifiers "public static"
> >>           at
> >>      org.apache.camel.util.ObjectHelper.invokeMethod(ObjectHelper.java:1407)
> >>           at
> >>      org.apache.camel.impl.converter.EnumTypeConverter.convertTo(EnumTypeConverter.java:51)
> >>           at
> >>      org.apache.camel.impl.converter.OptimisedTypeConverter.convertTo(OptimisedTypeConverter.java:71)
> >>           at
> >>      org.apache.camel.impl.converter.BaseTypeConverterRegistry.doConvertTo(BaseTypeConverterRegistry.java:300)
> >>           at
> >>      org.apache.camel.impl.converter.BaseTypeConverterRegistry.convertTo(BaseTypeConverterRegistry.java:141)
> >>           ... 2 more
> >>      Caused by: java.lang.IllegalAccessException: Class
> >>      org.apache.camel.util.ObjectHelper can not access a member of class
> >>      EnumConversionExperiment$Toggle with modifiers "public static"
> >>           at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
> >>           at
> >>      java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
> >>           at
> >>      java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
> >>           at java.lang.reflect.Method.invoke(Method.java:491)
> >>           at
> >>      org.apache.camel.util.ObjectHelper.invokeMethod(ObjectHelper.java:1405)
> >>           ... 6 more
> >>
> >> The type conversion process stops here instead of looking for custom
> >> type converters. Line 53: return null; of EnumTypeConverter is never
> >> reached. Would EnumTypeConverter indeed return null, the process would
> >> continue and a custom converter would finally be called.
> >>
> >> I'm pretty sure this is an issue. What do you think?
> >>
> >> Regards,
> >> Ralf
> >>
> >



--
Claus Ibsen
-----------------
http://davsclaus.com @davsclaus
Camel in Action 2: https://www.manning.com/ibsen2