在Kotlin中使用Jackon反序列化嵌套的json字段

时间:2019-01-29 18:24:41

标签: kotlin jackson

我过去已经按照https://www.baeldung.com/jackson-nested-values(第5节)中的说明反序列化了Java中的某些嵌套字段:

@JsonProperty("brand")
private void unpackNested(Map<String,Object> brand) {
    this.brandName = (String)brand.get("name");
    Map<String,String> owner = (Map<String,String>)brand.get("owner");
    this.ownerName = owner.get("name");
}

ownerName是bean中的一个字段。

现在,我需要在Kotlin中做类似的事情,但是我对到目前为止的情况不满意。假设我有一个具有MyPojo字段的createdAt类,但是在表示它的JSON中,该字段嵌套在metadata属性下:

data class MyPojo(var createdAt: LocalDateTime = LocalDateTime.MIN) {

    @JsonProperty("metadata")
    private fun unpackNested(metadata: Map<String, Any>) {

        var createdAtAsString = metadata["createdAt"] as String

        this.createdAt = LocalDateTime.parse(createdAtAsString,DateTimeFormatter.ISO_DATE_TIME)
    }
}

我在这里不喜欢的一件事是我被迫将createdAt设为var,而不是val

这里是否有Kotlin技巧可以使整体状况更好?

1 个答案:

答案 0 :(得分:0)

为简单起见,我将Int用作createdAt的类型。

您可以这样做:

class JsonData(createdAt: Int = 0) {

    private var _createdAt: Int = createdAt

    val createdAt: Int
        get() = _createdAt

    @JsonProperty("metadata")
    private fun unpackNested(metadata: Map<String, Any>) {
        _createdAt =  metadata["createdAt"] as Int
    }
}

createdAt将是具有默认值的参数。由于数据类的构造函数只能具有属性(var / val),因此您将失去data class(现成的toString()等优点)。

在实例化该类时,您将将此参数分配给private var _createdAt

唯一暴露给外部的是没有后备字段createAt的属性(用Java术语来说就是吸气剂)。因此,_createdAt实例化后无法更改。

现在有两种情况:

  1. 如果实例化该类,则_createdAt将被设置为您指定的值。
  2. 如果Jackson实例化了该类,则_createdAt的调用将覆盖unpackNested的值。

这里是一个例子:

val jsonStr = """{
    "metadata": {
        "createdAt": 1
    }
}
""".trimIndent()

fun main() {
    val objectMapper = ObjectMapper()

    // Jackson does instantiation
    val jsonData = objectMapper.readValue(jsonStr, JsonData::class.java)

    // you do it directly
    JsonData(5)
}