2

如何使用杰克逊(反)序列化 kotlin 委托属性。我有这样的课

class MyClass {
    var a: Int = 42
        set(value) {
            val changed = field != value
            field = value
            if (changed) notifyListeners()
        }

    ... and a dozen other properties that all follow this pattern ...
}

我想通过使用来简化它

class MyClass {
    var a: Int by NotifyUiOnChange(42)

    ...

    private inner class NotifyUiOnChange<T>(initialValue: T) : ObservableProperty<T>(initialValue) {
        override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
            notifyUiListeners()
        }
    }
}

但是杰克逊会忽略该属性。
我怎么能告诉杰克逊序列化和反序列化该属性呢?然后我如何应用 @JsonIgnore 注释(或类似的东西)?

4

1 回答 1

5

您必须在 Jackson 上使用过时的版本(或者可能是 Java 版本,而不是 Kotlin?)。我已经使用"com.fasterxml.jackson.module:jackson-module-kotlin:2.10.+"(解析为 2.10.1)检查了这一点。

我已经声明了两个类:

class MyClass {
    var a: Int = 42
        set(value) {
            val changed = field != value
            field = value
            if (changed) notifyListener(field)
        }

    private fun notifyListener(field: Any?) {
        println("changed: $field")
    }
}

class MyDelegatedClass {
    var a: Int by NotifyUi(42)

    private inner class NotifyUi<T>(initialValue: T) : ObservableProperty<T>(initialValue) {
        override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) {
            notifyListener(newValue)
        }
    }

    private fun notifyListener(field: Any?) {
        println("changed: $field")
    }
}

我的主要功能:

fun main() {
    val noDelegate = MyClass()
    val delegated = MyDelegatedClass()

    val mapper = ObjectMapper().registerKotlinModule()

    // Deserialization 
    val noDelegateValue = mapper.writeValueAsString(noDelegate)
    val delegatedValue = mapper.writeValueAsString(delegated)

    println("No delegate:\t$noDelegateValue")
    println("With delegate\t$delegatedValue")

    // Serialization
    val noDelegateObject = mapper.readValue<MyClass>("{\"a\":42}".trimIndent())
    val delegateObject = mapper.readValue<MyDelegatedClass>("{\"a\":42}".trimIndent())

}

输出:

No delegate:    {"a":42}
With delegate   {"a":42}
changed: 42

当我们使用委托属性时,我们甚至可以看到委托的输出:)(我相信这是一个副作用,实际上应该被视为错误)

因此,处理代表是杰克逊的开箱即用功能(我不确定从什么时候开始,但我在以前参与的旧项目中使用了lazy代表jackson,代表没有问题)。

如何忽略委托属性?

因此,您不能将JsonIgnore注释应用于委托字段,因为您将获得This annotation is not applicable to target 'member property with delegate'. 但是,您可以定义应应用注释的范围。下面的例子:

class MyDelegateClass {
    @get:JsonIgnore // or set:
    val a: Int by NotifyUi(42)
}

不幸的是,它似乎有点坏了,因为您可以使用get:orset:并且它不仅适用于 getter 或 setter,而且适用于两者。

于 2020-01-03T14:06:10.827 回答