null

Работа с Generic типами в Jackson

Когда мы работаем с сериализацией и десериализацией JSON с использованием библиотеки Jackson, часто возникает необходимость преобразования JSON в сложные обобщённые типы, такие как List или Map. Для этого Jackson предоставляет класс TypeReference, который решает проблему десериализации обобщённых типов. 
 

Проблема десериализации generic типов

 

Предположим, у нас есть JSON-строка, которая представляет список объектов типа ApplicationDto. Если мы попытаемся десериализовать её с помощью стандартного метода ObjectMapper.readValue(), как это делается для обычных классов, мы столкнёмся с проблемой, так как тип List<ApplicationDto> является обобщённым, и Jackson не может корректно определить тип элементов списка без дополнительной информации.
 

Пример кода, который приведёт к ошибке:
 

ObjectMapper objectMapper = new ObjectMapper();
List<ApplicationDto> result = objectMapper.readValue(message.data, List<ApplicationDto>.class);

Ошибка:
 

Only classes are allowed on the left hand side of a class literal

 

Это происходит из-за того, что List<ApplicationDto> — это параметризованный тип, а JVM на этапе компиляции теряет информацию о типах элементов списка из-за явления, называемого Type Erasure (стирание типов). Для решения этой проблемы используется класс TypeReference.
 

Использование TypeReference в Java

 

Jackson предоставляет класс TypeReference, который позволяет указать обобщённый тип для десериализации. Пример использования в Java:
 

ObjectMapper objectMapper = new ObjectMapper();
List<ApplicationDto> result = objectMapper.readValue(
    message.data, new TypeReference<List<ApplicationDto>>() {});

 

Здесь класс TypeReference помогает Jackson получить информацию о конкретном типе данных (в нашем случае — это List<ApplicationDto>), которую оно использует для корректной десериализации.
 

Использование TypeReference в Kotlin

 

Если вы попытаетесь использовать TypeReference в Kotlin аналогичным образом, вы можете столкнуться с ошибкой:
 

Cannot access '<init>': it is protected in 'TypeReference'

 

Это связано с тем, что в Kotlin конструктор класса TypeReference защищён и не может быть вызван напрямую, как в Java. Однако Kotlin предоставляет удобный способ создания анонимных объектов, который позволяет обойти это ограничение.
Для правильного использования TypeReference в Kotlin необходимо создать анонимный объект, унаследованный от TypeReference, используя следующую конструкцию:
 

val objectMapper = ObjectMapper()

val result: List<ApplicationDto> = objectMapper.readValue(
    message.data, object : TypeReference<List<ApplicationDto>>() {})

В этом коде выражение object : TypeReference<List<ApplicationDto>>() {} создаёт анонимный объект, который унаследован от TypeReference, позволяя таким образом корректно указать тип для десериализации.
 

Вперед