【问题标题】:How to use @JsonTypeInfo, @JsonSubType to determine a field type based on a sibling field's value?如何使用@JsonTypeInfo、@JsonSubType 根据兄弟字段的值确定字段类型?
【发布时间】:2020-08-11 17:13:37
【问题描述】:

假设我有这样的类结构:-

class ShapeRequest {

    ShapeInfo shapeInfo;
    Shape shape;

    static class ShapeInfo {
        String shapeName;
        String shapeDimension;
    }

    static abstract class Shape {

    }

    static class Square extends Shape{
        int area;
    }

    static class Circle extends Shape{
        int area;
    }
}

如何根据 shapeInfo.shapeName 字段值以将字段 shape 映射到 Square 或 Circle 类型的方式反序列化 ShapeRequest?

例如,下面的 JSON 应该映射到具有 Circle 形状类型的 ShapeRequest,因为 shapeInfo.shapeName = "circle"

{
  "shapeInfo": {
    "shapeName": "circle",
    "shapeDimension": "2"
  },
  "shape": {
    "area": 10
  }
}

【问题讨论】:

    标签: java spring jackson jackson-databind jackson2


    【解决方案1】:

    你可以在下面使用它:

    public class JsonTypeExample {
    
        // Main method to test our code.
        public static void main(String args[]) throws IOException {
            ObjectMapper objectMapper = new ObjectMapper();
    
            // json to circle based on shapeName
            String json = "{\"shapeName\":\"circle\",\"area\":10}";
            Shape shape = objectMapper.readerFor(Shape.class).readValue(json);
            System.out.println(shape.getClass());
            System.out.println(objectMapper.writeValueAsString(shape));
    
            // json to square based on shapeName
            json = "{\"shapeName\":\"square\",\"area\":10}";
            shape = objectMapper.readerFor(Shape.class).readValue(json);
            System.out.println(shape.getClass());
            System.out.println(objectMapper.writeValueAsString(shape));
        }
    
        @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "shapeName")
        @JsonSubTypes({
                @JsonSubTypes.Type(value = Square.class, name = "square"),
                @JsonSubTypes.Type(value = Circle.class, name = "circle")
        })
        static class Shape {
            Shape() {
            }
        }
    
        @JsonTypeName("square")
        static class Square extends Shape {
            public int area;
    
            Square(int area){
                super();
                this.area = area;
            }
        }
    
        @JsonTypeName("circle")
        static class Circle extends Shape {
            public int area;
    
            Circle(int area){
                super();
                this.area = area;
            }
        }
    }
    

    这里的 Shape 类是用 JsonTypeInfo 和 JsonSubTypes 注解的。

    @JsonTypeInfo 用于表示序列化和反序列化中要包含的类型信息的详细信息。 这里的 property 表示确定 SubType 时要考虑的值。

    @JsonSubTypes 用于表示注解类型的子类型。 这里 namevalue 将 shapeName 映射到适当的 SubType 类。

    每当像示例中那样传递 JSON 时,都会通过 JsonSubTypes 进行反序列化,然后它会根据 shapeName 返回适当的 JAVA 对象。

    【讨论】:

    • 感谢您的回复。但是,您错过了反序列化到包含 shapeInfo 和实际形状的类 ShapeRequest {} 的全部要点
    • 你能分享一个你想如何序列化/反序列化 ShapeRequest 的例子吗?
    • 看起来你没有正确地构建问题陈述。将类型能指放在不同的地方并不理想。尝试在形状内移动它。
    • 是的。但不幸的是,这就是它来自外部系统的方式。
    • 我尝试了很多来实现您正在寻找的东西,但这似乎是不可能的。您可以将形状最大设置为圆形/正方形,但不能设置区域。这可以使用显式映射器来实现: new ObjectMapper().readerFor(Shape.class) .readValue(new ObjectMapper().writeValueAsString( ImmutableMap.of("shapeName", shapeInfo.getShapeName(), "area", 0)) ).. 这应该在 shapeInfo 设置器中调用,并在 ShapeRequest 中忽略形状设置器。我觉得这并不容易实现,因为问题陈述与 JsonSubTypes 支持的内容背道而驰。
    猜你喜欢
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 2017-08-23
    • 1970-01-01
    • 2021-10-16
    • 2020-07-07
    • 2021-02-25
    相关资源
    最近更新 更多