我正在尝试使用Jackson和Kotlin将Json字符串反序列化为OperationResult<String>
类型的对象。
我需要像这样构造一个类型对象:
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类?
答案 0 :(得分:4)
您需要获取Class
而不是KClass
的实例。要获得它,只需使用::class.java
代替::class
。
val type : JavaType = mapper.typeFactory.constructParametricType(OperationResult::class.java, String::class.java)
答案 1 :(得分:4)
当使用Jackson,GSON或其他实例化Kotlin对象的库时,Kotlin会有一些问题引起关注。一,是如何获得Class
,TypeToken
,TypeReference
或其他某些图书馆想要了解的专业课程。另一个是他们如何构造并不总是具有默认构造函数的类,或者是不可变的。
对于杰克逊来说,专门为这些案件建立了一个模块。在@miensol的回答中提到了它。他展示了一个类似的例子:
import com.fasterxml.jackson.module.kotlin.* // added for clarity
val operationalResult: OperationalResult<Long> = mapper.readValue(""{"result":"5"}""")
这实际上是调用Kotlin模块添加到ObjectMapper
的内联扩展函数,它使用结果的推断类型获取已知的内联函数(可用于内联函数)来执行告诉Jackson所需的任何操作关于数据类型。它会在幕后为你创造一个杰克逊TypeReference
并将其传递给杰克逊。这是该功能的来源:
inline fun <reified T: Any> ObjectMapper.readValue(content: String): T = readValue(content, object: TypeReference<T>() {})
您可以轻松编写相同的代码,但模块中有大量的这些帮助程序可以为您完成此工作。此外,它还可以为您调用非默认构造函数和静态工厂方法。在Jackson 2.8。+中,它还可以更智能地处理可空性和默认方法参数(允许在JSON中缺少值,因此使用默认值)。没有该模块,您很快就会发现新的错误。
至于您对mapper.typeFactory.constructParametricType
的使用,您应该使用TypeReference
代替它,它更容易,并遵循与上述相同的模式。
val myTypeRef = object: TypeReference<SomeOtherClass>() {}
此代码创建一个类的匿名实例(通过object expression),其具有指定了您的泛型类的超级类型TypeRefrence
。然后,Java反射可以查询此信息。
请小心使用Class
,因为它会删除泛型类型信息,因此使用SomeOtherClass::class
或SomeOtherClass::class.java
都会丢失泛型,对于需要了解它们的内容应该避免使用。
所以即使你可以在不使用Jackson-Kotlin模块的情况下逃脱一些事情,你很快就会遇到很多痛苦。而不是必须破坏你的Kotlin这个模块消除了这些类型的错误,让你以“Kotlin方式”做更多事情。
答案 2 :(得分: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)