What is the correct syntax to deserialize the following JSON:
[ { "id" : "1", "name" : "Blues" }, { "id" : "0", "name" : "Rock" } ]
I tried:
//Works OK val dtos = mapper.readValue(json, List::class.java)
However I want:
val dtos : List<GenreDTO> = mapper.readValue(json, List<GenreDTO>::class.java)
The above syntax is not correct and gives: only classes are allowed on the left hand side of a class literal
A polymorphic deserialization allows a JSON payload to be deserialized into one of the known gadget classes that are documented in SubTypeValidator. java in jackson-databind in GitHub. The deserialized object is assigned to a generic base class in your object model, such as java. lang.
A JsonNode is Jackson's tree model for JSON and it can read JSON into a JsonNode instance and write a JsonNode out to JSON. To read JSON into a JsonNode with Jackson by creating ObjectMapper instance and call the readValue() method. We can access a field, array or nested object using the get() method of JsonNode class.
Jackson is a powerful and efficient Java library that handles the serialization and deserialization of Java objects and their JSON representations. It's one of the most widely used libraries for this task, and runs under the hood of many other frameworks.
GitHub - FasterXML/jackson-module-kotlin: Module that adds support for serialization/deserialization of Kotlin (http://kotlinlang.org) classes and data classes. Module that adds support for serialization/deserialization of Kotlin (http://kotlinlang.org) classes and data classes.
NOTE: The answer from @IRus is also correct, it was being modified at the same time I wrote this to fill in more details.
You should use the Jackson + Kotlin module or you will have other problems deserializing into Kotlin objects when you do no have a default constructor.
Your first sample of the code:
val dtos = mapper.readValue(json, List::class.java)
Is returning an inferred type of List<*>
since you did not specify more type information, and it is actually a List<Map<String,Any>>
which is not really "working OK" but is not producing any errors. It is unsafe, not typed.
The second code should be:
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue val mapper = jacksonObjectMapper() // ... val genres: List<GenreDTO> = mapper.readValue(json)
You do not need anything else on the right side of the assignment, the Kotlin module for Jackson will reify the generics and create the TypeReference
for Jackson internally. Notice the readValue
import, you need that or .*
for the com.fasterxml.jackson.module.kotlin
package to have the extension functions that do all of the magic.
A slightly different alternative that also works:
val genres = mapper.readValue<List<GenreDTO>>(json)
There is no reason to NOT use the extension functions and the add-on module for Jackson. It is small and solves other issues that would require you to jump through hoops to make a default constructor, or use a bunch of annotations. With the module, your class can be normal Kotlin (optional to be data
class):
class GenreDTO(val id: Int, val name: String)
The error you're getting is about following expression:
List<GenreDTO>::class.java
Because of how jvm treats generics there's no separate class for List<GenreDTO>
thus compiler complains. Similarly in Java the following will not compile:
List<GenreDTO>.getClass()
Here's a sample that will deserialize the list properly:
val value:List<GenreDTO> = mapper.readValue(json, object : TypeReference<List<GenreDTO>>() {})
As @JaysonMinard has pointed out you can use jackson-module-kotlin to simplify the invocation to:
val genres: List<GenreDTO> = mapper.readValue(json) // or val genres = mapper.readValue<List<GenreDTO>>(json)
This is possible because of reified type parameters
. Consider looking at Extensions
to find out details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With