2016-09-07 93 views
0

我正在尝试使用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类?

+2

您应该使用Jackson-Kotiln模块,然后不需要这些。 https://github.com/FasterXML/jackson-module-kotlin –

+0

@JaysonMinard谢谢。我已经下载并使用Maven构建了一个jar。我将继续使用它。 –

+2

它在Maven Central中有工件,无需构建它... https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-kotlin/2.8.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) 
+0

非常感谢。我正在使用的Eclipse的Kotlin插件不能解析'TypeReference'类型。它也提供很少或没有智能感知来找到你想参考的类型所属的地方。你能告诉我需要导入的包吗? –

+0

@ WaterCoolerv2查看更新。 – miensol

+0

非常感谢。 :-) –

2

您需要获取的实例不是KClass。为了得到它,你只需使用::class.java而不是::class

val type : JavaType = mapper.typeFactory.constructParametricType(OperationResult::class.java, String::class.java) 
+0

谢谢。我实际上也尝试过,但是一旦我输入'OperationResult :: class.',intellisense就没有提出任何建议。我相信这是Eclipse的Kotlin插件的一个问题,因为它无法加载kotlin反射程序集。但我无法确定。我将IDE切换到IntelliJ IDEA Ultimate,如果您提出的解决方案有效,我会向您报告,我认为这是正面的。再次感谢。 :-) –

+0

即使免费版本(Intellij IDEA社区)与Kotlin一起工作:) – rafal

+0

您是对的,但确实如此,但我想编写Community Edition不支持的servlet。 http://stackoverflow.com/q/39072303/303685 –

4

当使用Jackson,GSON或其他实例化Kotlin对象的库时,Kotlin有一些问题需要关注。一,你如何得到ClassTypeToken,TypeReference或某些图书馆想要了解的其他专业类。另一个是他们如何构造并不总是具有默认构造函数或不可变的类。

对于杰克逊来说,一个模块专门用于涵盖这些案例。在@ miensol的回答中提到了它。他示出了类似于一个例子:

import com.fasterxml.jackson.module.kotlin.* // added for clarity 

val operationalResult: OperationalResult<Long> = mapper.readValue(""{"result":"5"}""") 

这实际上是调用由科特林模块添加到ObjectMapper一个内联扩展函数,它使用敛物化泛型推断结果的类型(可用于内联函数)做任何事情来告诉杰克逊的数据类型。它会在幕后为您创建一个Jackson TypeReference并将它传递给Jackson。这是函数的源:

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::classSomeOtherClass::class.java所有失去的仿制药,应当避免为需要他们的知识的东西。

所以,即使你不使用Jackson-Kotlin模块就可以避开一些事情,你很快就会遇到很多痛苦。这个模块可以消除这些类型的错误,而且可以让您以“Kotlin方式”执行更多操作,而不必去修改Kotlin。

+0

谢谢你这么可爱和详细的答案。我喜欢所有的解释。我知道并且已经使用了对象声明,对象表达式(用于创建Java的lambda表达式替代,例如.e.g。inline mouselisteners等)和伴随对象。我明白当你说'对象时发生了什么:TypeReference (){}'。不过,我真的很喜欢你解释事物的方式。非常感谢您的宝贵时间。 :-) –