Java 使用GSON解析JSON时,对象有时包含列表,有时包含对象

Java 使用GSON解析JSON时,对象有时包含列表,有时包含对象,java,gson,Java,Gson,我使用的API有时包含子对象列表: { 'obj' : { children: [ {id: "1"}, {id: "2"} ] } } 我可以解析这个,没问题。但如果只有一个子项,则不会将其作为列表返回: { 'obj' : { children: {id: "1"} } } 我的解析器需要一个列表,然后它就中断了。有人对如何处理这个问题有什么建议吗?对于Gson,我知道如何处理这种情况的唯一方法是使用自定义反序列化程序。例如: // outputs: // [Container: obj

我使用的API有时包含子对象列表:

{ 'obj' : { children: [ {id: "1"}, {id: "2"} ] } }
我可以解析这个,没问题。但如果只有一个子项,则不会将其作为列表返回:

{ 'obj' : { children: {id: "1"} } }

我的解析器需要一个列表,然后它就中断了。有人对如何处理这个问题有什么建议吗?

对于Gson,我知道如何处理这种情况的唯一方法是使用自定义反序列化程序。例如:

// outputs:
// [Container: obj=[ChildContainer: children=[[Child: id=1], [Child: id=2]]]]
// [Container: obj=[ChildContainer: children=[[Child: id=1]]]]

public class Foo
{
  static String json1 = "{\"obj\":{\"children\":[{\"id\":\"1\"},{\"id\":\"2\"}]}}";
  static String json2 = "{\"obj\":{\"children\":{\"id\":\"1\"}}}";

  public static void main(String[] args)
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
    gsonBuilder.registerTypeAdapter(Child[].class, new ChildrenDeserializer());
    Gson gson = gsonBuilder.create();
    Container container1 = gson.fromJson(json1, Container.class);
    System.out.println(container1);

    Container container2 = gson.fromJson(json2, Container.class);
    System.out.println(container2);
  }
}

class Container
{
  ChildContainer obj;

  @Override
  public String toString()
  {
    return String.format("[Container: obj=%1$s]", obj);
  }
}

class ChildContainer
{
  Child[] children;

  @Override
  public String toString()
  {
    return String.format("[ChildContainer: children=%1$s]", Arrays.toString(children));
  }
}

class Child
{
  String id;

  @Override
  public String toString()
  {
    return String.format("[Child: id=%1$s]", id);
  }
}

class ChildrenDeserializer implements JsonDeserializer<Child[]>
{
  @Override
  public Child[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {
    if (json instanceof JsonArray)
    {
      return new Gson().fromJson(json, Child[].class);
    }
    Child child = context.deserialize(json, Child.class);
    return new Child[] { child };
  }
}
//输出:
//[Container:obj=[ChildContainer:children=[[Child:id=1],[Child:id=2]]
//[Container:obj=[ChildContainer:children=[[Child:id=1]]]
公开课Foo
{
静态字符串json1=“{\'obj\':{\'children\':[{\'id\':\'1\'},{\'id\':\'2\'}]}”;
静态字符串json2=“{\'obj\':{\'children\':{\'id\':\'1\'}}”;
公共静态void main(字符串[]args)
{
GsonBuilder GsonBuilder=新的GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_,带下划线);
gsonBuilder.registerTypeAdapter(子[].class,新的ChildRenderSerializer());
Gson-Gson=gsonBuilder.create();
Container container1=gson.fromJson(json1,Container.class);
系统输出打印LN(容器1);
Container container2=gson.fromJson(json2,Container.class);
系统输出打印LN(集装箱2);
}
}
类容器
{
儿童容器obj;
@凌驾
公共字符串toString()
{
返回String.format(“[Container:obj=%1$s]”,obj);
}
}
类子容器
{
儿童[]儿童;
@凌驾
公共字符串toString()
{
返回String.format(“[ChildContainer:children=%1$s]”,array.toString(children));
}
}
班童
{
字符串id;
@凌驾
公共字符串toString()
{
返回String.format(“[Child:id=%1$s]”,id);
}
}
类ChildRenderSerializer实现JsonDeserializer
{
@凌驾
公共子[]反序列化(JsonElement json,类型typeOfT,JsonDeserializationContext)
抛出JsonParseException
{
if(JsonArray的json实例)
{
返回新的Gson().fromJson(json,Child[].class);
}
Child=context.deserialize(json,Child.class);
返回新的子[]{Child};
}
}

我不认为这是Gson的问题,但不管是什么东西,首先都要创建数据。在您展示的JSON示例中,一种情况下,children是一个列表,另一种情况下,它是一个对象。在自定义反序列化程序中,不使用新的Gson对象来处理子[],只需迭代JsonArray,并使用现有的JSONESerializationContext逐个反序列化每个子对象,将结果作为组件添加到新的子[],然后由自定义反序列化程序返回。这将具有重用已配置的Gson反序列化器的优点。在本例中,没有必要在GsonBuilder上设置FieldNamingPolicy。这只是我没有删除的复制粘贴代码留下的东西。Jackson的解决方案更简单,因为它有一个内置功能来处理这种特殊情况。只需通过调用mapper.getDeserializationConfig().set(Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY,true)将ObjectMapper配置为接受_SINGLE_VALUE_AS_ARRAY;然后就不需要其他自定义反序列化了。我上面发布的两个JSON输入示例都将用一行代码反序列化。Container c=mapper.readValue(json,Container.class);(前提是Java数据结构中的字段全部公开,或按中所述公开)