Search code examples
jsonkotlinjackson

Can't serialize json with one field as a Map<String, Double>


I have the following kotlin class:

data class MyClass(private val myMap: Map<String, Double>, val defaultValue: Double)

I don't have problems to deserialize it (to convert it from json string to a Kotlin class), but when I try to serialize it (from Kotlin class to json string), it does not work for the property myMap.

This is an example of a test:

private val objectMapper: ObjectMapper = jacksonObjectMapper().findAndRegisterModules()

@Test
fun serializing() {
    val myClass = MyClass(mapOf(Pair("user1",1.0), Pair("user2", 2.0)), defaultPoints = 1.0)

    val myMapObject = JSONObject()
    myMapObject .put("user1",1)
    myMapObject .put("user2",2)
    val expected= JSONObject()
    expected.put("myMap", myMapObject)
    expected.put("defaultPoints", 1)
    val actual = JSONObject(this.objectMapper.writeValueAsString(pointCalculator))

    assertEquals(expected, actual)
}

But the json field myMap in the actual json is empty (This is what I get: {"defaultPoints":1}).

Am I missing something?


Solution

  • If your aim is to take your Kotlin object, serialize into a String and then deserialize it back into an object and asset that this round trip works, then you do not need JSONObject. The actual fault (as @Tim Roberts) says is due to the private modifier on the myMap field. By default Jackson will look for public getters for rather than use direct field access, so it cannot see the myMap field.

    This code works:

    data class MyClass(val myMap: Map<String, Double>, val defaultPoints: Double)
    private val objectMapper: ObjectMapper = jacksonObjectMapper().findAndRegisterModules()
    
    @Test
    fun serializing() {
        val myClass = MyClass(mapOf(Pair("user1",1.0), Pair("user2", 2.0)), defaultPoints = 1.0)
        val json = objectMapper.writeValueAsString(myClass)
        println(json)
        val myClassRoundTrip = objectMapper.readValue(json, MyClass::class.java)
        assertEquals(myClass, myClassRoundTrip)
    }
    
    

    and it prints

    {"myMap":{"user1":1.0,"user2":2.0},"defaultPoints":1.0}