with formatter @Serializable data class SampleScreenState( val familyName: String, val givenName: String, val age: Int ) val originalState = SampleScreenState("foo", "bar", 30) 12 potatotips #67
with formatter @Serializable data class SampleScreenState( val familyName: String, val givenName: String, val age: Int ) val originalState = SampleScreenState("foo", "bar", 30) val json = Json(JsonConfiguration.Stable) 13 potatotips #67
with formatter @Serializable data class SampleScreenState( val familyName: String, val givenName: String, val age: Int ) val originalState = SampleScreenState("foo", "bar", 30) val json = Json(JsonConfiguration.Stable) // {"familyName":"foo","givenName":"bar","age":30} val serialized = json.stringify(originalState) 14 potatotips #67
with formatter @Serializable data class SampleScreenState( val familyName: String, val givenName: String, val age: Int ) val originalState = SampleScreenState("foo", "bar", 30) val json = Json(JsonConfiguration.Stable) // {"familyName":"foo","givenName":"bar","age":30} val serialized = json.stringify(originalState) val restoredState = json.parse(SampleScreenState::class.serializer(), serialized) 15 potatotips #67
with formatter @Serializable data class SampleScreenState( val familyName: String, val givenName: String, val age: Int ) val originalState = SampleScreenState("foo", "bar", 30) val json = Json(JsonConfiguration.Stable) // {"familyName":"foo","givenName":"bar","age":30} val serialized = json.stringify(originalState) val restoredState = json.parse(SampleScreenState::class.serializer(), serialized) println(originalState == restoredState) // true 16 potatotips #67
classes 18 potatotips #67 sealed class SampleType data class FooType(val text: String = "foo") : SampleType() data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(val d: SampleType)
classes 19 potatotips #67 @Serializable sealed class SampleType @Serializable data class FooType(val text: String = "foo") : SampleType() @Serializable data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(val d: SampleType)
classes 20 potatotips #67 @Serializable sealed class SampleType @Serializable data class FooType(val text: String = "foo") : SampleType() @Serializable data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(val d: SampleType) val originalState = SampleScreenState(FooType()) val json = Json(JsonConfiguration.Stable) // {"d":{"type":"com.sample.FooType", "text":"foo"}} val serialized = json.stringify(originalState)
classes: prior to 0.14.0 21 potatotips #67 sealed class SampleType data class FooType(val text: String = "foo") : SampleType() data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(val d: SampleType) val json = Json(JsonConfiguration.Stable) // Don’t know how to serialize FooType val serialized = json.stringify(SampleScreenState(FooType()))
classes: prior to 0.14.0 22 potatotips #67 sealed class SampleType @Serializable data class FooType(val text: String = "foo") : SampleType() @Serializable data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(@Polymorphic val d: SampleType) val json = Json(JsonConfiguration.Stable) // Still don’t know how to serialize FooType val serialized = json.stringify(SampleScreenState(FooType()))
classes: prior to 0.14.0 23 potatotips #67 sealed class SampleType @Serializable data class FooType(val text: String = "foo") : SampleType() @Serializable data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(@Polymorphic val d: SampleType) val sampleTypeModule = SerializersModule { polymorphic<SampleType> { addSubclass<FooType>() addSubclass<BarType>() } } val json = Json(JsonConfiguration.Stable, sampleTypeModule) // {"d":{"type":"com.sample.FooType", "text":"foo"}} val serialized = json.stringify(SampleScreenState(FooType()))
a library serializable 24 potatotips #67 // Assume SampleType is in the library and cannot have @Serializable sealed class SampleType data class FooType(val text: String = "foo") : SampleType() data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(val d: SampleType) val json = Json(JsonConfiguration.Stable) // Don’t know how to serialize FooType val serialized = json.stringify(SampleScreenState(FooType()))
a library serializable 25 potatotips #67 // Assume SampleType is in the library and cannot have @Serializable sealed class SampleType data class FooType(val text: String = "foo") : SampleType() data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(@Polymorphic val d: SampleType) val json = Json(JsonConfiguration.Stable) // Still don’t know how to serialize FooType val serialized = json.stringify(SampleScreenState(FooType()))
a library serializable 26 potatotips #67 // Assume SampleType is in the library and cannot have @Serializable sealed class SampleType data class FooType(val text: String = "foo") : SampleType() data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(@Polymorphic val d: SampleType) val sampleTypeModule = SerializersModule { polymorphic<SampleType> { addSubclass<FooType>() // Need to have serializer for FooType addSubclass<BarType>() // Need to have serializer for BarType } } val json = Json(JsonConfiguration.Stable, sampleTypeModule) // Still don’t know how to serialize FooType val serialized = json.stringify(SampleScreenState(FooType()))
a library serializable 27 potatotips #67 // Assume SampleType is in the library and cannot have @Serializable sealed class SampleType data class FooType(val text: String = "foo") : SampleType() data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(@Polymorphic val d: SampleType) object FooTypeSerializer : KSerializer<FooType> { /* implementation */ } // define how to serialize FooType object BarTypeSerializer : KSerializer<BarType> { /* implementation */ } // define how to serialize BarType val sampleTypeModule = SerializersModule { polymorphic<SampleType> { addSubclass(FooTypeSerializer) addSubclass(BarTypeSerializer) } } val json = Json(JsonConfiguration.Stable, sampleTypeModule) // {"d":{"type":"com.sample.FooType", "text":"foo"}} val serialized = json.stringify(SampleScreenState(FooType()))
a library serializable 28 potatotips #67 // Assume SampleType is in the library and cannot have @Serializable sealed class SampleType data class FooType(val text: String = "foo") : SampleType() object FooTypeSerializer : KSerializer<FooType> { /* implementation */ }
a library serializable 29 potatotips #67 // Assume SampleType is in the library and cannot have @Serializable sealed class SampleType data class FooType(val text: String = "foo") : SampleType() object FooTypeSerializer : KSerializer<FooType> { override val descriptor = object : SerialClassDescImpl(FooType::class.java.name) { init { // remember this element is the first element (index = 0) addElement("text") } } }
a library serializable 30 potatotips #67 // Assume SampleType is in the library and cannot have @Serializable sealed class SampleType data class FooType(val text: String = "foo") : SampleType() object FooTypeSerializer : KSerializer<FooType> { override val descriptor = // …… override fun deserialize(decoder: Decoder): FooType { val input = decoder.beginStructure(descriptor) val text = input.decodeStringElement(descriptor, 0) input.endStructure(descriptor) return FooType(text) } }
a library serializable 31 potatotips #67 // Assume SampleType is in the library and cannot have @Serializable sealed class SampleType data class FooType(val text: String = "foo") : SampleType() object FooTypeSerializer : KSerializer<FooType> { override val descriptor = // …… override fun serialize(encoder: Encoder, obj: FooType) { val output = encoder.beginStructure(descriptor) val text = output.encodeStringElement(descriptor, 0, obj.text) output.endStructure(descriptor) } }
@Serializable sealed class SampleType @Serializable data class FooType(val type: String = "foo") : SampleType() @Serializable data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(val d: SampleType) val originalState = SampleScreenState(FooType()) val json = Json(JsonConfiguration.Stable) // {"d":{"type":"com.sample.FooType", "type":"foo"}} val serialized = json.stringify(originalState) // cannot restore because the JSON parser will take the latter "type" value val restored = json.parse(SampleScreenState::class.serializer(), serialized)
key for FQCN 33 potatotips #67 @Serializable sealed class SampleType @Serializable data class FooType(val type: String = "foo") : SampleType() @Serializable data class BarType(val flag: Boolean = false) : SampleType() @Serializable data class SampleScreenState(val d: SampleType) val originalState = SampleScreenState(FooType()) val json = Json(JsonConfiguration.Stable.copy(classDiscriminator = "kclass")) // {"d":{"kclass":"com.sample.FooType", "type":"foo"}} val serialized = json.stringify(originalState) val restored = json.parse(SampleScreenState::class.serializer(), serialized)
Cross-platform / Multi-platform reflectionless serialization for Kotlin ▸ Supports JSON/CBOR/Protobuf formats ▸ Works on Kotlin/JVM, Kotlin/JS and Kotlin/Native ▸ Compiler help us making the object serializable :) potatotips #67 35