如何使用GSON反序列化不同对象的数组

4
我收到的JSON如下:
[
  {
    "albums" : [
      {"id":"0", "name":"name"},
      {"id":"1", "name":"name"}
    ],
    "name":"name"
  },
  {
    "tracks" : [
      {"id":"0", "name":"name", "duration":"3:30"},
      {"id":"1", "name":"name", "duration":"2:40"}
    ],
    "name":"name"
  },
  {
    "playlists" : [
      {"id":"0", "name":"name", "tracksCount":"3"},
      {"id":"1", "name":"name", "tracksCount":"40"}
    ],
    "name":"name"
  }
]

当然,我实现了Track、Album和Playlist类,这些类包含了所有的字段和类。
Tracks {
  String name;
  List<Track> tracks;
}
Albums {
  String name;
  List<Album> albums;
}
Playlists {
  String name;
  List<Playlist> playlists;
}

我正在尝试对其进行反序列化:

Gson gson = new Gson();
JsonResponse[] rez = gson.fromJson(str, JsonResponse[].class);

JsonResponse 是什么?

class JsonResponse {
  Albums albums;
  Tracks tracks;
  Playlists playlists;
}

但是我遇到了错误:
11-20 19:24:55.210: E/AndroidRuntime(5432): 致命异常:主线程 com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: 预期的是BEGIN_OBJECT但实际上是BEGIN_ARRAY,位于第1行第13列。 在ReflectiveTypeAdapterFactory$Adapter.read()方法处抛出异常, 该方法位于com.google.gson.internal.bind.ReflectiveTypeAdapterFactory下的176行。 其他类似的异常还包括: ReflectiveTypeAdapterFactory$1.read() - 位于com.google.gson.internal.bind.ReflectiveTypeAdapterFactory下的93行; TypeAdapterRuntimeTypeWrapper.read() - 位于com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper下的40行; ArrayTypeAdapter.read() - 位于com.google.gson.internal.bind.ArrayTypeAdapter下的72行; Gson.fromJson() - 位于com.google.gson.Gson下的717、768、803行; MyRunnable.run() - 位于android.os.ResultReceiver下的43行。 此外,异常栈中还有关于Handler、Looper等的信息。 Caused by: java.lang.IllegalStateException: 预期的是BEGIN_OBJECT但实际上是BEGIN_ARRAY,位于第1行第13列。 在JsonReader.beginObject()方法处抛出异常,该方法位于com.google.gson.stream.JsonReader下的374行。

注意:在json响应中可能会缺少某些项。例如:

[
  {
    "albums" : [
      {"id":"0", "name":"name"},
      {"id":"1", "name":"name"}
    ],
    "name":"name"
  }
 ]

那么问题是什么,我该如何反序列化这个JSON?

顺便说一句,我不能改变JSON。所以我需要一段代码来按照它的原样解析它。


我无法更改JSON。因此,我需要一段代码将其解析为原样。 - oleg.semen
希望你有Album、Track和Playlist类,只需在JsonResponse中进行更改,你的方法是正确的,除了JsonResonse类中的小错误。 - Asif Bhutto
5个回答

3
感谢大家的帮助!这是我的解决方案。
public class JsonResponse {
    public static class Item {
        String name;
    }

    public static class Tracks extends Item {
        List<Track> tracks;
    }

    public static class Albums extends Item {
        List<Album> albums;
    }

    public static class Playlists extends Item {
        List<Playlist> playlists;
    }

    public static class JsonResponseDeserialize implements JsonDeserializer<List<? extends Item>> {
        Gson gson = new Gson();
        @Override
        public List<? extends Item> deserialize(JsonElement el, Type type, JsonDeserializationContext context) throws JsonParseException {
            List<Item> ls = new ArrayList<Item>();
            JsonArray jarr = el.getAsJsonArray();
            for (JsonElement e : jarr) {
                Item i;
                if (e.getAsJsonObject().get("tracks") != null){
                    i = gson.lsomJson(e, Tracks.class);
                    if (i != null) {
                        ls.add(i);
                        continue;
                    }
                }
                if (e.getAsJsonObject().get("albums") != null){
                    i = gson.lsomJson(e, Albums.class);
                    if (i != null) {
                        ls.add(i);
                        continue;
                    }
                }
                if (e.getAsJsonObject().get("playlists") != null){
                    i = gson.lsomJson(e, Playlists.class);
                    if (i != null) {
                        ls.add(i);
                        continue;
                    }
                }
            }
            return ls;
        }
    }

    private Tracks _tracks;
    private Albums _albums;
    private Playlists _playlists;
}

反序列化:

private static List<? extends Item> getDatalsomJson(String jsonString) {
    Type type = new TypeToken<List<? extends JsonResponse.Item>>(){}.getType();
    GsonBuilder gb = new GsonBuilder();
    gb.registerTypeAdapter(type, new JsonResponse.JsonResponseDeserialize());
    Gson gson = gb.create();
    List<? extends Item> ls = gson.lsomJson(jsonString, type);
    return ls;
}

1
lsomJson 找不到。 - Moorthy

3
最近我使用了RuntimeTypeAdapterFactory来实现同样的目的,这是一个简单而干净的解决方案。它是一个开放的Gson集成(附加组件)。
请查看此帖子以查看并激活示例:https://jansipke.nl/serialize-and-deserialize-a-list-of-polymorphic-objects-with-gson/ 我直接从GitHub导入了原始代码到我的项目中(因为该类不直接属于Maven依赖项):
代码 https://raw.githubusercontent.com/google/gson/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java 希望有所帮助。

2

这样做

您的数据

    String json = "[{\"albums\":[{\"id\":\"0\",\"name\":\"name\"},{\"id\":\"1\",\"name\":\"name\"}],\"name\":\"name\"},{\"tracks\":[{\"id\":\"0\",\"name\":\"name\",\"duration\":\"3:30\"},{\"id\":\"1\",\"name\":\"name\",\"duration\":\"2:40\"}],\"name\":\"name\"},{\"playlists\":[{\"id\":\"0\",\"name\":\"name\",\"tracksCount\":\"3\"},{\"id\":\"1\",\"name\":\"name\",\"tracksCount\":\"40\"}],\"name\":\"name\"}]";

你的POJOs
class JsonResponse {
      ArrayList<Album> albums;
      ArrayList<Track> tracks;
      ArrayList<Playlist> playlists;
      String name;
    @Override
    public String toString() {
        return "JsonResponse [albums=" + albums + ", tracks=" + tracks
                + ", playlists=" + playlists + ", name=" + name + "]";
    }     
}



class Track{
    int id;
    String name;
    String duration;
    @Override
    public String toString() {
        return "Track [id=" + id + ", name=" + name + ", duration=" + duration
                + "]";
    }    
}

class Album{
    int id;
    String name;
    @Override
    public String toString() {
        return "Album [id=" + id + ", name=" + name + "]";
    }   
}

class Playlist{ 
    int id;
    String name;
    int tracksCount;
    @Override
    public String toString() {
        return "Playlist [id=" + id + ", name=" + name + ", tracksCount="
                + tracksCount + "]";
    }

}

这是反序列化后的数组。
   JsonParser parser = new JsonParser();
   JsonArray Jarray = parser.parse(json).getAsJsonArray();
   Gson gson = new Gson();
   for(JsonElement obj : Jarray )
   {
        JsonResponse jsonResponse = gson.fromJson( obj , JsonResponse.class);
        System.out.println(jsonResponse);
   }

0
你发布的JSON不显示JSONResponse对象数组,而是包含了Albums、Tracks和Playlists类型的JSON对象。如果你有如下内容,则会有所不同:
[
  {
     {
       "albums" : [
         {"id":"0", "name":"name"},
         {"id":"1", "name":"name"}
       ],
       "name":"name"
     },
     {
       "tracks" : [
         {"id":"0", "name":"name", "duration":"3:30"},
         {"id":"1", "name":"name", "duration":"2:40"}
       ],
       "name":"name"
     },
     {
       "playlists" : [
         {"id":"0", "name":"name", "tracksCount":"3"},
         {"id":"1", "name":"name", "tracksCount":"40"}
       ],
       "name":"name"
     }
   }
]

此外,如果您的对象变得过于复杂,请记住您可以实现自己的JSONDeserializer类,并在调用create()之前将其注册到GSONBuilder对象上。

我无法更改JSON。因此,我需要一段代码将其解析为原样。 - oleg.semen
我知道JSON结构不在您的控制范围内,但是您误解了您所拥有的内容:您没有一个JSONResponse对象数组,而是一个Playlists、Track等对象数组... 所以,没问题,您只需要实现自己的反序列化程序;这里有一个示例 - Miquel

0

实际上,您在JsonResponse类中犯了错误。

从您的json格式中可以清楚地看出它从一个数组开始,在JsonResponse类中,您只需组成单个对象而不是对象集合。如果您仔细查看Gson异常,会显示"BEGIN_OBJECT but was BEGIN_ARRAY" 。这意味着Gason有Album、Tracks和PlayList的数组,而不是Albums、Tracks和Playlists类的对象。

您只需要对JsonResponse类做一点小修改,如下所示:

private  List<Albums> albums;
private  List<Tracks> tracks;
private  List<Playlists> playlists;

JsonResponse类包含对象而不是列表/数组,因为除了列表/数组外还有一个名为“name”的字符串字段。它是Albums类的一个对象,其中包含List <Album> albums; 和String name;。 - oleg.semen
每个列表都包含其自身类型的对象,每个对象都有一个字符串字段名称,因为每个实例都有其自己的属性。 - Asif Bhutto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接