Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何将json对象序列化为列表或将json列表序列化为对象列表?_Java_Json_Jackson - Fatal编程技术网

Java 如何将json对象序列化为列表或将json列表序列化为对象列表?

Java 如何将json对象序列化为列表或将json列表序列化为对象列表?,java,json,jackson,Java,Json,Jackson,我有一个json数据结构,可以是(忽略所有其他json): 也可能是 "warnings": { ... some json ... } jackson中的以下代码适用于第一种情况: @JsonProperty("warnings") private List<Warning> warnings; @JsonProperty(“警告”) 私人名单警告; 但第二次就不行了。使用jackson库(+注释,如果可能)进行映射的正确做法是什么,这样它可以将json以json列表

我有一个json数据结构,可以是(忽略所有其他json):

也可能是

"warnings": {
    ... some json ...
}
jackson中的以下代码适用于第一种情况:

@JsonProperty("warnings")
private List<Warning> warnings;
@JsonProperty(“警告”)
私人名单警告;

但第二次就不行了。使用jackson库(+注释,如果可能)进行映射的正确做法是什么,这样它可以将json以json列表或json对象的形式映射到同一字段。当从外部系统接收数据时,这似乎是一个相当常见的问题,尽管Jackson并没有开箱即用地处理数据(在我看来应该是这样的,因为列表和单个对象之间的实际差异很小).

Jackson依靠属性或字段的类型来确定如何反序列化某些JSON。没有可以同时充当
列表
警告
的类型。(这里有
对象
,但这并没有提示Jackson如何反序列化到特定的目标类型。)

一个选项是将字段设置为type
Object
,并让Jackson在一种情况下生成一个
LinkedHashMap
(单个对象)或
LinkedHashMap
(对象数组)的
列表。或者,您可以为该字段提供自己的反序列化程序,并根据找到的JSON生成一个
警告
对象或
列表

另一种方法是使用
ObjectNode
而不是POJO。然后,您可以在遍历时使用
get(String)
检查返回的
JsonNode
的类型


在任何一种情况下,您都必须不断检查列表的实例是否为
instanceof
,或者检查
JsonNode#isArray()

您可以通过向gson上下文提供包含警告属性的类型的反序列化程序来使用gson实现这一点。 假设RootElement类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;
}
RootElement反序列化的公共类型(最终JsonElement json,最终类型typeOfT,
最终JsonDeserializationContext)抛出JsonParseException{
RootElement结果的类型=新。。。;
JsonObject jsonRoot=json.getAsJsonObject();
final JsonElement jsonWarningsElement=root.get(“警告”);
列表警告=空;
if(jsonWarningElement.isJsonArray())
{
warnings=context.deserialize(JSONWarningElement,WarningType.class);
}
其他的
{
warnings=Collections.singletonList(context.deserialize)(jsonWarningsElement,
警告类型(class));
}
返回结果;
}

我解决这个问题实际上比所有这些解决方案加在一起更简单。虽然这比我预期的要痛苦一些(由于jackson类路径解决问题)

我将jackson的库版本从1.9.2升级到2.4.1,并将
警告
的类型更改为
列表
。在执行反序列化时,jackson 2.4.1似乎会自动将单个对象强制转换为列表类型-handy


我的类路径问题强调了单片应用程序的脆弱性,它们的核心依赖于相同的库,因此最好将单片应用程序拆分为多个较小的应用程序,以帮助升级库

我认为正确的做法是:如果它是一个列表,请确保它始终是一个列表(即使该列表只有一个条目)。列表和单个对象之间的实际差异非常小。最好将其建模为一个带有JSON中一个条目的列表。非常不幸的是,您的提供者生成了这样的JSON。Jackson中没有内置的功能来实现这一点。感谢您的回复@T.J.Crowder,但不幸的是,我无法改变这一点。我可以通知另一个团队他们的数据结构不正确(需要更改),但实际上他们不会很快更改。使用非Jacksonesque解析器将其解析为映射和列表,然后查询结构以查看“warnings”是什么对象类型。@Dropkick:啊,这一点都不好玩。无论如何,我都会和他们一起提出来,希望他们至少不会再犯这个错误……:-)谢谢这听起来很合理,我试试看。我不想尝试第二种选择,因为在ObjectNode上执行处理是痛苦的(我们经常这样做,在这种情况下我希望避免这样做)。抱歉,我没有在gson中要求它-需要另一个库/依赖项或重新编写所有其他代码以适应新库,因此我无法真正使用此建议-感谢您花费时间。您能给出完整的示例吗?我无法复制它。@SotiriosDelimanolis在上面的json示例中,完整示例作为对象和列表应该足够了。不过,您需要使用1.9.2 Jackson库版本。我升级到使用com.fasterxml.jackson.core:jackson-databind:2.4.1版本,而不是旧的库。回想起来,我不确定为什么会否决此解决方案,因为升级到支持将对象或列表json自动映射到list.class的新库版本不是无效答案。我希望您证明jackson 2.4.1在使用可复制的例子,因为它不适合我。
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;
}