1 /* <lambda>null2 * Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 @file:UseContextualSerialization(JsonCustomSerializersTest.B::class) 5 6 package kotlinx.serialization.json 7 8 import kotlinx.serialization.* 9 import kotlinx.serialization.builtins.* 10 import kotlinx.serialization.descriptors.* 11 import kotlinx.serialization.encoding.* 12 import kotlinx.serialization.modules.* 13 import kotlinx.serialization.test.* 14 import kotlin.test.* 15 16 class JsonCustomSerializersTest : JsonTestBase() { 17 18 @Serializable 19 data class A(@Id(1) val b: B) 20 21 data class B(@Id(1) val value: Int) 22 23 object BSerializer : KSerializer<B> { 24 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("B", PrimitiveKind.INT) 25 override fun serialize(encoder: Encoder, value: B) { 26 encoder.encodeInt(value.value) 27 } 28 29 override fun deserialize(decoder: Decoder): B { 30 return B(decoder.decodeInt()) 31 } 32 } 33 34 @Serializable 35 data class BList(@Id(1) val bs: List<B>) 36 37 @Serializable(C.Companion::class) 38 data class C(@Id(1) val a: Int = 31, @Id(2) val b: Int = 42) { 39 @Serializer(forClass = C::class) 40 companion object : KSerializer<C> { 41 override fun serialize(encoder: Encoder, value: C) { 42 val elemOutput = encoder.beginStructure(descriptor) 43 elemOutput.encodeIntElement(descriptor, 1, value.b) 44 if (value.a != 31) elemOutput.encodeIntElement(descriptor, 0, value.a) 45 elemOutput.endStructure(descriptor) 46 } 47 } 48 } 49 50 @Serializable 51 data class CList1(@Id(1) val c: List<C>) 52 53 @Serializable(CList2.Companion::class) 54 data class CList2(@Id(1) val d: Int = 5, @Id(2) val c: List<C>) { 55 @Serializer(forClass = CList2::class) 56 companion object : KSerializer<CList2> { 57 override fun serialize(encoder: Encoder, value: CList2) { 58 val elemOutput = encoder.beginStructure(descriptor) 59 elemOutput.encodeSerializableElement(descriptor, 1, ListSerializer(C), value.c) 60 if (value.d != 5) elemOutput.encodeIntElement(descriptor, 0, value.d) 61 elemOutput.endStructure(descriptor) 62 } 63 } 64 } 65 66 @Serializable(CList3.Companion::class) 67 data class CList3(@Id(1) val e: List<C> = emptyList(), @Id(2) val f: Int) { 68 @Serializer(forClass = CList3::class) 69 companion object : KSerializer<CList3> { 70 override fun serialize(encoder: Encoder, value: CList3) { 71 val elemOutput = encoder.beginStructure(descriptor) 72 if (value.e.isNotEmpty()) elemOutput.encodeSerializableElement(descriptor, 0, ListSerializer(C), value.e) 73 elemOutput.encodeIntElement(descriptor, 1, value.f) 74 elemOutput.endStructure(descriptor) 75 } 76 } 77 } 78 79 @Serializable(CList4.Companion::class) 80 data class CList4(@Id(1) val g: List<C> = emptyList(), @Id(2) val h: Int) { 81 @Serializer(forClass = CList4::class) 82 companion object : KSerializer<CList4> { 83 override fun serialize(encoder: Encoder, value: CList4) { 84 val elemOutput = encoder.beginStructure(descriptor) 85 elemOutput.encodeIntElement(descriptor, 1, value.h) 86 if (value.g.isNotEmpty()) elemOutput.encodeSerializableElement(descriptor, 0, ListSerializer(C), value.g) 87 elemOutput.endStructure(descriptor) 88 } 89 } 90 } 91 92 @Serializable(CList5.Companion::class) 93 data class CList5(@Id(1) val g: List<Int> = emptyList(), @Id(2) val h: Int) { 94 @Serializer(forClass = CList5::class) 95 companion object : KSerializer<CList5> { 96 override fun serialize(encoder: Encoder, value: CList5) { 97 val elemOutput = encoder.beginStructure(descriptor) 98 elemOutput.encodeIntElement(descriptor, 1, value.h) 99 if (value.g.isNotEmpty()) elemOutput.encodeSerializableElement( 100 descriptor, 0, ListSerializer(Int.serializer()), 101 value.g 102 ) 103 elemOutput.endStructure(descriptor) 104 } 105 } 106 } 107 108 private val moduleWithB = serializersModuleOf(B::class, BSerializer) 109 110 private fun createJsonWithB() = Json { isLenient = true; serializersModule = moduleWithB; useAlternativeNames = false } 111 // useAlternativeNames uses SerialDescriptor.hashCode, 112 // which is unavailable for partially-customized serializers such as in this file 113 private val jsonNoAltNames = Json { useAlternativeNames = false } 114 115 @Test 116 fun testWriteCustom() = parametrizedTest { jsonTestingMode -> 117 val a = A(B(2)) 118 val j = createJsonWithB() 119 val s = j.encodeToString(a, jsonTestingMode) 120 assertEquals("""{"b":2}""", s) 121 } 122 123 @Test 124 fun testReadCustom() = parametrizedTest { jsonTestingMode -> 125 val a = A(B(2)) 126 val j = createJsonWithB() 127 val s = j.decodeFromString<A>("{b:2}", jsonTestingMode) 128 assertEquals(a, s) 129 } 130 131 @Test 132 fun testWriteCustomList() = parametrizedTest { jsonTestingMode -> 133 val obj = BList(listOf(B(1), B(2), B(3))) 134 val j = createJsonWithB() 135 val s = j.encodeToString(obj, jsonTestingMode) 136 assertEquals("""{"bs":[1,2,3]}""", s) 137 } 138 139 @Test 140 fun testReadCustomList() = parametrizedTest { jsonTestingMode -> 141 val obj = BList(listOf(B(1), B(2), B(3))) 142 val j = createJsonWithB() 143 val bs = j.decodeFromString<BList>("{bs:[1,2,3]}", jsonTestingMode) 144 assertEquals(obj, bs) 145 } 146 147 @Test 148 fun testWriteCustomListRootLevel() = parametrizedTest { jsonTestingMode -> 149 val obj = listOf(B(1), B(2), B(3)) 150 val j = createJsonWithB() 151 val s = j.encodeToString(ListSerializer(BSerializer), obj, jsonTestingMode) 152 assertEquals("[1,2,3]", s) 153 } 154 155 @Test 156 fun testReadCustomListRootLevel() = parametrizedTest { jsonTestingMode -> 157 val obj = listOf(B(1), B(2), B(3)) 158 val j = createJsonWithB() 159 val bs = j.decodeFromString(ListSerializer(BSerializer), "[1,2,3]", jsonTestingMode) 160 assertEquals(obj, bs) 161 } 162 163 @Test 164 fun testWriteCustomInvertedOrder() = parametrizedTest { jsonTestingMode -> 165 val obj = C(1, 2) 166 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 167 assertEquals("""{"b":2,"a":1}""", s) 168 } 169 170 @Test 171 fun testWriteCustomOmitDefault() = parametrizedTest { jsonTestingMode -> 172 val obj = C(b = 2) 173 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 174 assertEquals("""{"b":2}""", s) 175 } 176 177 @Test 178 fun testReadCustomInvertedOrder() = parametrizedTest { jsonTestingMode -> 179 val obj = C(1, 2) 180 val s = jsonNoAltNames.decodeFromString<C>("""{"b":2,"a":1}""", jsonTestingMode) 181 assertEquals(obj, s) 182 } 183 184 @Test 185 fun testReadCustomOmitDefault() = parametrizedTest { jsonTestingMode -> 186 val obj = C(b = 2) 187 val s = jsonNoAltNames.decodeFromString<C>("""{"b":2}""", jsonTestingMode) 188 assertEquals(obj, s) 189 } 190 191 @Test 192 fun testWriteListOfOptional() = parametrizedTest { jsonTestingMode -> 193 val obj = listOf(C(a = 1), C(b = 2), C(3, 4)) 194 val s = jsonNoAltNames.encodeToString(ListSerializer(C), obj, jsonTestingMode) 195 assertEquals("""[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]""", s) 196 } 197 198 @Test 199 fun testReadListOfOptional() = parametrizedTest { jsonTestingMode -> 200 val obj = listOf(C(a = 1), C(b = 2), C(3, 4)) 201 val j = """[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]""" 202 val s = jsonNoAltNames.decodeFromString(ListSerializer<C>(C), j, jsonTestingMode) 203 assertEquals(obj, s) 204 } 205 206 @Test 207 fun testWriteOptionalList1() = parametrizedTest { jsonTestingMode -> 208 val obj = CList1(listOf(C(a = 1), C(b = 2), C(3, 4))) 209 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 210 assertEquals("""{"c":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]}""", s) 211 } 212 213 @Test 214 fun testWriteOptionalList1Quoted() = parametrizedTest { jsonTestingMode -> 215 val obj = CList1(listOf(C(a = 1), C(b = 2), C(3, 4))) 216 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 217 assertEquals("""{"c":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]}""", s) 218 } 219 220 @Test 221 fun testReadOptionalList1() = parametrizedTest { jsonTestingMode -> 222 val obj = CList1(listOf(C(a = 1), C(b = 2), C(3, 4))) 223 val j = """{"c":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]}""" 224 assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode)) 225 } 226 227 @Test 228 fun testWriteOptionalList2a() = parametrizedTest { jsonTestingMode -> 229 val obj = CList2(7, listOf(C(a = 5), C(b = 6), C(7, 8))) 230 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 231 assertEquals("""{"c":[{"b":42,"a":5},{"b":6},{"b":8,"a":7}],"d":7}""", s) 232 } 233 234 @Test 235 fun testReadOptionalList2a() = parametrizedTest { jsonTestingMode -> 236 val obj = CList2(7, listOf(C(a = 5), C(b = 6), C(7, 8))) 237 val j = """{"c":[{"b":42,"a":5},{"b":6},{"b":8,"a":7}],"d":7}""" 238 assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode)) 239 } 240 241 @Test 242 fun testWriteOptionalList2b() = parametrizedTest { jsonTestingMode -> 243 val obj = CList2(c = listOf(C(a = 5), C(b = 6), C(7, 8))) 244 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 245 assertEquals("""{"c":[{"b":42,"a":5},{"b":6},{"b":8,"a":7}]}""", s) 246 } 247 248 @Test 249 fun testReadOptionalList2b() = parametrizedTest { jsonTestingMode -> 250 val obj = CList2(c = listOf(C(a = 5), C(b = 6), C(7, 8))) 251 val j = """{"c":[{"b":42,"a":5},{"b":6},{"b":8,"a":7}]}""" 252 assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode)) 253 } 254 255 @Test 256 fun testWriteOptionalList3a() = parametrizedTest { jsonTestingMode -> 257 val obj = CList3(listOf(C(a = 1), C(b = 2), C(3, 4)), 99) 258 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 259 assertEquals("""{"e":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}],"f":99}""", s) 260 } 261 262 @Test 263 fun testReadOptionalList3a() = parametrizedTest { jsonTestingMode -> 264 val obj = CList3(listOf(C(a = 1), C(b = 2), C(3, 4)), 99) 265 val j = """{"e":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}],"f":99}""" 266 assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode)) 267 } 268 269 @Test 270 fun testWriteOptionalList3b() = parametrizedTest { jsonTestingMode -> 271 val obj = CList3(f = 99) 272 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 273 assertEquals("""{"f":99}""", s) 274 } 275 276 @Test 277 fun testReadOptionalList3b() = parametrizedTest { jsonTestingMode -> 278 val obj = CList3(f = 99) 279 val j = """{"f":99}""" 280 assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode)) 281 } 282 283 @Test 284 fun testWriteOptionalList4a() = parametrizedTest { jsonTestingMode -> 285 val obj = CList4(listOf(C(a = 1), C(b = 2), C(3, 4)), 54) 286 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 287 assertEquals("""{"h":54,"g":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]}""", s) 288 } 289 290 @Test 291 fun testReadOptionalList4a() = parametrizedTest { jsonTestingMode -> 292 val obj = CList4(listOf(C(a = 1), C(b = 2), C(3, 4)), 54) 293 val j = """{"h":54,"g":[{"b":42,"a":1},{"b":2},{"b":4,"a":3}]}""" 294 assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode)) 295 } 296 297 @Test 298 fun testWriteOptionalList4b() = parametrizedTest { jsonTestingMode -> 299 val obj = CList4(h = 97) 300 val j = """{"h":97}""" 301 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 302 assertEquals(j, s) 303 } 304 305 @Test 306 fun testReadOptionalList4b() = parametrizedTest { jsonTestingMode -> 307 val obj = CList4(h = 97) 308 val j = """{"h":97}""" 309 assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode)) 310 } 311 312 @Test 313 fun testWriteOptionalList5a() = parametrizedTest { jsonTestingMode -> 314 val obj = CList5(listOf(9, 8, 7, 6, 5), 5) 315 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 316 assertEquals("""{"h":5,"g":[9,8,7,6,5]}""", s) 317 } 318 319 @Test 320 fun testReadOptionalList5a() = parametrizedTest { jsonTestingMode -> 321 val obj = CList5(listOf(9, 8, 7, 6, 5), 5) 322 val j = """{"h":5,"g":[9,8,7,6,5]}""" 323 assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode)) 324 } 325 326 @Test 327 fun testWriteOptionalList5b() = parametrizedTest { jsonTestingMode -> 328 val obj = CList5(h = 999) 329 val s = jsonNoAltNames.encodeToString(obj, jsonTestingMode) 330 assertEquals("""{"h":999}""", s) 331 } 332 333 @Test 334 fun testReadOptionalList5b() = parametrizedTest { jsonTestingMode -> 335 val obj = CList5(h = 999) 336 val j = """{"h":999}""" 337 assertEquals(obj, jsonNoAltNames.decodeFromString(j, jsonTestingMode)) 338 } 339 340 @Test 341 fun testMapBuiltinsTest() = parametrizedTest { jsonTestingMode -> 342 val map = mapOf(1 to "1", 2 to "2") 343 val serial = MapSerializer(Int.serializer(), String.serializer()) 344 val s = jsonNoAltNames.encodeToString(serial, map, jsonTestingMode) 345 assertEquals("""{"1":"1","2":"2"}""", s) 346 } 347 348 @Test 349 fun testResolveAtRootLevel() = parametrizedTest { jsonTestingMode -> 350 val j = createJsonWithB() 351 val bs = j.decodeFromString<B>("1", jsonTestingMode) 352 assertEquals(B(1), bs) 353 } 354 } 355