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

Deserialise JSON array where an element is polymorphic #4277

Open
1 task done
jamesmudd opened this issue Dec 22, 2023 · 5 comments
Open
1 task done

Deserialise JSON array where an element is polymorphic #4277

jamesmudd opened this issue Dec 22, 2023 · 5 comments
Labels
has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue

Comments

@jamesmudd
Copy link

Search before asking

  • 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 jamesmudd added the to-evaluate Issue that has been received but not yet evaluated label Dec 22, 2023
@pjfanning pjfanning changed the title Deserialise JSON array where an element is polymorhic Deserialise JSON array where an element is polymorphic Dec 22, 2023
@jamesmudd
Copy link
Author

Actualy realised by example might be slightly wrong as im setting wrapper.type = "cat" this should be automatically handled when serializing to JSON so actually maybe im wrong to say the serialisation works correctly.

@JooHyukKim
Copy link
Member

Would be helpful if the reproduction had failing assertions against the output JSON string or values, instead of sout

@cowtowncoder cowtowncoder added the has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue label Dec 25, 2023
@cowtowncoder
Copy link
Member

Yeah, use of EXTERNAL_PROPERTY is not really supported with "POJO-as-Array" because that will introduce a new main-level property. Ideally an InvalidDefinitionException would be thrown, I think (unless of course we figured out a way to support this setup).

+1 for actual unit test -- test code that requires manual inspection of textual output is not automatable, and it typically ambiguous wrt meaning ("what is it supposed to be again?").
Should just require an assertion or two.

@jamesmudd
Copy link
Author

Ok think I understand this issue, i'm basically in an unsupported case, POJO-as-array where one polymorphic elements type is declared in another element. I'm thinking a better solution would be needed, something like an EXTERNAL_ARRAY_PROPERTY. Then I guess it throws up the question of if the type property should actually be a field of the POJO or not? If not declaring the order of POJO-as-array properties might be ambiguous but maybe that can be handled by @JsonPropertyOrder

@cowtowncoder cowtowncoder removed the to-evaluate Issue that has been received but not yet evaluated label Dec 30, 2023
@cowtowncoder
Copy link
Member

@jamesmudd Yes, at least currently this is unsupported. I am not 100% sure it couldn't be solved, fwtw, but the whole As.EXTERNAL_PROPERTY is rather tricky to support even without as-array serialization (since Jackson does not create or hold actual in-memory representation of the logical output tree, but writes everything incrementally).
I am not sure that addition of new As.XXX option would help, the fundamental challenge probably remains.

Still, if you or anyone else wants to try to figure it out (and has time & interest), I'd be happy to help with PR. I don't have time to drive it, but do my best to try to help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has-failing-test Indicates that there exists a test case (under `failing/`) to reproduce the issue
Projects
None yet
Development

No branches or pull requests

3 participants