【问题标题】:Deserializing JSON with Jackson for polymorphic classes使用 Jackson 为多态类反序列化 JSON
【发布时间】:2019-12-06 03:04:29
【问题描述】:

我正在尝试反序列化 JSON,它可以是 GroupRule 或 AttributeRule:

AbstractRule
  GroupRule
  AttributeRule

我希望我的模型/实体/POJO 是通用的,因为我还在其他项目中使用相同的类与 Snakeyaml 或其他序列化提供程序。

话虽如此,我偶然发现了这个:https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization

在文章中,它表明我可以做到:

{ // Using fully-qualified path
    "@class" : "com.fasterxml.beans.EmployeeImpl", ...
  }

但是,当我这样做时,我得到:

Cannot construct instance of `com.walterjwhite.email.organization.api.configuration.rule.AbstractRule` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 at [Source: (FileInputStream); line: 4, column: 10] (through reference chain: com.walterjwhite.email.organization.api.configuration.rule.EmailMatcherRule["rule"])
    com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)

我的配置是这样的:

 {
    "name": "default",
    "ordering": "1",
    "rule": {
        "@class": "com.walterjwhite.email.organization.api.configuration.rule.GroupRule",
        "criteriaType": "Should",
        "rules": [
            {"@class": "com.walterjwhite.email.organization.api.configuration.rule.AttributeRule",
            "emailMessageField": "Subject",
            "values": ["default"]
            }
        ]
    },
    "matchType": "ContainsIgnoreCase",
    "actionClassNames": [
        "com.walterjwhite.email.organization.plugins.count.CountAction",
        "com.walterjwhite.email.organization.plugins.index.IndexAction",
        "com.walterjwhite.email.organization.plugins.reply.MoveAction"
    ]
}

在 Java 方面,我通常这样做:

mapper.readValue(inputStream, entityType);

现在,本例中的 entityType 是 EmailMatcherRule,其中有一个规则字段,可以是属性或组。 Inputstream 就是我传入的 fileInputStream ...

我使用的是 Jackson 2.10.1。我还从 YAML 转换了上面的 JSON,通过 Snakeyaml 可以正常工作。请注意,它会自动将类嵌入到 YAML 中,因此这不是问题。

我的 JSON 是否正确 - 根据文档,我应该能够添加 @class 属性来指定我要使用的类,对吧?

【问题讨论】:

    标签: java json jackson


    【解决方案1】:

    我在下面尝试过,它在没有任何配置的情况下工作。不确定这是否是您想要实现的目标:

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        String groupRuleStr = "{\"parentId\":\"parent\",\"groupId\":\"group\"}";
        String attributeRuleStr = "{\"parentId\":\"parent\",\"attributeId\":\"attribute\"}";
    
        GroupRule groupRule = mapper.readValue(groupRuleStr, GroupRule.class);
        AttributeRule attributeRule = mapper.readValue(attributeRuleStr, AttributeRule.class);
    
        System.out.println(groupRule.groupId);
        System.out.println(attributeRule.attributeId);
    
    }
    
    static abstract class AbstractRule {
        public String parentId = "parent";
    }
    
    static class GroupRule extends AbstractRule {
        public String groupId = "group";
    }
    
    static class AttributeRule extends AbstractRule {
        public String attributeId = "attribute";
    }
    

    【讨论】:

    • 是的,所以我希望它尽可能通用。虽然我当然可以这样做,但我不会遍历每个嵌套对象。相反,我只阅读顶级对象并期望我可以声明子类型并让它自动正确地实例化它(就像snakeyaml一样)。
    【解决方案2】:

    我必须这样做:

    objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator());
    

    现在,我的 JSON 看起来像这样(注意:这是一个不同的测试实体,但你明白了):

    {
    "name": "default",
    "ordering": "1",
    "rule": [
        "com.walterjwhite.email.organization.api.configuration.rule.GroupRule",
        {
            "criteriaType": "Should",
            "rules": ["java.util.HashSet",[[
                "com.walterjwhite.email.organization.api.configuration.rule.AttributeRule",
                {
                    "emailMessageField": ["com.walterjwhite.email.organization.api.configuration.rule.EmailMessageField", "Subject"],
                    "values": ["java.util.HashSet", [
                        "default"
                    ]],
                    "matchType": ["com.walterjwhite.email.organization.api.configuration.rule.MatchType","ContainsIgnoreCase"]
                }]]
            ]
        }
    ],
    "actionClassNames": ["java.util.ArrayList",[
        "com.walterjwhite.email.organization.plugins.count.CountAction",
        "com.walterjwhite.email.organization.plugins.index.IndexAction",
        "com.walterjwhite.email.organization.plugins.reply.MoveAction"
        ]
    ]
    

    }

    所以,我在@class 中看到的参考文档似乎不准确。我对添加所有这些额外信息并不满意,尤其是在不需要其中一些信息时 - java.util.ArrayList。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-22
      • 2014-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多