Jackson Kotlin - Deserialize JsonNode Jackson Kotlin - Deserialize JsonNode json json

Jackson Kotlin - Deserialize JsonNode


The problem cause

Even though ObjectMapper.treeToValue is a Kotlin inline extension function with a reified generic parameter (which means that generics are preserved at runtime), it calls the Java ObjectMapper.treeToValue(TreeNode, Class<T>) method. The value passed as Class<T> will loose generic type information for generic types such as List<Comment>, because of type erasure.

So treeToValue can be used for:

mapper.treeToValue<Comment>(commentNode)

but not for:

mapper.treeToValue<List<Comment>>(commentsNode)

Also note that ObjectMapper contains multiple methods that have @SuppressWarnings annotations, which causes some problems not to appear at compile-time, but at run-time.

Solution 1 - use convertValue()

This is the best solution. It uses the Kotlin extension function ObjectMapper.convertValue.

val commentsNode = mapper.readTree(fullJsonContent).get(0).get("Comments")val comments = mapper.convertValue<List<Comment>>(commentsNode)

Solution 2 - use an ObjectReader

This solution doesn't use jackson-module-kotlin extension functions.

val reader = mapper.readerFor(object : TypeReference<List<Comment>>() {})val comments: List<Comment> = reader.readValue(commentsNode)

Solution 3 - deserialize in map

Because treeToValue (Kotlin extension function) does work for non-generic types, you can first get the nodes as as list of JsonNodes, and then map each JsonNode to a Comment.

But it's cumbersome that you cannot simply return mapper.treeToValue(it), because that causes type inference compile errors.

val commentsNode = mapper.readTree(fullJsonContent).get(0).get("Comments")val comments = commentsNode.elements().asSequence().toList().map {    val comment: Comment = mapper.treeToValue(it)    comment}