当前位置: 首页 > 知识库问答 >
问题:

使用jackson注释反序列化多级多态子类型

万俟穆冉
2023-03-14

我想使用jackson注释反序列化2级多态子类型。基本上,我想使用json注释和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;
    }
    }

我尝试为我的项目创建 Mixin 类作为

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

和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"])

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

共有2个答案

夏侯昆琦
2023-03-14

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

@JsonSubTypes({
    MySubItemA.class,
    MySubItemB.class,
    MySubItemC.class
})
龙智
2023-03-14

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

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

所以你需要做的是:

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

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); 

  }

希望这能解决你的顾虑。

谢谢

纳库尔·瓦希思

 类似资料:
  • 问题内容: 如果我有这样的类结构: 还有另一种反序列化的方法吗?在父类上使用此注释: 我不想强迫我的API的客户包括反序列化一个子类。 杰克逊不是使用,而是提供了一种方法来注释子类并通过唯一属性将其与其他子类区分开来?在上面的示例中,这类似于“如果JSON对象将其反序列化为,如果它将其反序列化为”。 问题答案: 感觉像是应该使用的东西,但是我在文档中进行了选择,可以提供的任何属性似乎都不符合您所描

  • 我对Jackson和类型层次结构有以下问题。我正在序列化一个类SubA,该类将扩展为一个字符串,然后尝试将其反序列化回来。当然,在编译时,系统不知道它是基还是SubA,因此我希望它是基,如果它是SubA,则会在编译后执行一些其他操作。 我的基本类看起来像: ...和一个派生自的类: ... 我试图执行以下代码: String是: 但我一次又一次地犯同样的错误。映射器现在知道如何处理另一个类参数-它

  • 我看过jackson反序列化@JsonTypeInfo的一个例子,那就是: 我试过了,效果很好。现在的问题是,在示例类中,Cat和Dog是从Animal中引用的,我想避免这种情况。有没有一种方法可以将类型绑定从类动物中移除,并且仍然进行反序列化工作?谢谢

  • 我正在尝试使用Jakson反序列化一个嵌套的多态类型。也就是说,我的顶级类型引用了另一个多态类型,该类型最终由不抽象的类扩展。这不起作用,它会抛出一个异常。 下面是我尝试做的一个简化的例子。 我得到了关于抽象类型的标准异常。 让我解释一下我的用例。我有一个描述数据工作流的Json文档。我在“Level One”有一个抽象类型,描述对单个值的操作。我派生了一堆不是抽象的类,它们实现了公共操作(我用@

  • 我想为我们的REST API实现一个自定义的反序列化器,它不仅被Java应用程序使用。因此,我不想让Jackson将类型信息放入序列化的JSON中。 我目前正在努力反序列化<code>CollectionExpand</code>,因为它包含特定<code>ResourceModel</code>的<code>数据</code>列表。 < code>ResourceModel是一个接口,每个< c