【问题标题】:Using GSON to parse array with multiple types使用 GSON 解析多种类型的数组
【发布时间】:2011-03-21 12:54:06
【问题描述】:

我希望使用 GSON 来解析以下 json:

[
    [
        "hello",
        1,
        [2]
    ],
    [
        "world",
        3,
        [2]
    ]
]

所以,这是 1 个数组,包含 2 个数组。 2个内部数组本身就是数组,由String、int、数组类型组成。

我不确定如何使用 Java 类对具有 3 种不同类型(字符串、整数、数组)的数组进行建模。我开始:

// String json just contains the aforementioned json string.

ArrayList<ArrayList<XXX>> data = new ArrayList<ArrayList<XXX>>();

Type arrayListType = new TypeToken<ArrayList<ArrayList<XXX>>>(){}.getType();

data = gson.fromJson(json, arrayListType);

但是“XXX”应该在哪里?我认为它应该是一个数组,但它应该是一个具有 3 种不同数据类型的数组。那么如何使用 Java 来建模呢?

有什么可以帮忙的吗? 谢谢。

【问题讨论】:

标签: java json gson


【解决方案1】:

Gson 对将一些单组件数组反序列化为非数组类型有特殊处理。例如,int data = gson.fromJson("[3]", int.class); 会将 int 值 3 分配给 data。

当然,不需要将单组件数组反序列化为非数组类型。比如前面的例子可以反序列化为int[] data = gson.fromJson("[3]", int[].class);

当被问到时,Gson 也经常将非字符串值反序列化为字符串。将此应用于第一个示例,String data = gson.fromJson("[3]", String.class); 也同样有效。

请注意,告诉 Gson 将第一个示例反序列化为 Object 类型是行不通的。 Object data = gson.fromJson("[3]", Object.class); 导致解析异常,抱怨 [3] 不是原语。

应用于上面原始问题中的示例,如果将所有值都视为字符串是可以接受的,那么反序列化就变得简单了。

// output:
// hello 1 2 
// world 3 2 

public class Foo
{
  static String jsonInput = 
    "[" +
      "[\"hello\",1,[2]]," +
      "[\"world\",3,[2]]" +
    "]";

  public static void main(String[] args)
  {
    Gson gson = new Gson();
    String[][] data = gson.fromJson(jsonInput, String[][].class);
    for (String[] data2 : data)
    {
      for (String data3 : data2)
      {
        System.out.print(data3);
        System.out.print(" ");
      }
      System.out.println();
    }
  }
}

不幸的是,对于 Gson,我无法找到一种简单的反序列化方法,该方法允许“更好”地绑定到数组中更具体和混合的类型,因为 Java 不提供定义混合类型的语法类型数组。例如,原始问题中集合的首选类型可能是List&lt;List&lt;String, int, List&lt;int&gt;&gt;&gt;,但这不可能在 Java 中定义。所以,你必须满足于List&lt;List&lt;String&gt;&gt; (or String[][]),或者转向更“手动”解析的方法。

(是的,Java 允许 List&lt;List&lt;Object&gt;&gt; 的类型声明,但 Object 不是一个足够具体的类型来有意义地反序列化。此外,如所讨论的,尝试将 [3] 反序列化为 Object 会导致解析异常。 )


小更新:我最近不得不反序列化一些草率的 JSON,其中包含与原始问题中的结构不太相似的结构。我最终只是使用自定义反序列化器从凌乱的 JSON 数组中创建一个对象。类似于下面的例子。

// output: 
// [{MyThreeThings: first=hello, second=1, third=[2]}, 
//  {MyThreeThings: first=world, second=3, third=[4, 5]}]

import java.lang.reflect.Type;
import java.util.Arrays;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

public class FooToo
{
  static String jsonInput =
      "[" +
          "[\"hello\",1,[2]]," +
          "[\"world\",3,[4,5]]" +
      "]";

  public static void main(String[] args)
  {
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(MyThreeThings.class, new MyThreeThingsDeserializer());
    Gson gson = gsonBuilder.create();
    MyThreeThings[] things = gson.fromJson(jsonInput, MyThreeThings[].class);
    System.out.println(Arrays.toString(things));
  }
}

class MyThreeThings
{
  String first;
  int second;
  int[] third;

  MyThreeThings(String first, int second, int[] third)
  {
    this.first = first;
    this.second = second;
    this.third = third;
  }

  @Override
  public String toString()
  {
    return String.format(
        "{MyThreeThings: first=%s, second=%d, third=%s}",
        first, second, Arrays.toString(third));
  }
}

class MyThreeThingsDeserializer implements JsonDeserializer<MyThreeThings>
{
  @Override
  public MyThreeThings deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException
  {
    JsonArray jsonArray = json.getAsJsonArray();
    String first = jsonArray.get(0).getAsString();
    int second = jsonArray.get(1).getAsInt();
    JsonArray jsonArray2 = jsonArray.get(2).getAsJsonArray();
    int length = jsonArray2.size();
    int[] third = new int[length];
    for (int i = 0; i < length; i++)
    {
      int n = jsonArray2.get(i).getAsInt();
      third[i] = n;
    }
    return new MyThreeThings(first, second, third);
  }
}

Gson 用户指南确实涵盖了处理混合类型集合的反序列化,其中包含与 the "Serializing and Deserializing Collection with Objects of Arbitrary Types" section 中类似的示例。

【讨论】:

    【解决方案2】:

    首先,我认为您在上面的示例中可能有误。至少可以说,由三个不同组成的数组是一种非常不寻常的方法。可能您的 json 结构是一个包含元组的数组。然后这些元组包含一个数组。

    喜欢:

    [
    {
        "hello",
        1,
        [2]
    },
    {
        "world",
        3,
        [2]
    }
    ]
    

    XXX 应该是一个包含以下内容的对象:

    一个字符串

    一个整数(或整数)

    (我猜)一个整数数组。

    然后你创建一个包含这些对象的数组并将 json 解析到其中。

    但是,您的 json 格式似乎真的很糟糕,因为所有成员都应该被命名,比如

    [
    {
        "str":"hello",
        "intVal":1,
        "intArr":[2]
    },
    {
        "str":"world",
        "intVal":3,
        "intArr":[2]
    }
    ]
    

    另一方面,如果 JSON 看起来确实如您所描述的那样,则您必须制作简单明了的 Object 数组,然后在您从数据结构中读取它们时对其进行转换。

    【讨论】:

    • 这也是我的想法...如果 JSON 格式为:{ "str":"hello", "intVal":1, "intArr":[2] },然后我可以简单地创建自己的类,对这些数据进行建模。不幸的是,数据确实与我发布的一样......因此我的问题和这篇文章:) 我会尝试你的建议,看看它是否有效。谢谢你的回复。
    • 好的,我不确定这种转换方法是否有效。您是否建议我做类似的事情:ArrayList&lt;ArrayList&lt;Object&gt;&gt; data = new ArrayList&lt;ArrayList&lt;Object&gt;&gt;(); Type arrayListType = new TypeToken&lt;ArrayList&lt;ArrayList&lt;Object&gt;&gt;&gt;(){}.getType(); data = gson.fromJson(json, arrayListType); 我明白这可能如何存储字符串或 int,但数组中的第 3 项是一个数组,如果这个数组包含一个 JSON 对象 { } 那么我将如何建模这个?
    • 我收到以下错误:com.google.gson.JsonParseException: Type information is unavailable, and the target is not a primitive: [2] 所以第三项有问题... intArr
    • 他无法控制数据的格式。这就是他得到的,他必须处理它。至少将您的答案(转换)放在回复的顶部,如果您必须继续说明数据的结构有多糟糕,可以,但请放在您的答案之后。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-11
    • 1970-01-01
    • 2018-12-11
    • 2013-08-27
    • 1970-01-01
    相关资源
    最近更新 更多