kotlin serializable with constructor properties and custom setters

247 Views Asked by At

I wanted to make a class of mine Serializable (kotlinx.serialization) but realized this is not possible due to these constraints in Kotlin:

  • Serializable requires every parameter in the primary constructor to be a property
  • constructor properties can't have custom setters

Here's some approaches with different drawbacks marked as TODOs. For me the third option seems a bit like a workaround.

Is there any easier solution than 3. without boiler plate code?

  1. class is not serializable automatically because it has primary constructor parameters that are not properties
// TODO: @Serializable
class Test1(
        x: Float
) {
    var x: Float = x
        set(value) {
            field = value; b = false
        }
    var b: Boolean = false
    
    fun set() {
        b = true
    }
}
  1. Can't use a custom setter on constructor property
@Serializable
class Test2(
        // TODO: b is not reset everytime x is updated
        var x: Float
) {
    // TODO: Can't define setter for constructor property
    // var x: Float = x
    //  set(value) {
    //      field = value; b = false
    //  }
    var b: Boolean = false
    
    fun set() {
        b = true
    }
}
  1. boiler plate code _x, using _x in code might lead to inconsistent state
@Serializable
class Test3(
        @SerialName("x")
        private var _x: Float
) {
    
    var x: Float
        get() = _x
        set(value) {
            _x = value; b = false
        }
    
    var b: Boolean = false
    
    fun set() {
        b = true
    }
}
1

There are 1 best solutions below

1
Scott Stanchfield On

Based on your constraints, you may want to consider having two separate objects - one to serialize, and one to use in the app. The one used in the app would have your custom setters, the one to serialize would only have (val) constructor properties.

The in-app one could have a toStorage() function (or some other name) that returns the serializable object. The serializable object could have a toState() function (or some other name) that creates the in-app-usage instance.