Jackson serialization/deserialization 使用@JsonTypeInfo 时出现问题。有人可以向我解释这是如何工作的吗?
Jackson serialization/deserialization problems when using @JsonTypeInfo. Can someone explain to me how this is working?
说我有这些 classes
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);
}
}
现在,假设我想添加另一个 class,它将包含一个 Shape 对象的列表。我知道要反序列化这个 class,我必须添加 @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 对象,但我无法再序列化圆 class。我还注意到,当我序列化 class 时,json 模式发生了一些变化,所以我现在有一个额外的键(“type”):
{
"type": "circle",
"r": 5
}
我目前的解决方法是通过添加新的键值对来稍微更改 json 字符串:
String json = "{\"type\": \"circle\", \"r\": 25 }";
谁能给我解释一下这是怎么回事?
为什么我无法再序列化圆形对象?
为什么 json 架构会因添加新的键值对而发生变化?
感谢您的宝贵时间。
一切正常。当您将 JsonTypeInfo
和 JsonSubTypes
注释添加到 Shape
class 时,如下所示:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Circle.class, name = "circle")
})
public abstract class Shape {}
您正在通知杰克逊您希望在每个 json 中找到一个名为 type
的 属性 并反序列化为 Shape
class 并且如果不存在,杰克逊将引发错误,而且 type
属性 将使用其值进行序列化。您还通知杰克逊,如果与 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
包装器 class:
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);
说我有这些 classes
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);
}
}
现在,假设我想添加另一个 class,它将包含一个 Shape 对象的列表。我知道要反序列化这个 class,我必须添加 @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 对象,但我无法再序列化圆 class。我还注意到,当我序列化 class 时,json 模式发生了一些变化,所以我现在有一个额外的键(“type”):
{
"type": "circle",
"r": 5
}
我目前的解决方法是通过添加新的键值对来稍微更改 json 字符串:
String json = "{\"type\": \"circle\", \"r\": 25 }";
谁能给我解释一下这是怎么回事? 为什么我无法再序列化圆形对象? 为什么 json 架构会因添加新的键值对而发生变化?
感谢您的宝贵时间。
一切正常。当您将 JsonTypeInfo
和 JsonSubTypes
注释添加到 Shape
class 时,如下所示:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Circle.class, name = "circle")
})
public abstract class Shape {}
您正在通知杰克逊您希望在每个 json 中找到一个名为 type
的 属性 并反序列化为 Shape
class 并且如果不存在,杰克逊将引发错误,而且 type
属性 将使用其值进行序列化。您还通知杰克逊,如果与 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
包装器 class:
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);