I'm encountering an inconsistency in how @JsonTypeInfo is applied when serializing collections.
When I serialize an array of polymorphic objects, Jackson includes the @type metadata as expected.
However, when I serialize a List
Jackson should include @type metadata for both arrays and lists, as long as the element type is correctly annotated with @JsonTypeInfo
Example code
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
import java.util.Arrays;
import java.util.List;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog")
})
abstract class Animal {
public String name;
}
@JsonTypeName("dog")
class Dog extends Animal {
public String breed;
public Dog() {
this.name = "Fido";
this.breed = "Labrador";
}
}
``` java ObjectMapper mapper = new ObjectMapper(); mapper.registerSubtypes(Dog.class);
// Case 1: Array Animal[] array = new Animal[] { new Dog() }; System.out.println(mapper.writeValueAsString(array));
// Output: // [{"@type":"dog","name":"Fido","breed":"Labrador"}] ✅
// Case 2: List
List
// Output: // [{"name":"Fido","breed":"Labrador"}] ❌ Missing @type
Questions
- Is this behavior intentional? Why does Jackson serialize type info correctly in arrays but not in lists ?
- Is there a way to globally or locally configure Jackson to include @type when serializing List
? - While using TypeReference
- > with ObjectMapper.writerFor(...) does force the inclusion of @type, this approach isn't feasible when using higher-level libraries like Spring's RestTemplate, which handles serialization internally.
=> Is there a recommended way to ensure @type metadata is included when sending a List
through such frameworks — without manually serializing to JSON strings or switching to arrays?
Environment Jackson version: 2.14.2 (also reproduced in earlier versions) Java: 21+ Module: jackson-databind
Comment From: pjfanning
Jackson 2.19.2 is the latest release. Could you try that?
Comment From: JooHyukKim
Also, try declaring a wrapper class to contain the polymorphic list and serialize that container? considering type erasure
Comment From: cowtowncoder
Definitely infamous Type Erasure problem: when directly serializing ("root value") List<T>
values, all runtime sees (and can see) is List<?>
, i.e. List<Object>
. And since java.lang.Object
has no @JsonTypeInfo
, no type info is included.
There are couple of ways to work-around this:
- Use helper type like
public class AnimalList extends ArrayList<Animal> { }
- Use wrapper (like @JooHyukKim suggested) -- non-generic Java class with
List<Animal> animals
-- type information is retained in class declarations -
Construct
ObjectWriter
with specified typeObjectWriter w = mapper.writerFor(new TypeReference
- >() { });
String json = w.writeValueAsString(animalList);
I hope this helps.