Search code examples
jsonkotlinserializationjacksondeserialization

Jackson JSON Serialization without field name from one string row


I have this JSON to deserialize:

"data": {
  "type": 18,        
  "msg": "firstName,lastName,15" 
  "timestamp": 1551770400000 
}

I want to get this data in my model:

class DataDto(
    type: String,
    timestamp: Long,
    msg: DataMsgDto?
) {
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    @JsonPropertyOrder("firstName", "lastName", "age")
    class DataMsgDto(
        firstName: String,
        lastName: String,
        age: Long
    )
}

I use this code to get data:

DataBuffer payload //this is what I get from server
val jsonNode = objectMapper.readTree(payload.toString(StandardCharsets.UTF_8))
objectMapper.treeToValue(jsonNode, DataDto::class.java)

But this does not work because in msg I don't have fields. So, how can I do this?


Solution

  • You have a JSON property that contains comma-separated values. The JSON message is valid, and can be deserialized by Jackson.

    It's possible to write custom Jackson code that can handle this case automatically

    But the most practical way to solve this is unlikely to be digging around trying to make Jackson understand msg, or writing a custom deserializer. Instead, allow msg to be a String

    class DataDto(
        val type: String,
        val timestamp: Long,
        // just use a normal String for msg
        val msg: String?
    ) 
    

    And then manually decode it in Kotlin

    fun parseDataDtoMsg(dto: DataDto): DataMsgDto? {
      val msgElements = dto.msg?.split(",") ?: return null
    
      // parse each message - you can chose whether to 
      // throw an exception if the `msg` does not match what you expect, 
      // or ignore invalid data and return `null`
    
      val firstName = ...
      val lastName = ...
      val age = ...
    
      return DataDtoMsg(
          firstName = firstName,
          lastName = lastName,
          age = age,
      )
    }
    
    data class DataMsgDto(
        val firstName: String
        val lastName: String
        val age: Long,
    )