Reputation: 3061
I receive JSON like this
[
{
"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"
}
]
Of course I implemented classes Track, Album and Playlist which contains all the fields and classes
Tracks {
String name;
List<Track> tracks;
}
Albums {
String name;
List<Album> albums;
}
Playlists {
String name;
List<Playlist> playlists;
}
I'm trying to deserialize it with:
Gson gson = new Gson();
JsonResponse[] rez = gson.fromJson(str, JsonResponse[].class);
where JsonResponse is
class JsonResponse {
Albums albums;
Tracks tracks;
Playlists playlists;
}
But I get the error:
11-20 19:24:55.210: E/AndroidRuntime(5432): FATAL EXCEPTION: main 11-20 19:24:55.210: E/AndroidRuntime(5432): com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 13 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:72) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.Gson.fromJson(Gson.java:803) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.Gson.fromJson(Gson.java:768) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.Gson.fromJson(Gson.java:717) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.Gson.fromJson(Gson.java:689) 11-20 19:24:55.210: 11-20 19:24:55.210: E/AndroidRuntime(5432): at android.os.ResultReceiver$MyRunnable.run(ResultReceiver.java:43) 11-20 19:24:55.210: E/AndroidRuntime(5432): at android.os.Handler.handleCallback(Handler.java:587) 11-20 19:24:55.210: E/AndroidRuntime(5432): at android.os.Handler.dispatchMessage(Handler.java:92) 11-20 19:24:55.210: E/AndroidRuntime(5432): at android.os.Looper.loop(Looper.java:130) 11-20 19:24:55.210: E/AndroidRuntime(5432): at android.app.ActivityThread.main(ActivityThread.java:3687) 11-20 19:24:55.210: E/AndroidRuntime(5432): at java.lang.reflect.Method.invokeNative(Native Method) 11-20 19:24:55.210: E/AndroidRuntime(5432): at java.lang.reflect.Method.invoke(Method.java:507) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625) 11-20 19:24:55.210: E/AndroidRuntime(5432): at dalvik.system.NativeStart.main(Native Method) 11-20 19:24:55.210: E/AndroidRuntime(5432): Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 13 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:374) 11-20 19:24:55.210: E/AndroidRuntime(5432): at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:165) 11-20 19:24:55.210: E/AndroidRuntime(5432): ... 21 more
P.S. Some Items in json response might be missed. For example
[
{
"albums" : [
{"id":"0", "name":"name"},
{"id":"1", "name":"name"}
],
"name":"name"
}
]
So what is the problem and how can I deserialize this JSON?
BTW I can't change JSON. So I need a code that parse it as it is.
Upvotes: 4
Views: 5470
Reputation: 693
Recently I used RuntimeTypeAdapterFactory for the same purpose, and it is easy an clean solution. It is a open Gson integration (extra)
Check this post to see and active example https://jansipke.nl/serialize-and-deserialize-a-list-of-polymorphic-objects-with-gson/ I imported the raw code from github directly to my project (because the class not owns to the maven dependency directly):
hope Helps
Upvotes: 3
Reputation: 3061
Thanks everybody for help! Here is my solution.
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;
}
Deserialization:
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;
}
Upvotes: 3
Reputation: 3994
Actually you did mistake in JsonResponse class.
Its clear form your json format that its start from an array , and In JsonResponse class you just compose single object not the collection of object . If you look carefully to Gson exception as
"BEGIN_OBJECT but was BEGIN_ARRAY
". This mean Gason has array of Album,Tracks and PlayList not the object of Albums,Tracks and Playlists class.
Just you need a little change in JsonResponse class as below
private List<Albums> albums;
private List<Tracks> tracks;
private List<Playlists> playlists;
Upvotes: 0
Reputation: 26084
do like this
Your data
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\"}]";
Your 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 + "]";
}
}
here the deserialized array.
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);
}
Upvotes: 2
Reputation: 15675
The JSON you have posted does not show an array of JSONResponse objects, instead, it contains JSON Objects of the types Albums, Tracks and Playlists. It would be different if you had this instead:
[
{
{
"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"
}
}
]
Also, if your objects end up being too complicated, remember you can always implement your own JSONDeserializer class and register it at the GSONBuilder object right before you call create() on it.
Upvotes: 0