Search code examples
jsonkotlinserializationconfigurationkotlinx.serialization

Serialize an object that has parent reference


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:

Before adding

{
  [
    name: "container_level_1",
    options: [
      { 
        name: "option_group" // implements both Option and OptionContainer
        options: [
          {
            name: "option1",
            value: false
          }
        ]
      },
      {
        name: "option2",
        value: "random value hello"
      }
    ]
  ]
}

After adding

{
  [
    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


Solution

  • 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.