Jackson在使用@JsonTypeInfo时出现序列化/反序列化问题,有人能给我解释一下这是如何工作的吗?

rm5edbpk  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(171)

假设我有这些课

public abstract class Shape {}

public class Circle extends Shape{
    private int r;
    ...
}

public class Main {
    public static void main(String [] args) {
         String json = "{\"r\": 25 }";
         ObjectMapper om = new ObjectMapper();

         //WORKS FINE
         Circle circle = om.readValue(json, Circle.class); 
    }
}

现在,假设我想添加另一个包含 Shape 对象列表的类,我知道要反序列化这个类,我必须添加@JsonTypeInfo。

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Circle.class, name = "circle")
})
public abstract class Shape {}

public class Circle extends Shape{...}

public class ListOfShapes {
    List<Shape> shapes;
}

public class Main {
    public static void main(String [] args) {
         String json = "{\"r\": 25 }";
         ObjectMapper om = new ObjectMapper();

         //DOES NOT WORK
         Circle circle = om.readValue(json, Circle.class); 
    }
}

我现在可以使用这些注解成功地序列化 ListOfShapes 对象,但是我不能再序列化circle类了。我还注意到,当我序列化类时,json模式发生了一些变化,所以我现在有了一个额外的键(“type”):

{
    "type": "circle",
    "r": 5
}

目前我的工作是通过添加新的键值对来稍微更改json字符串:

String json = "{\"type\": \"circle\", \"r\": 25 }";

**有人能给我解释一下这里发生了什么吗?****为什么我不能再序列化circle对象了?**为什么json模式会因为添加了新的键值对而发生变化?

感谢您抽出宝贵时间。

gmxoilav

gmxoilav1#

当你把JsonTypeInfoJsonSubTypes注解添加到你的Shape类中时,你可以像下面这样做:

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Circle.class, name = "circle")
})
public abstract class Shape {}

您将通知Jackson,您希望在每个json中找到一个名为type的属性,以便将其反序列化为Shape类,如果不存在,jackson将引发一个错误,此外,type属性将使用其值进行序列化。您还将通知Jackson,如果与type属性关联的值为 circle JSON必须被反串行化为Circle对象。
当您不知道必须反序列化或序列化哪种类型的对象时,此行为特别有用,如下例所示:

String json = "{\"type\": \"circle\", \"r\": 25 }";
ObjectMapper om = new ObjectMapper();
//I don't know json is a circle object but it can be deserialized as a Shape
Shape circle = om.readValue(json, Shape.class);
System.out.println(circle instanceof Circle); //<-- it prints true
//ok type is present with value circle {"type":"circle","r":25}
System.out.println(mapper.writeValueAsString(circle));

ListOfShapes Package 类使用相同的方法:

String json = "{\"type\": \"circle\", \"r\": 25 }";
ObjectMapper om = new ObjectMapper();
Shape circle = om.readValue(json, Shape.class);
//instantiate the wrapper class
ListOfShapes listOfShapes = new ListOfShapes();
listOfShapes.shapes = List.of(circle);
json = mapper.writeValueAsString(listOfShapes);
//it prints {"shapes":[{"type":"circle","r":25}]}
System.out.println(json);
listOfShapes = om.readValue(json, ListOfShapes.class);
//ok list inside contains the Circle object
System.out.println(listOfShapes);

相关问题