【问题标题】:How to de/serialize an instance with dynamically typed attribute如何反序列化具有动态类型属性的实例
【发布时间】:2019-03-05 17:45:52
【问题描述】:

使用 Jackson 序列化/反序列化 MyClass 实例的最佳方法是什么?

class MyClass {
    private String name;
    private MyInterface classInstance;

    // standard getters setters
}

属性classInstance可以是实现接口MyInterface的任意类型

理想情况下,我希望 yaml 结构看起来像这样

name: com.example.ClassE
classInstance: 
  value: 42
  category: "fancy"

请注意,“name”属性实际上包含“classInstance”属性内的对象的完全限定类型。

【问题讨论】:

    标签: java jackson yaml


    【解决方案1】:

    检查JsonTypeInfo 注释。它可以为您生成class 属性并使用此属性反序列化YAML 有效负载。检查以下示例:

    import com.fasterxml.jackson.annotation.JsonTypeInfo;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
    import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
    
    import java.math.BigDecimal;
    
    public class JsonApp {
    
        public static void main(String[] args) throws Exception {
            YAMLFactory yamlFactory = new YAMLFactory();
            yamlFactory.disable(YAMLGenerator.Feature.USE_NATIVE_TYPE_ID);
    
            ObjectMapper mapper = new ObjectMapper(yamlFactory);
    
            serialiseAndDeserialise(mapper, new MyValue());
            serialiseAndDeserialise(mapper, new MyBigDecimal());
        }
    
        private static void serialiseAndDeserialise(ObjectMapper mapper, MyInterface myInterface) throws java.io.IOException {
            MyClass myClass = new MyClass();
            myClass.setInstance(myInterface);
    
            String yaml = mapper.writeValueAsString(myClass);
            System.out.println(yaml);
            System.out.println(mapper.readValue(yaml, MyClass.class));
        }
    }
    
    class MyClass {
    
        @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "name")
        private MyInterface instance;
    
        public MyInterface getInstance() {
            return instance;
        }
    
        public void setInstance(MyInterface instance) {
            this.instance = instance;
        }
    
        @Override
        public String toString() {
            return "MyClass{" +
                    "instance=" + instance +
                    '}';
        }
    }
    
    interface MyInterface {
    }
    
    class MyValue implements MyInterface {
        private int value = 42;
        private String category = "fancy";
    
        public int getValue() {
            return value;
        }
    
        public void setValue(int value) {
            this.value = value;
        }
    
        public String getCategory() {
            return category;
        }
    
        public void setCategory(String category) {
            this.category = category;
        }
    
        @Override
        public String toString() {
            return "MyValue{" +
                    "value=" + value +
                    ", category='" + category + '\'' +
                    '}';
        }
    }
    
    class MyBigDecimal implements MyInterface {
        private BigDecimal pi = BigDecimal.valueOf(Math.PI);
    
        public BigDecimal getPi() {
            return pi;
        }
    
        public void setPi(BigDecimal pi) {
            this.pi = pi;
        }
    
        @Override
        public String toString() {
            return "MyBigDecimal{" +
                    "pi=" + pi +
                    '}';
        }
    }
    

    上面的代码打印:

    ---
    instance:
      name: "com.celoxity.MyValue"
      value: 42
      category: "fancy"
    
    MyClass{instance=MyValue{value=42, category='fancy'}}
    ---
    instance:
      name: "com.celoxity.MyBigDecimal"
      pi: 3.141592653589793
    
    MyClass{instance=MyBigDecimal{pi=3.141592653589793}}
    

    如果您想将name 移动到与instance 相同的级别,请将注释更改为:

    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "name")
    

    输出将变为:

    ---
    instance:
      value: 42
      category: "fancy"
    name: "com.celoxity.MyValue"
    
    MyClass{instance=MyValue{value=42, category='fancy'}}
    ---
    instance:
      pi: 3.141592653589793
    name: "com.celoxity.MyBigDecimal"
    
    MyClass{instance=MyBigDecimal{pi=3.141592653589793}}
    

    我更喜欢第一个,因为它表明name 属性属于instance。如果您从注释中删除 name 属性,Jackson 将使用这种use - '@class' 的默认名称。

    另见:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-30
      • 1970-01-01
      • 1970-01-01
      • 2016-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多