Пользовательский десериализатор JSON с использованием Gson

У меня проблема с разбором ответа JSON с использованием Gson.

Строка JSON:

response: [
  2, {
    owner_id: 23972237,
    album_id: 25487692,
    title: 'album not new'
  }, {
    owner_id: 23972237,
    album_id: 25486631,
    title: 'фыв'
  }
]

У меня есть эти 2 класса:

public class VkAudioAlbumsResponse {
    public ArrayList<VkAudioAlbum> response;
    public VkError error;
}

public class VkAudioAlbum {
    public int owner_id;
    public int album_id;
    public String title;
}

Но у меня есть Исключение, когда разбирайте это с помощью Gson. Я знаю, это потому, что первый элемент массива ответа не является объектом, а целым.

Итак, вопрос в том, могу ли я как-то его решить?

Ответ 1

Вам нужно написать настраиваемый десериализатор. Я бы сделал что-то вроде этого:

Сначала вам нужно включить новый класс, кроме 2, который у вас уже есть:

public class Response {
    public VkAudioAlbumsResponse response;
}

И тогда вам нужен пользовательский десериализатор, что-то похожее на это:

private class VkAudioAlbumsResponseDeserializer 
    implements JsonDeserializer<VkAudioAlbumsResponse> {

  @Override
  public VkAudioAlbumsResponse deserialize(JsonElement json, Type type,
        JsonDeserializationContext context) throws JsonParseException {

    JsonArray jArray = (JsonArray) json;

    int firstInteger = jArray.get(0); //ignore the 1st int

    VkAudioAlbumsResponse vkAudioAlbumsResponse = new VkAudioAlbumsResponse();

    for (int i=1; i<jArray.size(); i++) {
      JsonObject jObject = (JsonObject) jArray.get(i);
      //assuming you have the suitable constructor...
      VkAudioAlbum album = new VkAudioAlbum(jObject.get("owner_id").getAsInt(), 
                                            jObject.get("album_id").getAsInt(), 
                                            jObject.get("title").getAsString());
      vkAudioAlbumsResponse.getResponse().add(album);
    }

    return vkAudioAlbumsResponse;
  }  
}

Затем вам нужно десериализовать свой JSON, как:

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(VkAudioAlbumsResponse.class, new VkAudioAlbumsResponseDeserializer());
Gson gson = gsonBuilder.create();
Response response = gson.fromJson(jsonString, Response.class);

При таком подходе, когда Gson пытается десериализовать JSON в класс Response, он обнаруживает, что в этом классе есть атрибут Response, который соответствует имени в ответе JSON, поэтому он продолжает разбор.

Затем он понимает, что этот атрибут имеет тип VkAudioAlbumsResponse, поэтому он использует настраиваемый десериализатор, который вы создали для его синтаксического анализа, который обрабатывает оставшуюся часть ответа JSON и возвращает объект VkAudioAlbumsResponse.

Примечание. Код в десериализаторе довольно прост, поэтому, я думаю, вам не составит труда его понять... Для получения дополнительной информации см. Gson API Javadoc