We've got following structure:
sealed interface Option<T> : IFeature {
var value: T
abstract val parent: OptionContainer
val onChange: (T) -> Unit
fun set(newValue: T) {
if (newValue == value) return
this.value = newValue
Emitter.dispatch(OptionEvent.Change(this))
onChange(newValue)
}
operator fun setValue(thisRef: OptionContainer, property: KProperty<*>, value: T) = set(value)
operator fun getValue(thisRef: OptionContainer, property: KProperty<*>): T = value
}
interface OptionContainer {
val options: MutableList<Option<*>>
fun <V, T : Option<V>> addOption(option: T): T
}
yes, those are circular dependencies. The reason is serialization: we need to be able to somehow serialize an Option exclusively (instead of updating the entire container), but kotlinx.serialization doesn't support that it seems.
What we are trying to achieve:
{
[
name: "container_level_1",
options: [
{
name: "option_group" // implements both Option and OptionContainer
options: [
{
name: "option1",
value: false
}
]
},
{
name: "option2",
value: "random value hello"
}
]
]
}
{
[
name: "container_level_1",
options: [
{
name: "option_group" // implements both Option and OptionContainer
options: [
{
name: "option1",
value: false
},
{
name: "option3", // added
value: 69420
},
]
},
{
name: "option2",
value: "random value hello"
}
]
]
}
Obviously i can't have parent field as @Transient
, because it would require me to put default value there.
We also might have OptionGroup
in the future, so the structure is basically a tree.
Is there any elegant solution to this?
I read the docs, and also say this issue. Seems like they don't plan on supporting it: https://github.com/Kotlin/kotlinx.serialization/issues/15
Is there any elegant solution to this?
No. All possible solutions are ugly.
If it's a tree, you may need to make the parent property transient and then set it back later, for example.