1

I'm trying to serialize/deserialize a polymorphic type with Jackson 2.9.8, and it works fine unless I put an object of such type into a collection, because for some reason type info is not written then. Let's consider the following example:

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "animalKind")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "Dog")
})
public interface Animal {
}
@JsonIgnoreProperties(ignoreUnknown = true)
public class Dog implements Animal {
    private Boolean goodBoy;
    public Boolean isGoodBoy() { return goodBoy; }
    public void setGoodBoy(Boolean goodBoy) { this.goodBoy = goodBoy; } 
}

Now let's serialize an instance of Dog:

ObjectMapper objectMapper = new ObjectMapper();

Dog mike = new Dog();
mike.setGoodBoy(true);

// This works just fine
String mikeJson = objectMapper.writeValueAsString(mike);
System.out.println(mikeJson);

// This doesn't work
String listJson = objectMapper.writeValueAsString(Collections.singleton(mike));
System.out.println(listJson);

// This doesn't either
String mapJson = objectMapper.writeValueAsString(Collections.singletonMap("Mike", mike));
System.out.println(mapJson);

The output is the following:

{"animalKind":"Dog","goodBoy":true}
[{"goodBoy":true}]
{"Mike":{"goodBoy":true}}

So the animalKind is written in the first case but it's not in the second and the third case. Am I missing some serialization settings here or is it a bug?

Thank you!

Michał Ziober
  • 37,175
  • 18
  • 99
  • 146

1 Answers1

3

You need to instruct Jackson that you need given collection with reading abstract type annotation. See example:

CollectionType animalsListType = mapper.getTypeFactory()
    .constructCollectionType(Set.class, Animal.class);
System.out.println(mapper.writer().withType(animalsListType).writeValueAsString(Collections.singleton(mike)));

Map<String, Dog> mikeMap = Collections.singletonMap("Mike", mike);
MapType mapType = mapper.getTypeFactory().constructMapType(Map.class, String.class, Animal.class);
System.out.println(mapper.writer().withType(mapType).writeValueAsString(mikeMap));

Above code prints:

[{"animalKind":"Dog","goodBoy":true}]
{"Mike":{"animalKind":"Dog","goodBoy":true}}
Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
  • Wow, that's a bummer as I don't have a control over the code that actually writes the JSON, I can only model the classes/annotations to be serialized. – Alexander Eliseyev Mar 18 '19 at 13:43
  • 1
    @AlexanderEliseyev, I will try to think about it what other options we have but probably for raw collection this one is the best. Do these collections are part of bigger `POJO` or you provide collection as root object to serialisation process. – Michał Ziober Mar 18 '19 at 15:22