I have a JSON file:
{
"alice": {
age: 23
},
"bob": {
age: 45
}
}
I want to deserialise it to Collection<Person>
with
data class Person(val name: String, val age: Int)
and serialise back to JSON again.
Can Jackson do this using annotations alone? Or do I need a custom JsonSerializer
/JsonDeserializer
?
Can Jackson do this using annotations alone?
I believe it is not enough to use only annotations. However, there are a few other ways to solve the problem:
You may implement StdDeserializer
from jackson-databind
.
This is an example which works with your code:
const val JSON = """
{
"alice": {
"age": 23
},
"bob": {
"age": 45
}
}
"""
fun main(args: Array<String>) {
val mapper = ObjectMapper()
val module = SimpleModule()
module.addDeserializer(List::class.java, PersonDeserializer(Person::class.java))
mapper.registerModule(module)
val readValue = mapper.readValue(JSON, List::class.java)
println(readValue)
}
data class Person(val name: String, val age: Int)
class PersonDeserializer(vc: Class<*>? = null) : StdDeserializer<List<Person>>(vc) {
override fun deserialize(p: JsonParser, ctx: DeserializationContext): List<Person> {
val people = mutableListOf<Person>()
val node: JsonNode = p.codec.readTree(p)
if (node is ObjectNode) {
for (field in node.fields()) {
val name = field.key
val age = field.value["age"].asInt()
people.add(Person(name, age))
}
}
return people
}
}
The code prints
[Person(name=alice, age=23), Person(name=bob, age=45)]
HashMap
and intermediate representation and then remap
the object.See the example below:
const val JSON = """
{
"alice": {
"age": 23
},
"bob": {
"age": 45
}
}
"""
fun main(args: Array<String>) {
val mapper = ObjectMapper()
val readValue = mapper.readValue(JSON, object : TypeReference<HashMap<String, InterimPerson>>() {})
println("Interim: $readValue")
val finalValue = readValue.map { Person(it.key, it.value.age) }.toList()
println(finalValue)
}
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
data class InterimPerson(@JsonProperty("age") var age: Int)
data class Person(val name: String, val age: Int)
The code yields:
Interim: {bob=InterimPerson(age=45), alice=InterimPerson(age=23)}
[Person(name=bob, age=45), Person(name=alice, age=23)]