Performant Multiplatform Kotlin Serialization

Performant Multiplatform Kotlin Serialization

The promise of Kotlin is mutiplatform. Kotlin serialization is capable of making multiplatform projects share even more code. Come to learn how to get started with Kotlin serialization, how to use it with your chosen data formats, and how to integrate it with your existing frameworks. Now is the best time to hack on Kotlin serialization and learn how it can support your use cases.

627ce26ea490d993a49d6b263768ca67?s=128

Eric Cochran

October 05, 2018
Tweet

Transcript

  1. Performant Multiplatform Kotlin Serialization Eric Cochran KotlinConf October 5, 2018

  2. Performant Multiplatform Kotlin Serialization 0.8

  3. Why?

  4. Get Started buildscript { repositories { maven { url 'https://kotlin.bintray.com/kotlinx'

    } } dependencies { classpath 'org.jetbrains.kotlinx:kotlinx-gradle-serialization-plugin:serializerVersion' } } apply plugin: 'kotlinx-serialization' dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:serializerVersion' }
  5. Get Started IJ plugin https://github.com/Kotlin/ kotlinx.serialization#working-in-intellij-idea

  6. Run it @Serializable data class Data(val number: Long) JSON.stringify(Data(8L)) ProtoBuf.dump(Data(8L))

    val serializer: KSerializer<Data> = Data::class.serializer()
  7. Run it @Serializable data class Data(val number: Long) JSON.stringify(Data(8L)) ProtoBuf.dump(Data(8L))

    val serializer: KSerializer<Data> = Data::class.serializer() JSON.stringify(serializer, Data(8L))
  8. Run it @Serializable data class Data(val number: Long) val serializer:

    KSerializer<Data> = Data::class.serializer() val listSerializer: KSerializer<List<Data>> = serializer.list val setSerializer: KSerializer<Set<Data>> = serializer.set val mapSerializer: KSerializer<Map<User, User>> = (serializer to serializer).map
  9. Run it @Serializable data class Data( @Serializable(with=DifferentLongSerializer::class) val number: Long

    )
  10. Run it @SerialInfo @Target(AnnotationTarget.PROPERTY) annotation class Special @Serializable data class

    Data( @Special val number: Long )
  11. Run it @Serializable data class Data( @SerialName("a number") val number:

    Long )
  12. Run it @Serializable data class Data( @Optional val number: Long

    )
  13. Run it @Serializable data class Data( @Optional val number: Long

    = 8L )
  14. Run it @Serializable data class Data( val number: Long? )

  15. Custom Serialization @Serializable data class Data(val number: Long) { @Serializer(forClass

    = Data::class) companion object { override fun serialize(output: Encoder, obj: Data) { TODO() } override fun deserialize(input: Decoder): Data { TODO() } } }
  16. Custom Serialization @Serializable data class Data(val number: Long) { @Serializer(forClass

    = Data::class) companion object { override fun serialize(output: Encoder, obj: Data) { TODO() } override fun deserialize(input: Decoder): Data { TODO() } } }
  17. Custom Serialization @Serializable data class Data(val number: Long) { @Serializer(forClass

    = Data::class) companion object: KSerializer<Data> { override fun serialize(output: Encoder, obj: Data) { TODO() } override fun deserialize(input: Decoder): Data { TODO() } } }
  18. Platform Types @Serializer(forClass = Date::class) object DateSerializer: KSerializer<Date> { override

    fun serialize(output: Encoder, obj: Date) { TODO() } override fun deserialize(input: Decoder): Date { TODO() } }
  19. Platform Types @Serializer(forClass = Date::class) object DateSerializer: KSerializer<Date> { override

    fun serialize(output: Encoder, obj: Date) { TODO() } override fun deserialize(input: Decoder): Date { TODO() } }
  20. KSerializer SerializationStrategy - fun serialize(output: Encoder, obj : T)

  21. KSerializer SerializationStrategy - fun serialize(output: Encoder, obj : T) DeserializationStrategy

    - fun deserialize(input: Decoder): T
  22. KSerializer SerializationStrategy - fun serialize(output: Encoder, obj : T) DeserializationStrategy

    - fun deserialize(input: Decoder): T val descriptor: SerialDescriptor
  23. KSerialClassDesc @SerialInfo @Target(AnnotationTarget.PROPERTY) annotation class Special serialClassDesc.getAnnotationsForClass()

  24. Readers and Writers data class Pair<T, R>(val one: T, val

    two: R)
  25. Readers and Writers @Serializer(forClass = Pair::class) class PairSerializer<T, R>(val t:

    KSerializer<T>, val r: KSerializer<R>): KSerializer<Pair<T, R>> { }
  26. Readers and Writers @Serializer(forClass = Pair::class) class PairSerializer<T, R>(val t:

    KSerializer<T>, val r: KSerializer<R>): KSerializer<Pair<T, R>> { override fun load(input: Decoder): Pair<T, R> { val compositeDecoder = input.beginStructure(serialClassDesc, t, r) var index = compositeDecoder.decodeElementIndex(serialClassDesc) val one = compositeDecoder.decodeSerializableElement(serialClassDesc, index, t) index = compositeDecoder.decodeElementIndex(serialClassDesc) val two = compositeDecoder.decodeSerializableElement(serialClassDesc, index, r) input.endStructure(serialClassDesc) return Pair(one, two) } }
  27. Readers and Writers @Serializer(forClass = Pair::class) class PairSerializer<T, R>(val t:

    KSerializer<T>, val r: KSerializer<R>): KSerializer<Pair<T, R>> { override fun save( output: Encoder, obj: Pair<T, R> ) { val compositeEncoder = output.beginCollection(serialClassDesc, 2, r, t) compositeEncoder.encodeSerializableElement(serialClassDesc, 0, t, obj.one) output.encodeSerializableElement(serialClassDesc, 1, r, obj.two) output.endStructure(serialClassDesc) } }
  28. Simpler Generics @Serializable class Pair<R, T>(val one: R, val two:

    T) val serializer: KSerializer<Data> = Data::class.serializer() Pair.serializer(serializer, serializer)
  29. Adapting from Java Types fun serializerByTypeToken(type: Type): KSerializer<Any>

  30. Formats JSON Protobuf CBOR

  31. Formats JSON - JSON.parse(deserializationStrategy, string) - JSON.stringify(serializationStrategy, data) Protobuf -

    ProtoBuf.load(deserializationStrategy, byteArray) - ProtoBuf.dump(serializationStrategy, data) CBOR - CBOR.load(deserializationStrategy, byteArray) - CBOR.dump(serializationStrategy, data)
  32. None
  33. typealias Loader<T> = (DeserializationStrategy<Any>, T) -> Any typealias Saver<T> =

    (SerializationStrategy<Any>, Any) -> T https://github.com/JakeWharton/ retrofit2-kotlinx-serialization-converter/
  34. https://github.com/JakeWharton/ retrofit2-kotlinx-serialization-converter/ typealias Loader<T> = (DeserializationStrategy<Any>, T) -> Any typealias

    Saver<T> = (SerializationStrategy<Any>, Any) -> T fun stringBased( contentType: MediaType, loader: Loader<String>, saver: Saver<String> ): Converter.Factory
  35. https://github.com/JakeWharton/ retrofit2-kotlinx-serialization-converter/ typealias Loader<T> = (DeserializationStrategy<Any>, T) -> Any typealias

    Saver<T> = (SerializationStrategy<Any>, Any) -> T fun bytesBased( contentType: MediaType, loader: Loader<ByteArray>, saver: Saver<ByteArray> ): Converter.Factory
  36. https://github.com/JakeWharton/ retrofit2-kotlinx-serialization-converter/ val json = JSON.plain val retrofit = Retrofit.Builder()

    .baseUrl(baseUrl) .client(client) .addConverterFactory(stringBased(contentType, json::parse, json::stringify)) .build()
  37. None
  38. https://github.com/Kotlin/ kotlinx.serialization/ @Eric_Cochran