7

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
kolay
  • 73
  • 1
  • 6

1 Answers1

5

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.

Roland
  • 22,259
  • 4
  • 57
  • 84
  • I edited post. Variant with jackson kotlin module doesnt work – kolay Aug 31 '18 at 14:02
  • did you try with `reified`? – Roland Aug 31 '18 at 14:29
  • Same error? Or a different one? Did you pass the whole type from outside or a mixture? – Roland Aug 31 '18 at 16:40
  • Yes, still throw ClassCastException. – kolay Aug 31 '18 at 16:42
  • I have getUpdates fun, that call request fun with List type. That call parse fun with Response. request and parse are inline with reified typevar – kolay Aug 31 '18 at 16:43
  • I don't get what you mean.. can you post the beginning of your JSON and maybe also the outermost corresponding type? It should work with the code as shown.. are you sure that you need to wrap it as `Response`? – Roland Aug 31 '18 at 19:04
  • In this case```{"ok": true, "some info":"about response", "result": [{"update":"objects"}]}``` But `response.result` may have any type. – kolay Aug 31 '18 at 19:45
  • Assuming something like `class Response(val ok : Boolean, ..., val result : T)` and appropriate constructor, the following should deserialize it: `parse>>(json)`.. note that I write it with my smartphone now... could be that some minor things aren't ok.. but with the reified variant it should work or give rather another error... – Roland Aug 31 '18 at 19:51
  • 1
    What you could also do: try to serialize a similar object first and look what you get.. – Roland Aug 31 '18 at 19:52
  • When i serialize object, i have this json `{"ok":true,"result":[{"update_id":10,"message":null}]}`. When i try desialize, i have that error `Exception in thread "main" java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to ru.kolay.xxx.types.Update at ru.kolay.xxx.MainKt.main(main.kt)` My code: https://pastebin.com/bSgTXUVG – kolay Sep 01 '18 at 12:02
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/179239/discussion-between-kolay-and-roland). – kolay Sep 01 '18 at 12:11