suppose i have the following interface and impleme...
# serialization
a
suppose i have the following interface and implementation
Copy code
interface XY {
  val x: Int,
  val y: Int
}

@Serializable
data class Point(
  override val x: Int,
  override val y: Int
) : XY
a) How do I mark
XY
as serializable and that it should use
Point.serializer()
during serialization? b) Suppose I have a class Vehicle
Copy code
@Serializable
class Car(
  val position: XY
)
How do I mark
Car::position
to use
Point.serializer()
as it's serializer? c) Suppose I have a class
Point3
like so
Copy code
@Serializable
data class Point3(
  override val x: Int,
  override val y: Int,
  val x: Int = 0
) : XY
How do I mark
Car::position
in part (b) of the question to use
Point3.serializer()
as it's serialzer?
d
By coincidence, I was just going to ask something very similar, so I will add it here. If I define serial names for the interface properties inside that interface, will it also be used everywhere where those properties are overwritten? Example:
Copy code
interface Hashable {
    @Serializable
    @SerialName("h")
    val hash: String
}

@Serializable
data class Entity(val id: Int, override val hash: String): Hashable
@andylamax There seem to be an example for interfaces. I would guess there is not a way to centrally define serializer for the interface, but I think this might work
Copy code
interface XY {
    val x: Int
    val y: Int
}

object XYSerializer : KSerializer<XY> {
    override val descriptor: SerialDescriptor
        get() = //TODO
    override fun deserialize(decoder: Decoder): XY {
        //TODO
    }
    override fun serialize(encoder: Encoder, value: XY) {
        //TODO
    }
}

@Serializable
data class Car(
    @Serializable(with = XYSerializer::class)
    val position: XY
)
a
I am aware of custom serializers, i am just curious if I could use a compiler generated serializer without having to explicitly write a custom one myself
p
Your option c) is very error prone. Point3 has more information than XY so if you go that route, it will always crash if XY isn’t Point3.
Regarding your question, you would use a serializers module:
Copy code
fun main() {
  val json = Json {
    serializersModule = SerializersModule {
      polymorphic(XY::class, Point::class, Point.serializer())
    }
  }
  println(json.encodeToString(Car.serializer(), Car(Point(42, 24))))
}
If you don’t want to register a custom serializer you can use delegation: https://gist.github.com/PaulWoitaschek/c650466b8bbc0c44797b6b10951918a5
Though that’s error prone now because once XY is not a Point it will crash
So at some point you need to do a manual step to be safe against that:
Copy code
object XYSerializer : KSerializer<XY> {
  override fun deserialize(decoder: Decoder): XY = Point.serializer().deserialize(decoder)
  override val descriptor: SerialDescriptor = Point.serializer().descriptor
  override fun serialize(encoder: Encoder, value: XY) {
    encoder.encodeSerializableValue(Point.serializer(), Point(value.x, value.y))
  }
}
a
Your option c) is very error prone. Point3 has more information than XY so if you go that route, it will always crash if XY isn’t Point3.
How will it crash? I though
Point3
has a default z argument. and it will always be an instance of XY
The custom serializer you posted is a testament that
XY
can be purely serialized with
Point.serializer()
. What I am asking now is, "Is there a current way to tell the compiler to just go ahead and use `Point.serializer()`" to Serialize
XY
Instead of having to write this custom serializer down?. In better terms, the compiler has already generated a serializer that can easily serialize and deserialize XY, it feels like there should be an easier way to tell it, "for this particular case, go ahead and use this other serializer you have already generated". This might not be a currently available feature. But there sure is a use case for it