Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why kotlin jackson can't deserialize list

I have a function:

inline fun <reified T : Any>parse(result: String): T  = mapper.readValue<Response<T>>(result).someValue

When I pass a list type, e.g. List<MyClass>, and try to get some item from it, I get the following exception:

Exception in thread "ForkJoinPool.commonPool-worker-3" 
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to MyClass
like image 205
kolay Avatar asked Aug 31 '18 12:08

kolay


1 Answers

You need to pass the type to the readValue-function, otherwise Jackson has no way to know to which type it should transform to. By default jackson then just returns a map with keys and its values.

So for your particular problem you may just make the parse-function inline and add a reified to your passed type. This ensures, that the actual type is also passed to Jackson. See also reified types in the kotlin reference. Alternatively you pass the actual type (either using TypeReference or the class itself if it's not generic).

Previously this answer also contained a general information how to deserialize a json list to an actual one, which I will leave here for reference:

mapper.readValue(result, object : TypeReference<List<MyClass>>() {})

or if you use jackson-module-kotlin:

mapper.readValue<List<MyClass>>(result)

Applied to your function that could look like the following:

inline fun <reified T : Any>parse(result: String): T  = mapper.readValue(result, object : TypeReference<T>() {})

or using jackson-module-kotlin:

inline fun <reified T : Any>parse(result: String): T  = mapper.readValue(result)

Calling it would then just be:

val yourObjList = parse<List<MyClass>>(yourJson)
// or
val yourObjList : List<MyClass> = parse(yourJson)

Note that I used reified (which implies inline). If you do not use reified the actual type is not passed on to jackson-module-kotlin's reified methods.

like image 63
Roland Avatar answered Oct 21 '22 16:10

Roland