I think you need to make sure that you register the jackson kotlin module which e.g. adds support for data classes.
Module that adds support for serialization/deserialization of Kotlin classes and data classes. Previously a default constructor must have existed on the Kotlin object for Jackson to deserialize into the object. With this module, single constructor classes can be used automatically, and those with secondary constructors or static factories are also supported.
With that you can create an ObjectMapper that already has this module registered using com.fasterxml.jackson.module.kotlin.ExtensionsKt#jacksonObjectMapper. (Note how you can also use one of the extensions it provides to avoid stating the payload class)
var mapper = jacksonObjectMapper()
val movie: Movie = mapper.readValue(payload)
As an alternative you can still create the object mapper and register the module using the usual API:
var mapper = ObjectMapper()
mapper.registerModule(KotlinModule())
Answer from Mathias Dpunkt on Stack OverflowI think you need to make sure that you register the jackson kotlin module which e.g. adds support for data classes.
Module that adds support for serialization/deserialization of Kotlin classes and data classes. Previously a default constructor must have existed on the Kotlin object for Jackson to deserialize into the object. With this module, single constructor classes can be used automatically, and those with secondary constructors or static factories are also supported.
With that you can create an ObjectMapper that already has this module registered using com.fasterxml.jackson.module.kotlin.ExtensionsKt#jacksonObjectMapper. (Note how you can also use one of the extensions it provides to avoid stating the payload class)
var mapper = jacksonObjectMapper()
val movie: Movie = mapper.readValue(payload)
As an alternative you can still create the object mapper and register the module using the usual API:
var mapper = ObjectMapper()
mapper.registerModule(KotlinModule())
Just add @JsonIgnore annotation to your var id: Long? property
There is no question that the future of parsing in Kotlin will be with kotlinx.serialization. It is part of Kotlin libraries. Version kotlinx.serialization 1.0 is finally released
https://github.com/Kotlin/kotlinx.serialization
import kotlinx.serialization.*
import kotlinx.serialization.json.Json
@Serializable
data class MyModel(val a: Int, @Optional val b: String = "42")
fun main(args: Array<String>) {
// serializing objects
val jsonData = Json.encodeToString(MyModel.serializer(), MyModel(42))
println(jsonData) // {"a": 42, "b": "42"}
// serializing lists
val jsonList = Json.encodeToString(MyModel.serializer().list, listOf(MyModel(42)))
println(jsonList) // [{"a": 42, "b": "42"}]
// parsing data back
val obj = Json.decodeFromString(MyModel.serializer(), """{"a":42}""")
println(obj) // MyModel(a=42, b="42")
}
You can use this library https://github.com/cbeust/klaxon
Klaxon is a lightweight library to parse JSON in Kotlin.
With Jackson Kotlin Module current versions, if you import the full module package or the specific extension function you'll have all extension methods available. Such as:
import com.fasterxml.jackson.module.kotlin.*
val JSON = jacksonObjectMapper() // keep around and re-use
val myList: List<String> = JSON.readValue("""["a","b","c"]""")
Therefore the Jackson Module for Kotlin will infer the the correct type and you do not need a TypeReference instance.
so your case (slightly renamed and fixed the data class, and JSON):
import com.fasterxml.jackson.module.kotlin.readValue
data class MyData(val a: String, val b: Int)
val JSON = jacksonObjectMapper()
val jsonStr = """[{"a": "value1", "b": 1}, {"a": "value2", "b": 2}]"""
val myList: List<MyData> = JSON.readValue(jsonStr)
You can also use the form:
val myList = JSON.readValue<List<MyData>>(jsonStr)
Without the import you will have an error because the extension function is not found.
TL;DR
With Jackson 2.6.3-2 do as @jason-minard advises and simply use:
import com.fasterxml.jackson.module.kotlin.readValue
val listOfD: List<D> = jacksonMapper.readValue(jsonStr)
Details
There's nothing special about Kotlin wrt to deserializing collections, although you'll need the kotlin jackson module to deserialize data classes without annotations.
Namely, it will require full reified type information in your case in order to keep track of the generic parameter of the list (D) ; otherwise (e.g. if you use readValue(jsonStr, List::class.java)) Jackson will only see it as an erased type (i.e. List) (as Kotlin makes explicit) and deserialize it to a List<Map<String, String>>, not knowing it has to construct Ds. This is worked around by using an anonymous subclass of TypeReference in Java so that Jackson can access the full reified type to deserialize to at run time.
Translating Jackson Java code literally to Kotlin, the following thus achieves what you want (and as commented by @eski, notice that the JSON in your example is invalid):
val jacksonMapper = ObjectMapper().registerModule(KotlinModule())
val jsonStr = """[{"a": "value1", "b": 1}, {"a": "value2", "b":2}]"""
val listOfD: List<D> = jacksonMapper.readValue(jsonStr, object : TypeReference<List<D>>(){})
assertEquals(listOf(D("value1", 1), D("value2", 2)), listOfD)
This is a bit verbose and ugly though, so you could hide it in a Kotlin (extension) function (especially if you plan on using it several times):
inline fun <reified T> ObjectMapper.readValue(json: String): T = readValue(json, object : TypeReference<T>(){})
which would allow you to then just call:
val listOfD: List<D> = jacksonMapper.readValue(jsonStr)
And this is just what's included in the 2.6.3-2 jackson Kotlin module.