Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin: objectmapper.readValue() with TypeReference<HashMap<String, String>> cannot infer parameter

Tags:

kotlin

jackson

I would like to deserialize a json to Map with objectmapper with the following code:

fun onMessage(topic: String, message: MqttMessage) {
   val typeRef = object : TypeReference<HashMap<String, String>>() {}
   val msg = objectMapper.readValue(message.payload, typeRef)
   ...
}

Compiler says it connot infer parameter T in fun <T : Any!> readValue (src: ByteArray!, valueTypeRef: (TypeReference<Any!>..TypeReference<*>?)): T!

Is there any solution to this problem whitout extending a HashMap with my custom class like this:

class MyHashMap : HashMap<String, String>()

...

fun onMessage(topic: String, message: MqttMessage) {
   val msg = objectMapper.readValue(message.payload, MyHashMap::class.java)
   ...
}
like image 280
Dániel Kis Avatar asked Sep 08 '18 18:09

Dániel Kis


2 Answers

The issue, really, is in Jackson's API here. Here's how the readValue method is declared:

public <T> T readValue(String content, TypeReference valueTypeRef)

They are using the raw type of TypeReference for some reason, even though they could easily take a TypeReference<T> as their parameter. If they did, you code would work as is, as Kotlin could then infer the T generic type parameter of the function, and therefore know its return type.

You can work around this issue a couple different ways, however, by being explicit with your types.

  • Either by providing the generic type parameter for the function, and having the type of the msg variable inferred:

    val msg = objectMapper.readValue<HashMap<String, String>>(message.payload, typeRef)
    
  • Or alternatively, by explicitly typing your variable, and having the function's type parameter inferred:

    val msg: HashMap<String, String> = objectMapper.readValue(message.payload, typeRef)
    
like image 178
zsmb13 Avatar answered Sep 17 '22 19:09

zsmb13


One possible way:

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

val msg: Map<String,String> = objectMapper.readValue(message.payload) 
like image 41
rvit34 Avatar answered Sep 18 '22 19:09

rvit34