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

JSON/Jackson:没有类型字段的递归多态反序列化

慕容玉书
2023-03-14

我目前正在努力反序列化JSON数据结构,如下所示:

示例1:

{
    "condition": "AND",
    "rules": [
        {
            "id": "FIELD1",
            "field": "FIELD1",
            "type": "string",
            "input": "select",
            "operator": "equal",
            "value": [
                "a1"
            ]
        },
        {
            "id": "FIELD2",
            "field": "FIELD2",
            "type": "string",
            "input": "select",
            "operator": "in",
            "value": [
                "b1"
            ]
        }
    ]
}

示例 2:

{
    "condition": "AND",
    "rules": [
        {
            "id": "FIELD1",
            "field": "FIELD1",
            "type": "string",
            "input": "select",
            "operator": "equal",
            "value": [
                "a1"
            ]
        },
        {
            "id": "FIELD2",
            "field": "FIELD2",
            "type": "string",
            "input": "select",
            "operator": "in",
            "value": [
                "b1",
                "b2",
                "b3"
            ]
        },
        {
            "id": "FIELD3",
            "field": "FIELD3",
            "type": "string",
            "input": "select",
            "operator": "in",
            "value": [
                "c1",
                "c2",
                "c3"
            ]
        },
        {
            "id": "FIELD4",
            "field": "FIELD4",
            "type": "string",
            "input": "select",
            "operator": "in",
            "value": [
                "d1",
                "d2",
                "d3"
            ]
        },
        {
            "condition": "AND",
            "rules": [
                {
                    "id": "FIELD5",
                    "field": "FIELD5",
                    "type": "string",
                    "input": "select",
                    "operator": "equal",
                    "value": [
                        "e1"
                    ]
                },
                {
                    "id": "FIELD6",
                    "field": "FIELD6",
                    "type": "string",
                    "input": "select",
                    "operator": "in",
                    "value": [
                        "f1",
                        "f1",
                        "f3",
                        "f4",
                        "f5",
                        "f6"
                    ]
                },
                {
                    "condition": "AND",
                    "rules": [
                        {
                            "id": "FIELD7",
                            "field": "FIELD7",
                            "type": "string",
                            "input": "select",
                            "operator": "in",
                            "value": [
                                "g1",
                                "g2",
                                "g3"
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}

我必须处理许多此类结构的实例。它是规则生成器的输出。我无法更改JSON的格式,我必须使用我得到的东西。该结构是递归的,可以有多个级别。

我正在使用Jackson的ObjectMapper并构建一些内部类来映射数据。

static class Wrapper {
        public Condition condition;

        @JsonIgnoreProperties(ignoreUnknown = true)
        @JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
        @JsonSubTypes({
            @JsonSubTypes.Type(RuleGroup.class),
            @JsonSubTypes.Type(Rule.class) })
        public List<AbstractRuleObject> rules;
    }

    static abstract class AbstractRuleObject {
        public Condition condition;
        public List<Rule> rules;

        @JsonIgnoreProperties(ignoreUnknown = true)
        @JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
        @JsonSubTypes({
            @JsonSubTypes.Type(RuleGroup.class),
            @JsonSubTypes.Type(Rule.class) })
        public List<AbstractRuleObject> ruleGroups;
    }

    static class RuleGroup extends AbstractRuleObject {
        public Condition condition;
        public List<Rule> rules;
    }

    static class Rule extends AbstractRuleObject {
        public String id;
        public String field;
        public String type;
        public String input;
        public Operator operator;
        public List<String> value;
    }

大多数实例看起来像示例1,对于那些已经很好地工作的实例,但是有一些更复杂的实例,比如示例2,实际上比示例2更复杂、更深,但结构总是相同的:

总有一个“规则组”有一个“条件”和一个“规则”列表,规则可以是“规则”,也可以是“规则组”,你可以走的深度没有限制,但我相信它不会超过4或5级。每个级别可以有多个“规则组”

我无法解析这些更深层次的示例,使用当前代码和示例2,我得到了以下错误:

无法解析[简单类型,类MyClass$AbstractRuleObject]的子类型:无法推断出MyClass$AbstractRuleObject的唯一子类型(2个候选匹配)

共有1个答案

商骞仕
2023-03-14

Rule和RuleGroup没有任何共同之处,只是它们都可以出现在列表中,因此AbstractRuleObject不应该在其上有条件 --

我们也可以去掉Wrapper,因为它与RuleGroup相同。

这对我很有效:

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.List;

public class ParseExample {
    static class RuleObject {
    }

    static class RuleGroup extends RuleObject {

        public String condition;
        @JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
        @JsonSubTypes({
                @JsonSubTypes.Type(RuleGroup.class),
                @JsonSubTypes.Type(Rule.class)})
        public List<RuleObject> rules;
    }

    static class Rule extends RuleObject{

        public String id;
        public String field;
        public String type;
        public String input;
        public String operator;
        public List<String> value;
    }

    public static void main(String... args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        JsonParser parser = mapper.createParser(ParseExample.class.getClassLoader().getResourceAsStream("test2.json"));
        RuleGroup w = parser.readValueAs(new TypeReference<RuleGroup>() {});
    }
}

杰克逊版本:

      <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.12.4</version>
      </dependency>

结果:

args = {String[0]@1361} []
mapper = {ObjectMapper@1362} 
parser = {UTF8StreamJsonParser@1363} 
w = {ParseExample$RuleGroup@1364} 
 condition = "AND"
 rules = {ArrayList@1366}  size = 5
  0 = {ParseExample$Rule@1368} 
  1 = {ParseExample$Rule@1369} 
  2 = {ParseExample$Rule@1370} 
  3 = {ParseExample$Rule@1371} 
  4 = {ParseExample$RuleGroup@1372} 
   condition = "AND"
   rules = {ArrayList@1380}  size = 3
    0 = {ParseExample$Rule@1382} 
    1 = {ParseExample$Rule@1383} 
    2 = {ParseExample$RuleGroup@1384} 
     condition = "AND"
     rules = {ArrayList@1386}  size = 1
      0 = {ParseExample$Rule@1388} 
 类似资料:
  • 我看过jackson反序列化@JsonTypeInfo的一个例子,那就是: 我试过了,效果很好。现在的问题是,在示例类中,Cat和Dog是从Animal中引用的,我想避免这种情况。有没有一种方法可以将类型绑定从类动物中移除,并且仍然进行反序列化工作?谢谢

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

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

  • 问题内容: 我如何反序列化此json: 使用Google GSON? 问题答案: 要反序列化JSON,您需要为递归接口使用自定义反序列化器。在这种类中,您需要检查JSON并确定要实例化为JSON本身的type字段的类。在这里,您有一个我为您编写的示例基本解串器。 当然,管理边界事件可以得到改善(例如,如果没有类型字段,会发生什么情况?)。 这是我的代码的结果:

  • 使用Jackson将JSON响应反序列化为DTO。 使用Gson或Jackson反序列化JSON时忽略空字段 他们仍然从那个不规则的JSON对象创建一个对象。 这意味着我需要遍历这个列表,并通过实现一个清理方法删除所有不具有属性“value”的对象。 我的带有Jackson注释的DTO: 给定JSON响应的结果是初始化了3个DTOs,而不是4个。

  • Jackson版本:2.10.1 谢谢你的回答!