在使用Jackson序列化java对象时维护子类型信息,而不使用包装器类
我试图使用Jackson在JSON文件和Java中包含两个子类的抽象类之间进行转换。理想情况下,我希望使用JSON,如下所示: 不带包装的Json文档在使用Jackson序列化java对象时维护子类型信息,而不使用包装器类,java,json,serialization,polymorphism,jackson,Java,Json,Serialization,Polymorphism,Jackson,我试图使用Jackson在JSON文件和Java中包含两个子类的抽象类之间进行转换。理想情况下,我希望使用JSON,如下所示: 不带包装的Json文档 [ { "type" : "lion", "name" : "Simba", "endangered" : true, "action" : "running" }, { "type" : "elephant", "name" : "Dumbo", "endangered" : false, "table" : [
[ {
"type" : "lion",
"name" : "Simba",
"endangered" : true,
"action" : "running"
}, {
"type" : "elephant",
"name" : "Dumbo",
"endangered" : false,
"table" : [ 1.0, 2.0, 3.0 ]
} ]
{
"animals" : [ {
"type" : "lion",
"name" : "Simba",
"endangered" : true,
"action" : "running"
}, {
"type" : "elephant",
"name" : "Dumbo",
"endangered" : false,
"table" : [ 1.0, 2.0, 3.0 ]
} ]
}
我已经注释了Animal
抽象类,如图所示
我可以使用包装器对象成功地读/写它,但是生成的JSON文件将包含一个额外的anives
对象
带包装的JSON文档
[ {
"type" : "lion",
"name" : "Simba",
"endangered" : true,
"action" : "running"
}, {
"type" : "elephant",
"name" : "Dumbo",
"endangered" : false,
"table" : [ 1.0, 2.0, 3.0 ]
} ]
{
"animals" : [ {
"type" : "lion",
"name" : "Simba",
"endangered" : true,
"action" : "running"
}, {
"type" : "elephant",
"name" : "Dumbo",
"endangered" : false,
"table" : [ 1.0, 2.0, 3.0 ]
} ]
}
当我使用普通Java列表时,我可以在没有包装的情况下成功地读取Json文档,但是如果我尝试编写它,输出文件将如下所示:
// Test reading using array
Animal[] jsonArray = mapper.readValue(
new FileInputStream(demoFile), Animal[].class);
System.out.println("Reading using array:\nObject: "
+ Arrays.toString(jsonArray));
// Test writing using array
outputJson = mapper.writeValueAsString(jsonArray);
System.out.println("Writing using array:\nJSON: " + outputJson);
output.json
[ {
"name" : "Simba",
"endangered" : true,
"action" : "running"
}, {
"name" : "Dumbo",
"endangered" : false,
"table" : [ 1.0, 2.0, 3.0 ]
} ]
Java代码
// Test reading using raw list
JavaType listType = mapper.getTypeFactory()
.constructCollectionType(List.class, Animal.class);
List<Animal> jsonList = mapper.readValue(new FileInputStream(
"demo.json"), listType);
jsonDocument = new File(outputFile);
// Test writing using raw list
mapper.writerWithDefaultPrettyPrinter().writeValue(jsonDocument,
jsonList);
这里的问题是Java类型擦除,这意味着列表对象的标称类型是List。由于java.lang.Object没有@JsonTypeInfo,因此不会启用它 但您可以将Jackson配置为使用特定Java类型转换列表元素:
JavaType listJavaType = mapper.getTypeFactory().constructCollectionType(List.class, Animal.class);
String outputJson = mapper.writerWithType(listJavaType).writeValueAsString(myList);
修改您的代码:
公共静态void main(字符串[]args){
另一种解决方案:
您可以使用自定义TypeReference通知Jackson需要使用什么类来转换列表:
mapper.writerWithType(new TypeReference<List<Animal>>() {}).writeValueAsString(myList)
mapper.writerWithType(新类型引用(){}).writeValueAsString(myList)
该解决方案也可以工作,但我更喜欢主解决方案,因为它更干净,您不需要实例化抽象的“TypeReference”类…谢谢,您是对的,我实际上发现它被列为“已知问题”在wiki中,.我最终使用了一个数组来避免创建类型引用,也许您想在解决方案中更新它,
Animal[]array=myList.toArray(新的Animal[myList.size());outputJson=mapper.writeValueAsString(数组);System.out.println(outputJson);
您使用JavaType
而不是TypeReference
的解决方案非常简单,因此我更新了我的问题:-)
mapper.writerWithType(new TypeReference<List<Animal>>() {}).writeValueAsString(myList)