Java 如何使用动态类型化属性反序列化实例

Java 如何使用动态类型化属性反序列化实例,java,jackson,yaml,Java,Jackson,Yaml,使用Jackson序列化/反序列化MyClass实例的最佳方法是什么 class MyClass { private String name; private MyInterface classInstance; // standard getters setters } 属性classInstance可以是实现接口MyInterface的任意类型 理想情况下,我希望yaml结构像这样 name: com.example.ClassE classInstance:

使用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”属性中包含完全限定类型的对象

检查
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}}
如果要将
名称
移动到与
实例
相同的级别,请仅将注释更改为:

@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
将使用此类
的默认名称使用
-
'@class'

另见: