Problem with Enums as generic type with 2.10.x works on 2.9.x

42 views
Skip to first unread message

TimB

unread,
Jan 23, 2020, 4:12:56 PM1/23/20
to jackson-user
Hi there,
maybe I have an regression issue with Jackson 2.10.. but maybe I doing something wrong... hope you can help me out.

A simple Test shows the problem. We having a class like this:

@JsonTypeInfo(
   
use = JsonTypeInfo.Id.MINIMAL_CLASS,
    include
= JsonTypeInfo.As.PROPERTY,
    property
= "@class"
)
public class EnumContaintingClass <ENUM_TYPE extends Enum<ENUM_TYPE>> {
   
private ENUM_TYPE selected;
   
private List<ENUM_TYPE> options;

 
public EnumContaintingClass(){
 
}

 
public EnumContaintingClass(ENUM_TYPE selected, Class<ENUM_TYPE> cls) {
   
this.selected = selected;
    readOptionsFromEnum
(cls);
 
}

 
private void readOptionsFromEnum(Class < ENUM_TYPE > enumClass) {
   
ENUM_TYPE[] enumConstants = enumClass.getEnumConstants();
   
options = Arrays.asList(enumConstants);
 
}
 
// getter and setter here..
}

And a Test for a roundtrip:
public class JacksonTestCase {
 
public enum TestEnum { FIRST, SECOND, THIRD; }

 
@Test
  public void serialize() throws IOException {
   
EnumContaintingClass gui = new EnumContaintingClass(TestEnum.SECOND, TestEnum.class);
   
ObjectMapper mapper = new ObjectMapper();
   
String str = mapper.writer().writeValueAsString(gui);
   
Object o = mapper.readerFor(EnumContaintingClass.class).readValue(str);
   
Assert.assertNotNull(o);
 
}
}

Serializing works fine but deserzializing fails with 
Cannot deserialize Class java.lang.Enum (of type enum) as a Bean

This testcase works fine with the latest 2.9 Jackson but with 2.10 it fails.
I tried to add the TypeInfos also to the member but this didn't make it works. The only thing I could do is changing from <ENUM_TYPE extends Enum<ENUM_TYPE>> to <ENUM_TYPE>.
But that is not what we want to have, only Enums shall be allowed there (to indicate this I added the readOptionsFromEnum-Method).

So please could you guide me how to make this work in Jackson 2.10 or is this an regression issue?

Tatu Saloranta

unread,
Jan 23, 2020, 6:19:08 PM1/23/20
to jackson-user
I don't see how it should have worked ever, actually: problem is that type information is missing: there is just type variable `ENUM_TYPE`, of some Enum type. This will not be enough to deserialize anything back. Use of polymorphic typing will not likely help, being orthogonal to generic types (and typically combination does not work well).

So, instead of `EnumContaintingClass` as type (which is raw type, with unbound type variable), you should use `EnumContaintingClass<TestEnum>` (or whatever type you are using). That should be enough on deserialization: however, may or may not cause problems during serialization: you might need to force root type:

    mapper.writerFor(new TypeReference<EnumContainingClass<TestEnum>>() { })
       .writeValue(....)

Another thing to try that could help would be to use `@JsonTypeInfo` for properties:

  private ENUM_TYPE selected;
   private List<ENUM_TYPE> options;

and NOT on class: use at class level in this case does not make much sense actually as it will only retain type `EnumContainingClass` (which is not polymorphic), but does nothing to type variable/binding. So it could be dropped; it does not serve purpose as far as I can see.
This may be due to misunderstanding on role of this annotation: it does not actually apply to members of annotated class but only to instances of that class.

-+ Tatu +- 
 

TimB

unread,
Jan 24, 2020, 1:47:23 AM1/24/20
to jackson-user
Hi Tatu,
thanks for your help. 
As i wrote i did tried it with adding the TypeInfos also to the properties of the class, but that doesn't helped. But I really hoped it did.
The Type Info on the class is useless that is right, but I need it in the real code where I have this problem (at the list property containting instances of this class to be exact). 

TypeReference Objects are sadly no option for use...
Maybe the usecase help to understand. This is part of a search enginge, where the possible criterias are added dynamically based on the type/class the user is searching for. Based on the properties of the type we create criteria-objects. Beside the EnumSearchCriteria (what is almost like the EnumContaintingClass) there are others like String, Number or DateCriterias. All the criterias are added into a list, so we need the TypeInfo at the list.

There are a lot of possible searches, thats why we need it dynamically/generic and can not create a TypeReference as you propose. At transportlevel we don't know what exact EnumType is transfered by this Criteria.

Hope you have another clue to help me with this. 

Thanks Tim

Tatu Saloranta

unread,
Jan 24, 2020, 5:25:00 PM1/24/20
to jackson-user
I think filing a jackson-databind issue, with smallest possible reproduction (passes on 2.9, fails on 2.10) would be helpful. There is a possibility that a small regression caused it, and is easily fixable; most likely wrt Enum type detection.

Also: not sure if this was mentioned but if you haven't yet checked 2.10.2, make sure to try that out (over 2.10.0 and 2.10.1) as there were a few possibly relevant fixes.

-+ Tatu +-
 
Message has been deleted

TimB

unread,
Jan 25, 2020, 5:37:38 AM1/25/20
to jackson-user
Hi Tatu,
I will create a issue on github with the example that is attached here. 
Thanks for your reply to my question :)

Kind regards
Tim
jsontest.zip
Reply all
Reply to author
Forward
0 new messages