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

JSON/ Jackson: Recursive polymorphic deserialization without type field

我目前正在努力反序列化一个看起来像这样的 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 更复杂、更深入,但结构始终相同:

总有一个“RuleGroup”和一个“Condition”和一个“Rule”列表,规则可以是“Rule”也可以是“RuleGroup”,没有限制你可以去多深,但我相信它不会超过 4 或 5 级。每个级别可以有多个“RuleGroups”

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

Could not resolve subtype of [simple type, class MyClass$AbstractRuleObject]: Cannot deduce unique subtype of MyClass$AbstractRuleObject (2 candidates match)

Rule 和 RuleGroup 没有任何共同点,除了它们都可以出现在列表中,所以 AbstractRuleObject 不应该有 conditionrules -- a Rule 没有这些属性。

我们也可以去掉 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}