1 /* 2 * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.serialization.json 6 7 import kotlinx.serialization.* 8 import kotlinx.serialization.descriptors.* 9 import kotlinx.serialization.encoding.* 10 import kotlin.test.* 11 12 class JsonTreeAndMapperTest { 13 private val decoderData = """{"id":0,"payload":{"from":42,"to":43,"msg":"Hello world"},"timestamp":1000}""" 14 private val decoderError = """{"id":1,"payload":{"error":"Connection timed out"},"timestamp":1001}""" 15 16 @Serializable 17 data class Payload(val from: Long, val to: Long, val msg: String) 18 19 sealed class Either { 20 data class Left(val errorMsg: String) : Either() 21 data class Right(val data: Payload) : Either() 22 } 23 24 object EitherSerializer : KSerializer<Either> { <lambda>null25 override val descriptor: SerialDescriptor = buildSerialDescriptor("Either", PolymorphicKind.SEALED) { 26 val leftDescriptor = buildClassSerialDescriptor("Either.Left") { 27 element<String>("errorMsg") 28 } 29 val rightDescriptor = buildClassSerialDescriptor("Either.Right") { 30 element("data", Payload.serializer().descriptor) 31 } 32 element("left", leftDescriptor) 33 element("right", rightDescriptor) 34 } 35 deserializenull36 override fun deserialize(decoder: Decoder): Either { 37 val input = decoder as? JsonDecoder ?: throw SerializationException("This class can be loaded only by Json") 38 val tree = input.decodeJsonElement() as? JsonObject 39 ?: throw SerializationException("Expected JsonObject") 40 if ("error" in tree) return Either.Left(tree.getValue("error").jsonPrimitive.content) 41 42 return Either.Right(input.json.decodeFromJsonElement(Payload.serializer(), tree)) 43 } 44 serializenull45 override fun serialize(encoder: Encoder, value: Either) { 46 val output = encoder as? JsonEncoder ?: throw SerializationException("This class can be saved only by Json") 47 val tree = when (value) { 48 is Either.Left -> JsonObject(mapOf("error" to JsonPrimitive(value.errorMsg))) 49 is Either.Right -> output.json.encodeToJsonElement(Payload.serializer(), value.data) 50 } 51 52 output.encodeJsonElement(tree) 53 } 54 } 55 56 @Serializable 57 data class Event( 58 val id: Int, 59 @Serializable(with = EitherSerializer::class) val payload: Either, 60 val timestamp: Long 61 ) 62 63 @Test testParseDatanull64 fun testParseData() { 65 val ev = Json.decodeFromString(Event.serializer(), decoderData) 66 with(ev) { 67 assertEquals(0, id) 68 assertEquals(Either.Right(Payload(42, 43, "Hello world")), payload) 69 assertEquals(1000, timestamp) 70 } 71 } 72 73 @Test testParseErrornull74 fun testParseError() { 75 val ev = Json.decodeFromString(Event.serializer(), decoderError) 76 with(ev) { 77 assertEquals(1, id) 78 assertEquals(Either.Left("Connection timed out"), payload) 79 assertEquals(1001, timestamp) 80 } 81 } 82 83 @Test testWriteDatanull84 fun testWriteData() { 85 val encoderData = Event(0, Either.Right(Payload(42, 43, "Hello world")), 1000) 86 val ev = Json.encodeToString(Event.serializer(), encoderData) 87 assertEquals(decoderData, ev) 88 } 89 90 @Test testWriteErrornull91 fun testWriteError() { 92 val encoderError = Event(1, Either.Left("Connection timed out"), 1001) 93 val ev = Json.encodeToString(Event.serializer(), encoderError) 94 assertEquals(decoderError, ev) 95 } 96 } 97