英文:
(de)serializing kotlin delegate properties with jackson
问题
如何使用Jackson序列化和反序列化Kotlin代理属性。
我有一个类似这样的类
class MyClass {
var a: Int = 42
set(value) {
val changed = field != value
field = value
if (changed) notifyListeners()
}
... 还有其他十几个遵循这种模式的属性 ...
}
我想通过以下方式简化它
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会忽略该属性。
我该如何告诉Jackson序列化和反序列化该属性?
然后如何应用@JsonIgnore注释(或类似的内容)?
英文:
How can I (de)serialize kotlin delegate properties with jackson.
I have a class like this
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 ...
}
I wanted to simplify that by using
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()
}
}
}
but then Jackson will ignore that property.
How can I tell Jackson to serialize and deserialize that property anyway?
And how do I then apply @JsonIgnore annotations (or something comparable)?
答案1
得分: 4
You must use outdated version on Jackson (or maybe a version for Java, not Kotlin?). I've checked this using "com.fasterxml.jackson.module:jackson-module-kotlin:2.10.+"
(resolved to 2.10.1).
I've declared two classes:
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")
}
}
My main function:
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())
}
Output:
No delegate: {"a":42}
With delegate {"a":42}
changed: 42
We even can see output on delegate when we use delegate property (I believe it's a side-effect that should be considered as a bug actually)
So, handling delegates is an out-of-the-box feature in Jackson (I am not sure since when, but I used lazy
delegate with Jackson
in an older project I used to participate and there were no problems with delegates).
How to ignore delegated property?
So, you cannot apply JsonIgnore
annotation to delegated field because you will get This annotation is not applicable to target 'member property with delegate'
. But, you can define the scope that the annotation should be applied. Example below:
class MyDelegateClass {
@get:JsonIgnore // or set:
val a: Int by NotifyUi(42)
}
Unfortunately, it seems that it's kind of broken because you can use get:
or set:
and it's not applied to the getter or setter only but for both.
英文:
You must use outdated version on Jackson (or maybe a version for Java, not Kotlin?). I've checked this using "com.fasterxml.jackson.module:jackson-module-kotlin:2.10.+"
(resolved to 2.10.1).
I've declared two classes:
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")
}
}
My main function:
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())
}
Output:
No delegate: {"a":42}
With delegate {"a":42}
changed: 42
We even can see output on delegate when we use delegate property (I believe it's a side-effect that should be consider as bug actually)
So, handling delegates is out of the box feature in jackson (I am not sure since when, but I used lazy
delegate with jackson
in older project I used to participate and there was no problems with delegates).
How to ignore delegated property?
So, you cannot apply JsonIgnore
annotation to delegated field, because you will get This annotation is not applicable to target 'member property with delegate'
. But, you can define the scope that annotation should be applied. Example below:
class MyDelegateClass {
@get:JsonIgnore // or set:
val a: Int by NotifyUi(42)
}
Unfortunately, seems that it's kind of broken, because you can use get:
or set:
and it's not apply to getter or setter only, but for both.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论