Sermilion
Sermilion

Reputation: 2049

Deserializing json element that can be either Array or Object at different times

Json that is returned by server has an element that is sometimes an empty array and other times an object. I wrote custom TypeAdapterFactory to best of my knowledge:

@Override
public T read(final JsonReader in) throws IOException {
    if (in.peek() == JsonToken.BEGIN_ARRAY) {
        return null;
    } else {
        return delegateTypeAdapter.read(in);
    }
}

But it still throws: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 652 path $.timetable

This is my Timetable class:

public final class Timetable implements Serializable{

private final Map<Integer, String> teachers;
private final Map<Integer, String> hours;
private final Map<Integer, String> rooms;
private final Map<Integer, String> groups;
private final Map<Integer, String> subjects;
private final Map<Integer, List<Map<String, String>>> entries;
}

So sometimes when timetable is empty json looks like this: "timetable": [] When it is not empty it is like this:

 "timetable": {
    "teachers": {
        "762": "sfsdfsdf",

    },
    "hours": {
        "1": "09:00",
    },
    "rooms": {
        "439": "sdfsdfsdf",
    },
    "subjects": {
        "738": "sdfsdfdsf",
    },
    "entries": {
        "10": [
            {
                "week": "1",
                "day": "6",
                "date": "2017-03-01",
                "hour": "1",
                "type": "0",
                "course": "3844",
                "teacher": "59502",
                "room": "640",
                "p": "-1",
                "table": "1447"
            },
            {
                "week": "1",
                "day": "6",
                "date": "2017-03-01",
                "hour": "2",
                "type": "0",
                "course": "4047",
                "teacher": "50792",
                "room": "799",
                "p": "-1",
                "table": "1447"
            }
        ]
    }

Upvotes: 1

Views: 258

Answers (1)

Jameido
Jameido

Reputation: 1354

I had a problem similar to yours (I was getting an empty string when the array had no elements) so i created a generic GsonArrayDeserializer, this modified version for an Ojbect sould work for you

public class GsonObjectDeserializer<T> implements JsonDeserializer<T> {

@Override
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
    Gson gson = new Gson();
    T result = null;
    if (json.isJsonObject()) {
        result = gson.fromJson(json.getAsJsonObject(), typeOfT);
    }

}

}

And using it like this

Gson gson = new GsonBuilder()
.registerTypeAdapter(Timetable.class , new GsonObjectDeserializer<Timetable>(Timetable.class))
.create();

EXTRA:

To use it with Retrofit2 add it like this

final Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constants.URL_BASE)
                ...... //other paramaeters
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();

It's well explained here

Upvotes: 2

Related Questions