开发者

Using GSON to parse array with multiple types

I wish to use GSON to parse the following json:

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

So, that's 1 array, containing 2 arrays. The 2 inner arrays are themselves arrays, comprised of String, int, array types.

I'm unsure how I can using Java classes to model the array which has 3 different types (String, int, array). I start with:

// String json just contains the aforementioned json string.

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

Type arrayListType = new TypeToken<ArrayList<ArrayList<XXX>>>(){开发者_Python百科}.getType();

data = gson.fromJson(json, arrayListType);

But what should be where the 'XXX' are? I think it should be an array, but it should be an array with 3 different data types. So how can I use Java to model this?

Can any help? Thank you.


Gson has special handling for deserializing some single-component arrays into a non-array type. For example, int data = gson.fromJson("[3]", int.class); would assign the int value 3 to data.

Of course, deserializing a single-component array into a non-array type is not required. For example, the previous example could be deserialized as int[] data = gson.fromJson("[3]", int[].class);.

Gson will also often deserialize a non-String value into a String, when asked. Applying this to the first example, String data = gson.fromJson("[3]", String.class); works just as well.

Note that it does not work to tell Gson to deserialize the first example as type Object. Object data = gson.fromJson("[3]", Object.class); results in a parse exception complaining that [3] is not a primitive.

Applied to the example in the original question above, if it's acceptable to treat all of the values as Strings, then deserialization becomes simple.

// 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();
    }
  }
}

Unfortunately, with Gson I've not been able to figure out a simple deserialization approach that would allow for "better" binding to more specific and mixed types in an array, since Java doesn't provide a syntax for defining a mixed type array. For example, the preferred type of the collection in the original question might be List<List<String, int, List<int>>>, but that's not possible to define in Java. So, you gotta be content with List<List<String>> (or String[][]), or turn to an approach with more "manual" parsing.

(Yes, Java allows a type declaration of List<List<Object>>, but Object is not a specific enough type to meaningfully deserialize to. Also, as discussed, attempting to deserialize [3] to Object results in a parse exception.)


Small Update: I recently had to deserialize some sloppy JSON that included a structure not too dissimilar from that in the original question. I ended up just using a custom deserializer to create a object from the messy JSON array. Similar to the following example.

// 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);
  }
}

The Gson user guide does cover handling deserialization of collections of mixed types with a similar example as this in the "Serializing and Deserializing Collection with Objects of Arbitrary Types" section.


First, I think you may be mistaken in your example above. An Array consisting of three different is a very unusual approach, to say the least. Probably your json structure is an array, containing tuples. These tuples then include an array.

Like:

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

XXX should be an object containing:

A String

An int (or Integer)

An Array of (I guess) ints.

Then you make an array of these objects and parse the json into it.

However, your json seems really badly formed, since all members should be named, like

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

If, on the other hand, the JSON really looks the way you describe it, you would have to make arrays of Object, plain and simple, and then cast them when you read them from your data structure.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜