为什么杰克逊多态序列化在列表中不起作用?
杰克逊正在做一些真正奇怪的事情,我找不到任何解释。我正在进行多态序列化,当一个对象独立时它可以很好地工作。但是,如果将相同的对象放入列表并对列表进行序列化,则会删除类型信息。
Jackson is doing something truly bizarre and I cannot find any explanation for it. I'm doing polymorphic serialization and it works perfectly when an object is on its own. But if you put the same object into a list and serialize the list instead, it erases the type information.
它丢失类型信息的事实会导致人们怀疑类型擦除。但是在序列化列表的内容期间会发生这种情况;杰克逊所要做的就是检查它正在序列化的当前对象以确定它的类型。
The fact that it's losing type info would lead one to suspect type erasure. But this is happening during serialization of the contents of the list; all Jackson has to do is inspect the current object it's serializing to determine its type.
我用Jackson 2.5.1创建了一个例子:
I've created an example using Jackson 2.5.1:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
public class Test {
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
@JsonSubTypes({
@Type(value = Dog.class, name = "dog"),
@Type(value = Cat.class, name = "cat")})
public interface Animal {}
@JsonTypeName("dog")
public static class Dog implements Animal {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@JsonTypeName("cat")
public static class Cat implements Animal {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) throws JsonProcessingException {
List<Cat> list = new ArrayList<>();
list.add(new Cat());
System.out.println(new ObjectMapper().writeValueAsString(list));
System.out.println(new ObjectMapper().writeValueAsString(list.get(0)));
}
}
这是输出:
[{"name":null}]
{"@type":"cat","name":null}
如您所见,当对象在列表中时,Jackson不会添加类型信息。有谁知道为什么会发生这种情况?
As you can see, Jackson is not adding the type information when the object is in a list. Does anyone know why this is happening?
讨论了发生这种情况的各种原因在此处和此处。我不一定同意这些原因,但杰克逊,因为类型擦除,不会关闭蝙蝠知道元素的类型列表
(或 Collection
或 Map
)包含。它选择使用不能解释您的注释的简单序列化器。
The various reasons for why this happens are discussed here and here. I don't necessarily agree with the reasons, but Jackson, because of type erasure, doesn't off the bat know the type of elements the List
(or Collection
or Map
) contains. It chooses to use a simple serializer that doesn't interpret your annotations.
您可以在这些链接中建议两个选项:
You have two options suggested in those links:
首先,您可以创建一个实现 List< Cat>
的类,适当地实例化并序列化实例。
First, you can create a class that implements List<Cat>
, instantiate it appropriately and serialize the instance.
class CatList implements List<Cat> {...}
泛型类型参数 Cat
没有丢失。 Jackson可以访问它并使用它。
The generic type argument Cat
is not lost. Jackson has access to it and uses it.
其次,您可以实例化并使用 ObjectWriter
作为类型列表与LT;目录>
。例如
Second, you can instantiate and use an ObjectWriter
for the type List<Cat>
. For example
System.out.println(new ObjectMapper().writerFor(new TypeReference<List<Cat>>() {}).writeValueAsString(list));
将打印
[{"@type":"cat","name":"heyo"}]