我有一个json数据结构,可以是(忽略所有其他json):
"warnings": [
{
... some json ...
},
{
... some json ...
}
]
或者它也可能是
"warnings": {
... some json ...
}
杰克逊的以下代码适用于第一种情况:
@JsonProperty("warnings")
private List<Warning> warnings;
但它不会为第二个工作。使用jackson库进行映射的正确做法是什么(如果可能的话,+注释),这样它将以json列表或json对象的形式映射json,但两者都映射到同一个字段。这在从外部系统接收数据时似乎是一个相当普遍的问题,虽然杰克逊没有开箱即用(在我看来它应该是因为列表和单个对象之间的实际差别很小)
答案 0 :(得分:1)
Jackson依赖于属性或字段的类型来确定如何反序列化某些JSON。没有类型可以同时充当List<Warning>
和Warning
。 (好吧,有Object
但这并没有暗示杰克逊如何反序列化到特定的目标类型。)
一个选项是将字段设置为Object
类型,让Jackson在一个案例(单个对象)或LinkedHashMap
List
中生成LinkedHashMap
(数组对象)。或者,您可以为该字段提供自己的反序列化器,并生成Warning
对象或List<Warning>
,具体取决于您找到的JSON。
另一种方法是使用ObjectNode
而不是POJO。然后,您可以在浏览时检查JsonNode
get(String)
的类型。
在任何一种情况下,您都必须经常检查instanceof List
或检查JsonNode#isArray()
。
答案 1 :(得分:0)
您可以通过为包含gson上下文的warning属性的类型提供反序列化器来使用gson执行此操作。 假设类TypeOfRootElement作为容器类,类WarningType用于警告,请在反序列化器中执行以下操作:
public TypeOfRootElement deserialize(final JsonElement json, final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
TypeOfRootElement result=new ...;
JsonObject jsonRoot=json.getAsJsonObject();
final JsonElement jsonWarningsElement = root.get("warnings");
List<WarningType> warnings=null;
if (jsonWarningsElement.isJsonArray())
{
warnings=context.deserialize(jsonWarningsElement, WarningType.class);
}
else
{
warnings=Collections.singletonList(context.deserialize(jsonWarningsElement,
WarningsType.class));
}
return result;
}
答案 2 :(得分:0)
我实际上比所有这些解决方案更简单地解决了这个问题。虽然它比我预期的更痛苦(由于杰克逊类路径解析问题)。
我将jackson的库版本从1.9.2升级到2.4.1,并将Warning warning
的类型更改为List<Warning>
。看来jackson 2.4.1在执行反序列化时会自动将单个对象转换为列表类型 - 方便!
我的类路径问题突出了虽然脆弱的单片应用程序依赖于核心相同的库,并且将单个应用程序拆分为多个较小的应用程序以帮助升级库可能更好。