Използване на GSON за анализиране на масив с множество типове

Искам да използвам GSON за анализ на следния json:

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

И така, това е 1 масив, съдържащ 2 масива. Самите два вътрешни масива са масиви, състоящи се от типове String, int, array.

Не съм сигурен как мога да използвам Java класове, за да моделирам масива, който има 3 различни типа (String, int, array). започвам с:

// 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, за да моделирам това?

Може ли някаква помощ? Благодаря ти.


person Fofx    schedule 21.03.2011    source източник
comment
Кодът е точно такъв, какъвто го получавам от сървъра...за съжаление не мога да променя данните, които получавам. Разбира се, това не прави JSON данните правилни. :P   -  person Fofx    schedule 21.03.2011
comment
Възможен дубликат на Gson десериализира JSON масив с множество типове обекти   -  person ed22    schedule 12.09.2017
comment
Това е странен, но валиден Json..   -  person Leo Droidcoder    schedule 18.04.2018


Отговори (2)


Gson има специална обработка за десериализация на някои еднокомпонентни масиви в тип без масив. Например int data = gson.fromJson("[3]", int.class); ще присвои int стойност 3 на данни.

Разбира се, не се изисква десериализация на еднокомпонентен масив в тип без масив. Например, предишният пример може да бъде десериализиран като int[] data = gson.fromJson("[3]", int[].class);.

Gson също така често ще десериализира стойност, която не е String, в String, когато бъде попитана. Прилагайки това към първия пример, 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<List<String, int, List<int>>>, но това не е възможно да се дефинира в Java. Така че трябва да се задоволите с List<List<String>> (or String[][]) или да се обърнете към подход с по-„ръчно“ анализиране.

(Да, Java позволява декларация на тип на List<List<Object>>, но 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 обхваща обработката на десериализация на колекции от смесени типове с подобен пример като този в раздела "Сериализиране и десериализиране на колекция с обекти от произволни типове".

person Programmer Bruce    schedule 02.06.2011

Първо, мисля, че може да грешите в примера си по-горе. Масив, състоящ се от три различни, е най-малкото много необичаен подход. Вероятно вашата json структура е масив, съдържащ кортежи. След това тези кортежи включват масив.

Като:

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

XXX трябва да бъде обект, съдържащ:

Струна

Int (или Integer)

Масив от (предполагам) int.

След това правите масив от тези обекти и анализирате json в него.

Вашият json обаче изглежда наистина зле оформен, тъй като всички членове трябва да бъдат именувани, като

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

Ако, от друга страна, JSON наистина изглежда така, както го описвате, ще трябва да направите масиви от обекти, ясни и прости, и след това да ги преобразувате, когато ги прочетете от вашата структура от данни.

person uvesten    schedule 21.03.2011
comment
Точно това е и моето мислене... че ако JSON беше във формат: { str:hello, intVal:1, intArr:[2] }, тогава бих могъл просто да създам свой собствен клас, който моделира тези данни. За съжаление данните наистина са такива, каквито публикувах... оттук и моят проблем и тази публикация :) Ще опитам вашето предложение и ще видя дали работи. Благодаря ви за отговора. - person Fofx; 21.03.2011
comment
Добре, не съм сигурен, че този подход за кастинг ще проработи. Предлагате ли да направя нещо като: ArrayList<ArrayList<Object>> data = new ArrayList<ArrayList<Object>>(); Type arrayListType = new TypeToken<ArrayList<ArrayList<Object>>>(){}.getType(); data = gson.fromJson(json, arrayListType); Разбирам как това може да работи за съхраняване на String или int, но 3-ти елемент в масива е масив и ако този масив съдържа JSON обект { }, тогава как бих моделирал това? - person Fofx; 21.03.2011
comment
Получавам следната грешка: com.google.gson.JsonParseException: Type information is unavailable, and the target is not a primitive: [2] Значи има проблем с третия елемент... intArr - person Fofx; 21.03.2011