jackson-databind icon indicating copy to clipboard operation
jackson-databind copied to clipboard

Deserialise JSON array where an element is polymorphic

Open jamesmudd opened this issue 1 year ago • 15 comments

Search before asking

  • [X] I searched in the issues and found nothing similar.

Describe the bug

I also rasied this as a SO question so far with no response but I believe it might be a bug.

When I try to deserialise a JSON array with an element containig the type of another element the polymorphic type doesn't seem to be handled correcly. The code can work if you change to use JsonTypeInfo.Id.DEDUCTION again suggesting the issue is in the type selection.

I beleive the source of the issue here is somehow the combination of @JsonFormat(shape = JsonFormat.Shape.ARRAY) with JsonTypeInfo.As.EXTERNAL_PROPERTY and a polymorphic array ellement.

Version Information

2.15.3

Reproduction

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;

class Scratch {

    private static  ObjectMapper objectMapper = new ObjectMapper();

    @JsonFormat(shape = JsonFormat.Shape.ARRAY)
    @JsonPropertyOrder({"type", "uniqueId", "animal"})
    public static class Wrapper {

        public String type;
        public String uniqueId;

        @JsonTypeInfo(
                use = JsonTypeInfo.Id.NAME,
                include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
                property = "type"
        )
        @JsonSubTypes({
                @JsonSubTypes.Type(value = Cat.class, name = "cat")
        })
        public Animal animal;
    }

    public interface Animal {
        int getLegs();
    }

    public static class Cat implements Animal {

        public int legs = 4;
        @Override
        public int getLegs() {
            return legs;
        }
    }

    public static void main(String[] args) throws Exception {
        Wrapper wrapper = new Wrapper();
        wrapper.type = "cat";
        wrapper.uniqueId = "123";
        wrapper.animal = new Cat();

        String json = objectMapper.writeValueAsString(wrapper);
        System.out.println(json);

        Wrapper deserialized = objectMapper.readValue(json, Wrapper.class);
        System.out.println(deserialized);
    }
}

Expected behavior

Should deserialise correctly (and with more possible types)

Additional context

This example is kind of an extension of JsonTypeInfo.As.WRAPPER_ARRAY where the array also includes other elements in this example uniqueId.

jamesmudd avatar Dec 22 '23 12:12 jamesmudd