Я пытаюсь десериализовать строку Json в объект типа OperationResult<String>
, используя Джексон с Kotlin.
Мне нужно создать объект типа так:
val mapper : ObjectMapper = ObjectMapper();
val type : JavaType = mapper.getTypeFactory()
.constructParametricType(*/ class of OperationResult */,,
/* class of String */);
val result : OperationResult<String> = mapper.readValue(
responseString, type);
Я пробовал следующее, но они не работают.
val type : JavaType = mapper.getTypeFactory()
.constructParametricType(
javaClass<OperationResult>,
javaClass<String>); // Unresolved javaClass<T>
val type : JavaType = mapper.getTypeFactory()
.constructParametricType(
OperationResult::class,
String::class);
Как мне получить класс java из имен типов?
3 ответа
Следующее работает должным образом:
val type = mapper.typeFactory.constructParametricType(OperationalResult::class.java, String::class.java)
val operationalResult = mapper.readValue<OperationalResult<String>>("""{"result":"stack"}""", type)
println(operationalResult.result) // -> stack
Более простая альтернатива десериализации универсальных типов с использованием com.fasterxml.jackson.core.type.TypeReference:
val operationalResult = mapper.readValue<OperationalResult<Double>>("""{"result":"5.5"}""",
object : TypeReference<OperationalResult<Double>>() {})
println(operationalResult.result) // -> 5.5
А с помощью jackson-kotlin-module вы даже можете написать:
val operationalResult = mapper.readValue<OperationalResult<Long>>("""{"result":"5"}""")
println(operationalResult.result)
Вам нужно получить экземпляр Class
, а не KClass
. Чтобы получить его, просто используйте ::class.java
вместо ::class
.
val type : JavaType = mapper.typeFactory.constructParametricType(OperationResult::class.java, String::class.java)
У Kotlin есть несколько вещей, которые вызывают беспокойство при использовании Jackson, GSON или других библиотек, которые создают экземпляры объектов Kotlin. Во-первых, как получить Class
, TypeToken
, TypeReference
или другой специализированный класс, о котором хотят знать некоторые библиотеки. Другой - как они могут создавать классы, которые не всегда имеют конструкторы по умолчанию или являются неизменяемыми.
Для Джексона был построен модуль специально для таких случаев. Это упоминается в ответе @miensol. Он показывает пример, похожий на:
import com.fasterxml.jackson.module.kotlin.* // added for clarity
val operationalResult: OperationalResult<Long> = mapper.readValue(""{"result":"5"}""")
На самом деле это вызывает встроенную функцию расширения, добавленную к ObjectMapper
модулем Kotlin, и он использует предполагаемый тип результата, захватывая обобщенные универсальные шаблоны (доступные встроенным функциям), чтобы делать все необходимое, чтобы сообщить Джексону о данных. тип. Он создает для вас Джексона TypeReference
за кулисами и передает его Джексону. Это источник функции:
inline fun <reified T: Any> ObjectMapper.readValue(content: String): T = readValue(content, object: TypeReference<T>() {})
Вы можете легко кодировать то же самое, но в модуле есть большее количество этих помощников, которые сделают эту работу за вас. Кроме того, он обрабатывает возможность вызывать нестандартные конструкторы и статические фабричные методы. А в Jackson 2.8. + Он также может более разумно обрабатывать параметры метода по умолчанию и допускать значение NULL (позволяя значениям отсутствовать в JSON и, следовательно, использовать значение по умолчанию). Без модуля вы скоро обнаружите новые ошибки.
Что касается использования mapper.typeFactory.constructParametricType
, вы должны использовать вместо него TypeReference
, это намного проще и следует тому же шаблону, что и выше.
val myTypeRef = object: TypeReference<SomeOtherClass>() {}
Этот код создает анонимный экземпляр класса (через выражение объекта ) с супертипом TypeRefrence
с указанным универсальным классом. Затем отражение Java может запросить эту информацию.
Будьте осторожны при прямом использовании Class
, поскольку при этом стирается информация об общем типе, поэтому использование SomeOtherClass::class
или SomeOtherClass::class.java
теряет универсальные типы, и его следует избегать для вещей, требующих их знания.
Так что даже если вам удастся кое-что сойти с рук без использования модуля Jackson-Kotlin, вы скоро столкнетесь с большой болью позже. Вместо того, чтобы искажать ваш Kotlin, этот модуль удаляет эти типы ошибок и позволяет вам делать больше "способом Kotlin".
Похожие вопросы
Связанные вопросы
Новые вопросы
kotlin
Kotlin — это кроссплатформенный статически типизированный язык программирования общего назначения высокого уровня с выводом типов. Этот тег часто используется вместе с дополнительными тегами для различных целей (JVM, JavaScript, нативные и т. д.) и библиотек/фреймворков (Android, Spring и т. д.), используемых разработчиками Kotlin, если вопрос относится именно к этим темам.