【问题标题】:Jackson Unmarshall custom object instead of LinkedHashMapJackson Unmarshall 自定义对象而不是 LinkedHashMap
【发布时间】:2015-10-18 14:35:45
【问题描述】:

我有一个 Java 对象结果

public class MetaData {
    private List<AttributeValue<String,Object>> properties
    private String name
    ...

    ... getters/setters ...
}

AttributeValue 类是一个通用的键值类。可能嵌套了不同的 AttributeValue。然后,(值)Object 将是另一个 AttributeValue,依此类推。

由于遗留原因,无法更改此对象的结构。

我有我的 JSON,我尝试将其映射到这个对象。 常规属性一切顺利。列表的第一级也填充了 AttributeValues。

问题在于对象。 Jackson 不知道如何解释这种嵌套行为,只是将其设为 LinkedHashMap。

我正在寻找一种方法来实现自定义行为,以告诉 Jackson 这必须是一个 AttributeValue 对象而不是 LinkedHashMap。

这就是我目前转换 JSON 的方式:

ObjectMapper om = new ObjectMapper();
MetaData metaData = om.readValue(jsonString, new TypeReference<MetaData>(){});

这是 JSON 示例。 (这是通过将现有的 MetaData 对象序列化为 JSON 来获得的,我可以完全控制这种语法)。

{
    "properties":[
        {
            "attribute":"creators",
            "value":[
                {
                    "attribute":"creator",
                    "value":"user1"
                },{
                    "attribute":"creator",
                    "value":"user2"
                }
            ]
        },{
            "attribute":"type",
            "value": "question"
        }
    ],
    "name":"example"
}

(顺便说一句:我已经尝试过使用 GSON,但是对象是 StringMap 并且问题是一样的。也欢迎使用 GSON 的解决方案)。

editUsing Jackson ObjectMapper with Generics to POJO instead of LinkedHashMap 中有来自 StaxMan 的评论: "LinkedHashMap 仅在缺少类型信息时返回(或者如果 Object.class 被定义为类型)。"

后者似乎是这里的问题。有没有办法可以覆盖它?

【问题讨论】:

  • 谢谢。是的,我做到了,但这不是我的问题的解决方案。 MetaData 对象已正确创建,并且有一个 AttributeValues 列表(在第一级)。问题出在第二层,Object 应该被另一个(嵌套的)AttributeValue 替换。
  • stackoverflow.com/questions/8903863/…StaxMan 中说:“LinkedHashMap 仅在缺少类型信息时返回 (或者如果 Object.class 被定义为类型) " 这似乎是原因,但我想覆盖它...
  • 你能举一个JSON解析的例子吗?看起来AttributeValue 有一个嵌套的 JSON 对象(即{}),并且因为 Jackson 没有关于嵌套对象的任何类型信息,所以通用反序列化器会启动。可以通过自定义序列化器解决这个问题,但它是更多的工作,所以这里有一个示例 JSON 会有所帮助。
  • 感谢@dhke,我在上面添加了一个示例 Json。从我读过的内容来看,我认为这确实是要走的路,但我真的不知道从哪里开始。

标签: java json jackson


【解决方案1】:

如果您可以控制序列化,请尝试在您的映射器上调用 enableDefaultTyping()

考虑这个例子:

Pair<Integer, Pair<Integer, Integer>> pair = new Pair<>(1, new Pair<>(1, 1));
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pair);
Pair result = mapper.readValue(str, Pair.class);

如果没有enableDefaultTyping(),我将拥有str = {"k":1,"v":{"k":1,"v":1}},它将反序列化为带有LinkedHashMapPair

但如果我在mapper 上使用enableDefaultTyping(),那么str = {"k":1,"v":["Pair",{"k":1,"v":1}]} 然后完美反序列化为Pair&lt;Integer, Pair&lt;...&gt;&gt;

【讨论】:

  • 谢谢@hotkey,我会试试的。但如果我理解正确,这将意味着我必须将我的 Java 类写入我的 JSON,这会将它们紧密耦合在一起?
  • @user3319803,是的,将类型信息包含到 JSON 中会将其绑定到某些类。但是绑定是可定制的:您可以更改 Jackson 的类型,例如,在您的类上使用 @JsonTypeInfo 并更改映射器的类型。即使您无法控制序列化,它有时也可以帮助您进行动态/泛型类型反序列化,例如当您使用某些 API 时。
  • @user3319803,顺便说一下,你可以看看this article作为介绍,虽然它是关于多态脱脂的。
  • 感谢@hotkey 的链接。似乎是一个很好的介绍,也是我的问题的潜在解决方案。
  • 我希望我的 JSON 是这样的:str = {"k":1,"v":{"k":1,"v":1}} 我的 JS 前端不应该知道后端的类。 @JsonTypeInfo 似乎允许大量自定义,但仍然保持这种耦合(如果我理解正确的话)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-05
  • 2012-07-08
  • 2014-04-17
  • 2021-10-23
  • 1970-01-01
  • 2012-02-12
  • 2017-04-29
相关资源
最近更新 更多