Created
October 29, 2018 19:17
-
-
Save tokou/1660906bd103b0a68f2da283a9c6522c to your computer and use it in GitHub Desktop.
Parent serializer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed class Parent { | |
@Serializable | |
data class B(val b: String) : Parent() | |
@Serializable | |
data class A(val a: String) : Parent() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object ParentSerializer : KSerializer<Parent> { | |
override val descriptor: SerialDescriptor = SerialClassDescImpl("Parent") | |
override fun deserialize(input: Decoder): Parent { | |
val jsonReader = input as? JSON.JsonInput | |
?: throw SerializationException("This class can be loaded only by JSON") | |
val tree = jsonReader.readAsTree() as? JsonObject | |
?: throw SerializationException("Expected JSON object") | |
val mapper = JsonTreeMapper() | |
return when (val t = tree["t"].primitive.content) { | |
"a" -> mapper.readTree(tree, Parent.A.serializer()) | |
"b" -> mapper.readTree(tree, Parent.B.serializer()) | |
else -> throw SerializationException("Unknown type $t") | |
} | |
} | |
override fun serialize(output: Encoder, obj: Parent) { | |
val jsonWriter = output as? JSON.JsonOutput | |
?: throw SerializationException("This class can be saved only by JSON") | |
val mapper = JsonTreeMapper() | |
val tree = when (obj) { | |
is Parent.A -> mapper.writeTree(obj, Parent.A.serializer()) | |
is Parent.B -> mapper.writeTree(obj, Parent.B.serializer()) | |
} | |
val k = when (obj) { | |
is Parent.A -> "a" | |
is Parent.B -> "b" | |
} | |
val o = tree.jsonObject | |
val c: MutableMap<String, JsonElement> = mutableMapOf("t" to JsonPrimitive(k)) | |
c.putAll(o.content) | |
val r = o.copy(c) | |
jsonWriter.writeTree(r) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ParentSerializerTest { | |
@Test | |
fun serialize() { | |
val strA = JSON.stringify(ParentSerializer, Parent.A("hello")) | |
val strB = JSON.stringify(ParentSerializer, Parent.B("toto")) | |
assertEquals("""{"t": "a", "a": "hello"}""", strA) | |
assertEquals("""{"t": "b", "b": "toto"}""", strB) | |
} | |
@Test | |
fun deserialize() { | |
val str = """{"t": "a", "a": "bibi"}""" | |
val o = JSON.parse(ParentSerializer, str) | |
assertEquals(Parent.A("bibi"), o) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open class PolymorphicSerializer<T : Any>( | |
name: String, | |
private val typeKey: String, | |
private val keys: Map<KClass<out T>, String> | |
) : KSerializer<T> { | |
private val classes = keys.reversed() | |
override val descriptor: SerialDescriptor = SerialClassDescImpl(name) | |
@ImplicitReflectionSerializer | |
override fun deserialize(input: Decoder): T { | |
val jsonReader = input as? JSON.JsonInput | |
?: throw SerializationException("This class can be loaded only by JSON") | |
val tree = jsonReader.readAsTree() as? JsonObject | |
?: throw SerializationException("Expected JSON object") | |
val mapper = JsonTreeMapper() | |
val t = tree[typeKey].primitive.content | |
val k = classes[t] | |
val s = k?.serializer() | |
if (s != null) return mapper.readTree(tree, s) | |
else throw SerializationException("No serializer found for type $t") | |
} | |
@ImplicitReflectionSerializer | |
override fun serialize(output: Encoder, obj: T) { | |
val jsonWriter = output as? JSON.JsonOutput | |
?: throw SerializationException("This class can be saved only by JSON") | |
val mapper = JsonTreeMapper() | |
val k = obj::class as KClass<T> | |
val tree = mapper.writeTree(obj, k.serializer()) | |
val l = keys[k] | |
val o = tree.jsonObject | |
val c: MutableMap<String, JsonElement> = mutableMapOf(typeKey to JsonPrimitive(l)) | |
c.putAll(o.content) | |
val r = o.copy(c) | |
jsonWriter.writeTree(r) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PolymorphicSerializerTest { | |
private val serializer = PolymorphicSerializer("Parent", "type", mapOf( | |
Parent.A::class to "a", | |
Parent.B::class to "b" | |
)) | |
@Test | |
fun polymorphicSerialize() { | |
val strA = JSON.stringify(serializer, Parent.A("hello")) | |
val strB = JSON.stringify(serializer, Parent.B("toto")) | |
assertEquals("""{"type": "a", "a": "hello"}""", strA) | |
assertEquals("""{"type": "b", "b": "toto"}""", strB) | |
} | |
@Test | |
fun polymorphicDeserialize() { | |
val str = """{"type": "a", "a": "bibi"}""" | |
val o = JSON.parse(serializer, str) | |
assertEquals(Parent.A("bibi"), o) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment