Заставляем Gson создавать объекты нормально — через конструктор

В жизни мне приходилось сталкиваться с двумя библиотеками для работы с JSON: Gson и Jackson-Databind.

Jackson-Databind

Довольно популярная библиотека. Обычно суёт информацию в объекты через мутаторы. Особой фишкой для меня является возможность создавать объекты и нормальным путём — через конструктор.

Единственный замеченный минус — монструозность: порядка 12 тысяч методов. На back-end это не создаёт никаких проблем, а вот для Android-приложений — многовато.

Gson

Не менее популярен. Груб и бесцеремонен. Безразличен к конструкторам — в случае отсутствия no-arg конструктора прибегает к чёрной магии sun.misc.Unsafe. Суёт информацию прямо в поля, минуя мутаторы. Снимает с них модификатор final, если потребуется. Размер — тысяча методов.

Gson и хорошие манеры

Обычно Gson создаёт объекты посредстром ReflectiveTypeAdapterFactory — фабрики адаптеров с вышеописанным грубым поведением. Имеется возможность регистрировать собственные адаптеры и фабрики адаптеров, что позволяет писать десериализацию руками, если не повезло с back-end по каким-то причинам это потребовалось.

Собственно, с помощью написанного за пару часов и занявшего 12 методов ConstructorTypeAdapterFactory я сэмулировал поведение Jackson: создал объект так, как следует — через конструктор. Здесь, конечно, присутствует рефлексия, но в достаточно лёгкой форме.

Пример (Kotlin)

class User @Read constructor(
        @ReadAs("firstName") val name: String,
        @ReadAs("lastName") val surname: String
)
val gson = GsonBuilder()
        .registerTypeAdapterFactory(ConstructorTypeAdapterFactory)
        .create()

val user = gson.fromJson("""{
        "firstName": "John",
        "lastName": "Smith"
    }""", User::class.java)

Смотреть исходный код Gson ConstructorTypeAdapterFactory скачать бесплатно без ожидания и SMS

Комментарии к статье