Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enum polymorphism not working correctly with DEDUCTION #3711

Closed
smilep opened this issue Jan 3, 2023 · 7 comments
Closed

Enum polymorphism not working correctly with DEDUCTION #3711

smilep opened this issue Jan 3, 2023 · 7 comments
Labels
polymorphic-deduction Issues related to "Id.DEDUCTION" mode of `@JsonTypeInfo`

Comments

@smilep
Copy link

smilep commented Jan 3, 2023

Describe the bug
When an interface type is being used for an attribute and an enum implements this interface, resulting serialization and deserialization behavior is incorrect.

Version information
2.14.1

To Reproduce
If you have a way to reproduce this with:

// POJO
public class Animal {

    private LivingBeingType type;

    private String name;
    // getters and setters
}

@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
@JsonSubTypes({@JsonSubTypes.Type(value = AnimalType.class)})
public interface LivingBeingType {
}

public enum AnimalType implements LivingBeingType {
    FOURLEGGED, TWOLEGGED
}

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();

        // Serialization
        Animal animal = new Animal();
        animal.setName("Horse");
        animal.setType(AnimalType.FOURLEGGED);
        System.out.println("***Serialization***");
        System.out.println(objectMapper.writeValueAsString(animal));

        // Deserialization
        String json = "{\"type\":\"FOURLEGGED\",\"name\":\"Horse\"}";
        System.out.println("***Deserialization***");
        System.out.println(objectMapper.readValue(json, Animal.class));
    }

Output :

***Serialization***
{"type":["com.smilep.jackson.AnimalType","FOURLEGGED"],"name":"Horse"}


***Deserialization***
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class com.smilep.jackson.LivingBeingType]: Unexpected input
 at [Source: (String)"{"type":"FOURLEGGED","name":"Horse"}"; line: 1, column: 9] (through reference chain: com.smilep.jackson.Animal["type"])
	at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
	at com.fasterxml.jackson.databind.DeserializationContext.missingTypeIdException(DeserializationContext.java:2088)
	at com.fasterxml.jackson.databind.DeserializationContext.handleMissingTypeId(DeserializationContext.java:1601)
	at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._handleMissingTypeId(TypeDeserializerBase.java:307)
	at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedUsingDefaultImpl(AsPropertyTypeDeserializer.java:185)
	at com.fasterxml.jackson.databind.jsontype.impl.AsDeductionTypeDeserializer.deserializeTypedFromObject(AsDeductionTypeDeserializer.java:110)
	at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:263)
	at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:138)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:314)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
	at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4730)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3677)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3645)
	at com.smilep.jackson.JacksonMain.main(JacksonMain.java:20)

Process finished with exit code 1

Expected behavior
Serialization should produce {"type":"FOURLEGGED","name":"Horse"}
Deserialization should produce Animal instance with type having value of AnimalType.FOURLEGGED instance.

@smilep smilep added the to-evaluate Issue that has been received but not yet evaluated label Jan 3, 2023
@cowtowncoder
Copy link
Member

I am not sure usage as indicated makes sense -- you are enabling polymorphic type handling for type indicator AnimalType -- instead of Animal. Polymorphic typing does not work (or be needed/useful) for enum types anyway (with exception of something more general like java.lang.Object having enum types).

Serialization of AnimalType does look odd tho: DEDUCTION should prevent serialization.

@cowtowncoder
Copy link
Member

Ahhhhhh. So the problem is that DEDUCTION uses:

        if(_idType == JsonTypeInfo.Id.DEDUCTION) {
            // Deduction doesn't require a type property. We use EXISTING_PROPERTY with a name of <null> to drive this.
            return new AsExistingPropertyTypeSerializer(idRes, null, _typeProperty);
        }

with assumption that prevents serialization of type id -- it does but ONLY if value is written as JSON Object.
But in case of something else (JSON Array or Scalar value), serialization of type id uses WRAPPER_ARRAY (since there is no place for properties in scalars or arrays). And in this case there is no suppression of writing type id.
This is not specific to enums I think, but does affect them.

I'll have to think of best way to tackle the issue; instead of using an existing TypeSerializer maybe it's better to create new "NoTypeSerializer" or something.

@cowtowncoder
Copy link
Member

Ok this gets surprisingly tricky to fix, due to TypeSerializer having to still output surround START_OBJECT/END_OBJECT and START_ARRAY/END_ARRAY even if no type id is to be written.
Hoping to figure out a way, still.

@cowtowncoder cowtowncoder added 2.14 polymorphic-deduction Issues related to "Id.DEDUCTION" mode of `@JsonTypeInfo` and removed to-evaluate Issue that has been received but not yet evaluated labels Jan 5, 2023
@cowtowncoder
Copy link
Member

Ok, managed to make it work at least for all existing tests, 2 new simple cases, see #3716.

@smilep
Copy link
Author

smilep commented Jan 5, 2023

Thank you so much! When will the new version be available with this change?

@cowtowncoder
Copy link
Member

@smilep No idea, unfortunately. Full patch release takes 3-4 hours to do and it's unpaid work for me, with lots of competing things to do. Will probably take until late january - mid-february if I had to guess.

@smilep
Copy link
Author

smilep commented Jan 6, 2023

@cowtowncoder Thanks. Really appreciate your work! Please do let me know if I can be on any help in releases or anything else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
polymorphic-deduction Issues related to "Id.DEDUCTION" mode of `@JsonTypeInfo`
Projects
None yet
Development

No branches or pull requests

2 participants