Динамическое добавление новых подтипов после того, как исходный супертип уже был настроен в jackson

#java #inheritance #jackson #jackson-databind

#java #наследование #джексон #jackson-databind

Вопрос:

У меня есть один суперкласс Field и есть два других класса, которые наследуют суперкласс Field .

Я хочу динамически добавлять подкласс, не влияя на изменения суперкласса

 public class TestConfiguration {

private List<Field> fields;


}
  

Я хочу использовать сопоставление таким образом, когда fields является экземпляром того же класса Field, тогда без свойства className «Field», используемого для сопоставления

 {
          "fields" : [ {
            "name" : "First_name",
            "type" : {
              "fieldType" : {
                "name" : "string"
              }
            },
            "required" : true
          }]
}
  

Я хочу использовать сопоставление таким образом, когда fields является экземпляром дочернего класса ExtendedHierarchicalField, тогда свойство className «ExtendedHierarchicalField» используется для сопоставления или любым другим способом для сопоставления объектов

 {
          "fields" : [ {
            "className" : "ExtendedHierarchicalField",
            "name" : "First_name",
            "type" : {
              "fieldType" : {
                "name" : "string"
              }
            },
            "required" : true
          }]
}
  

Ответ №1:

Вы можете добиться того же, используя аннотации jackson.
Определите свои классы как:
Field.java

 import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, property = "className")
@JsonSubTypes({
                      @JsonSubTypes.Type(value = SubField1.class),
                      @JsonSubTypes.Type(value = SubField2.class)
              })
public class Field {
    public String name;
}
  

SubField1.java

 public class SubField1 extends Field {
    public String subField1Property = "subField1Property value";
}
  

SubField2.java

 public class SubField2 extends Field {
    public String subField2Property = "subField2Property value";
}
  

TestConfiguration.java

 public class TestConfiguration {
    public List<Field> fields;
}
  

основной метод

 public static void main(String[] args) throws JsonProcessingException {

    ObjectMapper mapper = new ObjectMapper();

    Field field = new Field();
    field.name = "main field";

    Field subField1 = new SubField1();
    subField1.name = "sub field 1";

    Field subField2 = new SubField2();
    subField2.name = "sub field 2";

    TestConfiguration testConfiguration = new TestConfiguration();
    testConfiguration.fields = Arrays.asList(field, subField1, subField2);

    String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(testConfiguration);
    System.out.println(json);
}
  

Вывод:

 {
  "fields" : [ {
    "className" : ".Field",
    "name" : "main field"
  }, {
    "className" : ".SubField1",
    "name" : "sub field 1",
    "subField1Property" : "subField1Property value"
  }, {
    "className" : ".SubField2",
    "name" : "sub field 2",
    "subField2Property" : "subField2Property value"
  } ]
}
  

Примечание:

  • className свойство является своего рода обязательным (даже для класса верхнего уровня Field ) из-за того, что при десериализации того же json обратно в POJO без className свойства будет запутано, какой экземпляр создавать, Field , SubField1 или SubField2 .
  • Я использовал общедоступные свойства в POJO для простоты. Вы должны предпочесть закрытые поля только с установщиком / получателем.