Skip to content

Instantly share code, notes, and snippets.

@sandwwraith
Created July 23, 2019 16:23
Show Gist options
  • Save sandwwraith/3d736a5ed6a51ede4a291b7bbb482733 to your computer and use it in GitHub Desktop.
Save sandwwraith/3d736a5ed6a51ede4a291b7bbb482733 to your computer and use it in GitHub Desktop.
Samples for kotlinx.serialization talk (WIP)
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.serialization.*
import kotlinx.serialization.CompositeDecoder.Companion.READ_DONE
import kotlinx.serialization.internal.HexConverter
import kotlinx.serialization.json.*
import kotlinx.serialization.protobuf.ProtoBuf
import org.junit.Test
import java.security.MessageDigest
import java.sql.PreparedStatement
import java.sql.ResultSet
import kotlin.test.assertEquals
@Serializable
data class Data(
val data: String,
val optionalData: String = "empty"
)
@Serializable
data class GenericData<T>(val description: String, val data: T)
private const val inputString = """{"data":"Foo"}"""
private const val inputGenericString = """{"description":"wrapped data","data":{"data":"Bar"}}"""
private const val inputListString = """[{"data":"Bar"}]"""
class TalkSamples {
@Test
fun kxSerialization() {
val serializer: KSerializer<Data> = Data.Companion.serializer()
val data = Json.parse<Data>(serializer, inputString)
// Data(data=Foo, optionalData=empty)
println(data)
}
@Test
fun gson() {
val data = Gson().fromJson(inputString, Data::class.java)
// Data(data=Foo, optionalData=null)
println(data)
}
@Test
fun jackson() {
val data = jacksonObjectMapper().readValue<Data>(inputString)
println(data)
println(jacksonObjectMapper().writeValueAsString(Data("Foo")))
}
@Test
fun gsonGeneric() {
val data: GenericData<Data> = Gson().fromJson(
inputGenericString,
(object : TypeToken<GenericData<Data>>() {}).type
)
println(data)
}
@Test
fun gsonGenericList() {
val data: List<Data> = Gson().fromJson(
inputListString,
(object : TypeToken<List<Data>>() {}).type
)
println(data)
}
@Test
fun kxGeneric() {
val json = Json(JsonConfiguration(
encodeDefaults = false,
unquoted = true,
prettyPrint = true
))
val protobuf = ProtoBuf()
val data = json.parse(
GenericData.serializer(Data.serializer()),
inputGenericString
)
println(data)
println(protobuf)
}
@Test
fun descriptors() {
println(GenericData.serializer(Data.serializer()).descriptor.dump())
println(JsonSchema(Data.serializer().descriptor))
}
fun JsonSchema(descriptor: SerialDescriptor): JsonObject {
val properties = mutableMapOf<String, kotlinx.serialization.json.JsonElement>()
descriptor.elementDescriptors().forEachIndexed { index, child ->
val elementName = descriptor.getElementName(index)
properties[elementName] = JsonSchema(child)
}
val objectData = mutableMapOf<String, JsonElement>(
"description" to JsonLiteral(descriptor.name)
)
if (properties.isNotEmpty()) objectData["properties"] = JsonObject(properties)
return JsonObject(objectData)
}
fun SerialDescriptor.dump(): String {
fun SerialDescriptor.dumpInt(): List<String> {
val builder = mutableListOf<String>()
builder.add("{")
elementDescriptors().forEachIndexed { i, it ->
val inners = it.dumpInt()
val name = getElementName(i)
val type = it.name
builder.add(" $name : $type")
if (it.elementsCount > 0)
builder.addAll(inners.map { " $it" })
}
builder.add("}")
return builder
}
return "$name\n" + dumpInt().joinToString("\n")
}
@Test
fun pluggable() {
val data = Data("Foo")
val stringData = Json.stringify(Data.serializer(), data)
val bytesData = ProtoBuf.dump(Data.serializer(), data)
println(stringData)
println(HexConverter.printHexBinary(bytesData))
val json = Json(JsonConfiguration.Default)
requireNotNull(json)
}
val digest = MessageDigest.getInstance("MD5")
class Hasher(val digest: MessageDigest) : ElementValueEncoder() {
override fun encodeByte(value: Byte) = digest.update(value)
override fun encodeString(value: String) {
digest.update(value.toByteArray())
}
}
fun hash(data: Data): ByteArray {
Data.serializer().serialize(Hasher(digest), data)
return digest.digest()
}
}
class StatementSerializer(val stmt: PreparedStatement) : ElementValueEncoder() {
override fun encodeString(value: String) {
stmt.setString(i++, value)
}
private var i = 0
}
class ResultSetDeserializer(private val rs: ResultSet) : NamedValueDecoder() {
override fun decodeTaggedString(tag: String): String {
return rs.getString(tag)
}
}
@Serializable
data class Color(val r: Byte, val g: Byte, val b: Byte) // #00FFAA
const val color = "#00FFAA"
@Serializable
data class Color(val r: Byte, val g: Byte, val b: Byte) // #00FFAA
const val color = "#00FFAA"
fun Byte.toHexCode(): String = HexConverter.printHexBinary(byteArrayOf(this))
object SingleColorSerializer : KSerializer<Color> {
override fun serialize(encoder: Encoder, obj: Color) {
val code = obj.r.toHexCode() +
obj.b.toHexCode() +
obj.g.toHexCode()
encoder.encodeString("#$code")
}
override fun deserialize(decoder: Decoder): Color {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override val descriptor: SerialDescriptor
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
}
@Serializable
data class SingleColor(val argb: Int)
const val input = """{"red": 255, "green": 128, "blue": 0}"""
object MultipleColorSerializer : KSerializer<SingleColor> {
override fun deserialize(decoder: Decoder): SingleColor {
var result = 0
val decoder = decoder.beginStructure(descriptor)
loop@ while (true) {
when (val i = decoder.decodeElementIndex(descriptor)) {
0 -> result += decoder.decodeByteElement(descriptor, i).toInt() shl 16
1 -> result += decoder.decodeByteElement(descriptor, i).toInt() shl 8
2 -> result += decoder.decodeByteElement(descriptor, i).toInt() shl 0
READ_DONE -> break@loop
}
}
decoder.endStructure(descriptor)
return SingleColor(result)
}
override fun serialize(encoder: Encoder, obj: SingleColor) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override val descriptor: SerialDescriptor
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment