¿Cómo obtengo el nombre de class de un nombre de tipo?

Estoy tratando de deserializar una cadena Json en un object de tipo OperationResult<String> usando Jackson con Kotlin.

Necesito build un object tipo así:

 val mapper : ObjectMapper = ObjectMapper(); val type : JavaType = mapper.getTypeFactory() .constructParametricType(*/ class of OperationResult */,, /* class of String */); val result : OperationResult<String> = mapper.readValue( responseString, type); 

He intentado lo siguiente, pero no funcionan.

 val type : JavaType = mapper.getTypeFactory() .constructParametricType( javaClass<OperationResult>, javaClass<String>); // Unresolved javaClass<T> val type : JavaType = mapper.getTypeFactory() .constructParametricType( OperationResult::class, String::class); 

¿Cómo obtengo una class Java de los nombres tipo?

El siguiente funciona como se espera:

 val type = mapper.typeFactory.constructParametricType(OperationalResult::class.java, String::class.java) val operationalResult = mapper.readValue<OperationalResult<String>>("""{"result":"stack"}""", type) println(operationalResult.result) // -> stack 

Una alternativa más simple para deserializar los types generics usando com.fasterxml.jackson.core.type.TypeReference :

 val operationalResult = mapper.readValue<OperationalResult<Double>>("""{"result":"5.5"}""", object : TypeReference<OperationalResult<Double>>() {}) println(operationalResult.result) // -> 5.5 

Y con la ayuda del module jackson-kotlin, incluso puedes escribir:

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

Kotlin tiene algunas cosas que se vuelven una preocupación cuando se usa Jackson, GSON u otras bibliotecas que crean instancias de objects de Kotlin. Una, es ¿cómo se obtiene Class , TypeToken , TypeReference u otra class especializada sobre la que algunas bibliotecas quieran saber. La otra es cómo pueden build classs que no siempre tienen constructores por defecto, o son inmutables.

Para Jackson, se creó un module específicamente para cubrir estos casos. Se menciona en la respuesta de @miensol. Él muestra un ejemplo similar a:

 import com.fasterxml.jackson.module.kotlin.* // added for clarity val operationalResult: OperationalResult<Long> = mapper.readValue(""{"result":"5"}""") 

En realidad, se trata de una function de extensión en línea añadida a ObjectMapper por el module de Kotlin, y utiliza el tipo inferido del resultado que toma los generics reificados (disponible para las funciones en línea) para hacer lo que sea necesario para decirle a Jackson sobre el tipo de datos. Crea un Jackson TypeReference detrás de escena para ti y se lo pasa a Jackson. Esta es la fuente de la function:

 inline fun <reified T: Any> ObjectMapper.readValue(content: String): T = readValue(content, object: TypeReference<T>() {}) 

Puede codificar fácilmente lo mismo, pero el module tiene un número mayor de estos ayudantes para hacer este trabajo por usted. Además, maneja la posibilidad de llamar a constructores no pnetworkingeterminados y methods de fábrica estáticos para usted también. Y en Jackson 2.8. + También puede tratar de manera más inteligente con nulability y parameters de método por defecto (lo que permite que falten los valores en el JSON y, por lo tanto, que usen el valor pnetworkingeterminado). Sin el module, pronto encontrará nuevos errores.

En cuanto a su uso de mapper.typeFactory.constructParametricType , debe usar TypeReference , es mucho más fácil y sigue el mismo patrón que el anterior.

 val myTypeRef = object: TypeReference<SomeOtherClass>() {} 

Este código crea una instancia anónima de una class (a través de una expresión de object ) que tiene un tipo estupendo de TypeRefrence con su class genérica especificada. La reflexión de Java puede consultar esta información.

Tenga cuidado al usar Class directamente porque borra información de tipo genérico, por lo que al usar SomeOtherClass::class o SomeOtherClass::class.java todos pierden los generics y deben evitarse para las cosas que requieren su conocimiento.

Entonces, incluso si puede salirse con la suya con algunas cosas sin usar el module Jackson-Kotlin, pronto se encontrará con mucho dolor más adelante. En lugar de tener que manipular su Kotlin, este module elimina estos types de errores y le permite hacer más cosas de la "manera Kotlin".

KClass get una instancia de Class not KClass . Para getlo, simplemente utiliza ::class.java lugar de ::class .

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