【问题标题】:Deserialize multi level polymorphic subtypes using jackson annotations使用杰克逊注解反序列化多级多态子类型
【发布时间】:2017-01-10 13:49:27
【问题描述】:

我想使用杰克逊注解反序列化 2 级多态子类型。 基本上我想使用 json annotations 和 jacksons 将以下 json 转换为 xml,如下所示

{
  "mainSet": {
    "name": "bla bla",
    "myItems": [
      {
        "MySubItem": {
          "id": 1,
          "name": "Value1",
          "itemAProperty1": "Some stuff",
          "itemAProperty2": "Another property value",
          "type": "MySubItemA"
        }
      },
      {
        "MySubItem": {
          "id": 2,
          "name": "Value2",
          "itemBProperty1": 1000,
          "itemBProperty2": "B property",
          "type": "MySubItemB"
        }
      }
    ]
  }
}

我想要的最终 XML 是

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<mainTag schemaVersion="1" xmlns="http://www.utiba.com/xml/ns/brms/v1"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <name>bla bla</name>
    <MySubItem xsi:type="MySubItemA" id="1" name="value1" itemAProperty1="Some stuff" itemAProperty2="Another property value"/>
    <MySubItem xsi:type="MySubItemB" id="2" name="value2" itemAProperty1=1000 itemAProperty2="B Property"/>
</mainTag>

我有以下一组类 - 主类

public abstract class MyItem {

private int id;
private String name;
 //getter and setter
}

它有抽象子类

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MySubItem")
@XmlSeeAlso({
    MySubItemA.class,
    MySubItemB.class,
    MySubItemC.class
})
    public abstract class MySubItem extends MyItem {

    private String itemAProperty1;
    private String itemAProperty2;
     //getter and setter
    }

而 MySubItem 有具体的子类说 MySubItemA、MySubItemB、MySubItemC

现在最后,我们创建一个包含抽象类对象列表的客户端类

 import java.util.ArrayList;
    import java.util.List;

    public class MainSet{
     @XmlElements({
        @XmlElement(name = "MysubItem", type = MySubItem.class),
    })
    private List<MyItem> myItems;

      public List<MyItem> getMyItems() {
        return this.myItems;
    }
    }

我尝试为 MyItem 创建 Mixin 类

@JsonTypeInfo(use=Id.MINIMAL_CLASS, include=As.PROPERTY, property="itemType")
@JsonSubTypes({
   @Type(MySubItem.class)
})

And for 和 MySubItem

@JsonTypeInfo(use=Id.MINIMAL_CLASS, include=As.PROPERTY, property="type")
@JsonSubTypes({
   @Type(MySubItemA.class)
   @Type(MySubItemB.class)
   @Type(MySubItemC.class)
})

我得到的错误是:

Error parsing JSON from client: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of MySubItem, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
 at [Source: java.io.StringReader@26bd8952; line: 1, column: 498] (through reference chain: bla bla class ["mainSet"]->com.bla.bla["myItems"])

ISSUE : 为 myItems 列表创建 mixin 类,具有 2 级抽象子类层次结构

【问题讨论】:

    标签: json serialization jackson polymorphism deserialization


    【解决方案1】:

    Jackson api 不支持多级多态类型层次结构。

    你可以看看:https://github.com/FasterXML/jackson-databind/issues/374

    所以你需要做的是:

    请为 jsonMapper 创建一个反序列化器(对于 MySubItem.class,比如 MySubItemDeserializerMixin.class),就像我们为其他 Mixin 类所做的那样。

    mapper.addMixInAnnotations(MySubItem.class, MySubItemDeserializerMixin.class);
    

    MySubItemDeserializerMixin.java 看起来像:

    @JsonDeserialize(using = MySubItemDeserializer.class)
    public abstract class MySubItemDeserializerMixin{
    }
    

    您还需要按照 MySubItemDeserializerMixin.java 中的指定为 MySubItem 创建一个反序列化器(MySubItemDeserializer)。

    现在您需要创建如下所示的 MySubItemMixin.java:

    @JsonTypeInfo(use=Id.MINIMAL_CLASS, include=As.PROPERTY, property="type")
    @JsonSubTypes({
    @Type(MySubItemA.class)
    @Type(MySubItemB.class)
    @Type(MySubItemC.class)
    })
    

    在 MySubItemDeserializer 中,您可以执行以下操作:

    @Override
    public MySubItem deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
    
        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
    
        ObjectMapper jsonMapper = new ObjectMapper();
    
        // Omit null values from the JSON.
        jsonMapper.setSerializationInclusion(Include.NON_NULL);
    
        // Treat received empty JSON strings as null Java values.
        // Note: doesn't seem to work - using custom deserializer through module
        // below instead.
        jsonMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
    
        jsonMapper.addMixInAnnotations(MySubItem.class, MySubItemMixin.class);
    
        // Enable interpretation of JAXB annotations on our beans (e.g. for 
        // resolving ID/IDREF references).
        jsonMapper.registerModule(new JaxbAnnotationModule());
    
        MySubItem condition = jsonMapper.readValue(node.toString(), MySubItem.class); 
    
      }
    

    希望能解决您的疑虑。

    感谢和问候

    纳库尔·瓦希什斯

    【讨论】:

      【解决方案2】:

      您的子类型注释告诉 JAXB 要做什么,但没有告诉杰克逊,这是试图从 JSON 反序列化您的请求的原因。除了 TypeInfo 之外,尝试将其添加到您的抽象类中:

      @JsonSubTypes({
          MySubItemA.class,
          MySubItemB.class,
          MySubItemC.class
      })
      

      【讨论】:

      • 嗨我忘了提早点..我现在已经更新了..我正在使用上面更新的子类型标签。但它不起作用。同样的错误。
      • 我还尝试通过添加 @XmlElement(name = "mySubItem", type = MySubItemA.class),@XmlElement(name = "mySubItem", type = MySubItemB.class),@XmlElement(name = "mySubItem", type = MySubItemC.class)MainSet 创建 mixin 类,但在这种情况下,它会为所有子子类型 A、B、 C.
      猜你喜欢
      • 1970-01-01
      • 2012-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多