(反)使用 jackson 序列化 kotlin 委托属性

(de)serializing kotlin delegate properties with jackson

我如何使用 jackson(反)序列化 kotlin 委托属性。 我有一个这样的class

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()
        }
    }
}

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

您必须在 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

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

因此,处理委托是 jackson 中开箱即用的功能(我不确定从什么时候开始,但我在以前参与的旧项目中使用 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:set: 并且它不适用于 getter 或 setter,但两者都适用.