杰克逊使用@jsontypeinfo时的序列化/次要化问题。有人可以向我解释这是如何工作的吗?

发布于 2025-01-29 04:37:07 字数 1441 浏览 3 评论 0原文

说我现在有这些类

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); 
    }
}

我能够成功地使用这些注释序列化 listofshape 对象,但我不再能够序列化圆圈类。我还注意到,当我序列化类时,JSON模式有所变化,因此我现在有一个额外的密钥(“ type”):

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

目前对我的工作是通过添加该新的密钥值来更改JSON字符串配对:

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

有人可以向我解释这里发生了什么? 为什么我无法再序列化圆对象? 为什么JSON模式会通过添加新的钥匙值对来改变?

谢谢您的时间。

Say I have these 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); 
    }
}

Now, say I want to add another class that will contain a list of Shape objects. I understand that to deserialize this class, I will have to add @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); 
    }
}

I am able to successfully serialize the ListOfShapes object now using these annotations but I am no longer able to serialize the circle class. I also noticed that the json schema changed a bit when I serialized the class so I now have an extra key ("type"):

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

The work around for me at the moment is to change the json string a bit by adding that new key value pair:

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

Can someone explain to me whats going on here?
Why am I not able to serialize the circle object any more?
Why does the json schema change, by the addition of a new key value pair?

Thank you for your time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

懷念過去 2025-02-05 04:37:07

它是按预期工作的。当您将jsontypeinfojsonsubtypes注释 shape> shape> shape 类时,就像您完成的那样:

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

您正在告知杰克逊,您期望找到属性命名type在您要挑选到shape> Shape类中的每个JSON中,如果缺席,Jackson会引起错误,此外以其价值序列化。您还告诉杰克逊,如果与类型属性相关的值是 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)); 

list> listofshapes包装器类别一起使用相同的方法:

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);

It's working as expected. When you add the JsonTypeInfo and JsonSubTypes annotations to your Shape class like you have done below:

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

You are informing jackson you are expecting to find a property named type in every json you want to deserialize to the Shape class and in case of absence jackson will raise an error, moreover the type property will be serialized with its value. You are also informing jackson that in case the value associated to the type property is circle the json has to be deserialized as a Circle object.

This behaviour is particularly useful when you are not aware of which type of object has to be deserialized or serialized like the example below :

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)); 

Same approach is used with a ListOfShapes wrapper 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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文