(де) сериализация свойств делегата kotlin с помощью jackson

Как я могу (де) сериализовать свойства делегата kotlin с помощью jackson. У меня есть такой класс

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 (или что-то подобное)?

1 ответ

Решение

Вы должны использовать устаревшую версию для 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: или set: и это относится не только к геттеру или сеттеру, но и к обоим.

Другие вопросы по тегам