Есть ли простой способ заставить Gson пропустить поле, если при десериализации его возникла ошибка? - PullRequest
2 голосов
/ 09 января 2020

Я пытаюсь десериализовать некоторые данные с помощью Gson (Java), и API, из которого я извлекаю данные, иногда содержит данные неправильного типа в поле. Т.е. если я ожидаю массив String типов, он может встретить Boolean.

Теперь я понимаю, что это мои текущие параметры:

  • Всегда игнорировать поле из десериализации
  • Создайте пользовательский TypeAdapter, чтобы выполнить десериализацию и отловить ошибку и сделать что-то (например, установить поле в null)

Однако я спрашиваю если есть другой способ легко сделать это, если есть исключение, разбирающее определенное поле, то Gson просто проигнорирует это поле. Что-то вроде аннотации к этому полю, например @Skippable или, может быть, настройки при использовании GsonBuilder для создания Gson объекта?

Кто-нибудь знаком с такой вещью?

1 Ответ

2 голосов
/ 10 января 2020

Это непростая задача - правильно обработать все возможные ошибки в JSON и несоответствия между полезной нагрузкой и POJO моделью. Но мы можем попытаться реализовать интерфейс com.google.gson.TypeAdapterFactory, обернуть все значения по умолчанию TypeAdapter s в try-catch и пропустить неверные данные. Пример решения может выглядеть следующим образом:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class GsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        Gson gson = new GsonBuilder()
                .setLenient()
                .registerTypeAdapterFactory(new IgnoreFailureTypeAdapterFactory())
                .create();

        Entity entries = gson.fromJson(new FileReader(jsonFile), Entity.class);
        System.out.println(entries);
    }

}

class IgnoreFailureTypeAdapterFactory implements TypeAdapterFactory {

    public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        return createCustomTypeAdapter(delegate);
    }

    private <T> TypeAdapter<T> createCustomTypeAdapter(TypeAdapter<T> delegate) {
        return new TypeAdapter<T>() {
            @Override
            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }

            @Override
            public T read(JsonReader in) throws IOException {
                try {
                    return delegate.read(in);
                } catch (Exception e) {
                    in.skipValue();
                    return null;
                }
            }
        };
    }
}

class Entity {
    private Integer id;
    private String name;

    // getters, setters, toString
}

Например, приведенный выше код печатает:

Entity{id=null, name='1'}

для ниже JSON полезная нагрузка:

{
  "id": [
    {
      "a": "A"
    }
  ],
  "name": 1
}

См. Также :

...