Kotlin Классы данных великолепны; они краткие, они нулевые. Gson тоже хорош; Это де-факто стандарт разбора JSON на Android по уважительной причине. Но! Классы данных, анализируемые с помощью Gson, не гарантируют ни нулевой безопасности, ни даже значений по умолчанию. Или они?
Эта проблема
Есть отличная статья с описанием проблемы. TL; DR, если у вас есть такой класс данных
значения по умолчанию будут проигнорированы, поэтому JSON, например {"intValue":2}
, создаст объект {intValue=2,srtValue=null}
вместо ожидаемого {intValue=2,srtValue="default"}
Хорошие новости, есть способ исправить это!
Решение
Давайте немного изменим наш класс данных.
Заметили тонкую разницу? Этот класс определяет значения по умолчанию для всех полей. Вот и все! Как только все поля будут иметь значения по умолчанию, Gson будет учитывать их, когда соответствующие поля отсутствуют в JSON (если вам не нужны значения по умолчанию, используйте пустые значения).
Почему это работает?
Причина
Это действительно сводится к двум особенностям.
1. Перегрузки Java Kotlin.
Сравните два класса
байт-код для них будет выглядеть следующим образом Java
как только все поля будут иметь значения по умолчанию, компилятор Kotlin сгенерирует конструктор без параметров по умолчанию в дополнение к другим перегруженным версиям, которые он создает.
2. Небезопасные вызовы Java в Gson
Для Gson важно наличие конструктора по умолчанию. Это работает примерно так (подробнее см. Код ConstructorConstructor):
- попробуйте создать объект через предоставленную реализацию InstanceCreator на основе type-token
- попробуйте вызвать конструктор по умолчанию
- попробуйте вызвать известный конструктор для карт, наборов, очередей и т. д.
- используйте небезопасное распределение, если ничего не помогает (подробнее о небезопасном распределении)
Это означает, что если вы не укажете создателя экземпляра и в вашем классе нет конструктора по умолчанию, объект будет создан без вызова конструктора. Kotlin помещает в конструктор все проверки на null и значения по умолчанию, поэтому все они будут пропущены.
Итак, если вы хорошо разбираетесь в Gson и еще не готовы перейти к новой библиотеке, которая поддерживает значения Kotlin по умолчанию, такие как Moshi, определите все значения по умолчанию в классах данных и позвольте Остальное сделает Gson.
Это оно? Хорошо…
Предостережение
Приведенное выше решение хорошо работает для JSON с пропущенными полями, но есть еще одна проблема. Обнуляемость, определенная в коде Kotlin, может не соблюдаться в JSON, и Gson не будет жаловаться на JSON, как {"intValue":2,"strValue":null}
, который содержит явный null. Если такая ситуация возможна, определите все непримитивные поля как допускающие значение NULL, чтобы избежать неожиданных сбоев в производстве.
Вот и все. Удачного парсинга!