1 /* <lambda>null2 * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.serialization 6 7 import kotlinx.serialization.builtins.* 8 import kotlinx.serialization.descriptors.* 9 import kotlinx.serialization.encoding.* 10 import kotlinx.serialization.features.sealed.SealedChild 11 import kotlinx.serialization.features.sealed.SealedParent 12 import kotlinx.serialization.json.* 13 import kotlinx.serialization.modules.* 14 import kotlinx.serialization.test.* 15 import kotlin.reflect.* 16 import kotlin.test.* 17 import kotlin.time.Duration 18 19 @Suppress("RemoveExplicitTypeArguments") // This is exactly what's being tested 20 class SerializersLookupTest : JsonTestBase() { 21 22 @Test 23 fun testPrimitive() { 24 val token = typeOf<Int>() 25 val serial = serializer(token) 26 assertSame(Int.serializer() as KSerializer<*>, serial) 27 assertSerializedWithType("42", 42) 28 } 29 30 @Test 31 fun testPlainClass() { 32 val b = StringData("some string") 33 assertSerializedWithType("""{"data":"some string"}""", b) 34 } 35 36 @Test 37 fun testListWithT() { 38 val source = """[{"intV":42}]""" 39 val serial = serializer<List<IntData>>() 40 assertEquals(listOf(IntData(42)), Json.decodeFromString(serial, source)) 41 } 42 43 @Test 44 fun testPrimitiveList() { 45 val myArr = listOf("a", "b", "c") 46 assertSerializedWithType("""["a","b","c"]""", myArr) 47 } 48 49 @Test 50 fun testListAsCollection() { 51 val myArr: Collection<String> = listOf("a", "b", "c") 52 assertSerializedWithType("""["a","b","c"]""", myArr) 53 } 54 55 @Test 56 fun testUnsigned() { 57 assertSame(UByte.serializer(), serializer<UByte>()) 58 assertSame(UShort.serializer(), serializer<UShort>()) 59 assertSame(UInt.serializer(), serializer<UInt>()) 60 assertSame(ULong.serializer(), serializer<ULong>()) 61 } 62 63 @Test 64 @OptIn(ExperimentalUnsignedTypes::class) 65 fun testUnsignedArrays() { 66 assertSame(UByteArraySerializer(), serializer<UByteArray>()) 67 assertSame(UShortArraySerializer(), serializer<UShortArray>()) 68 assertSame(UIntArraySerializer(), serializer<UIntArray>()) 69 assertSame(ULongArraySerializer(), serializer<ULongArray>()) 70 } 71 72 @Test 73 fun testPrimitiveSet() { 74 val mySet = setOf("a", "b", "c", "c") 75 assertSerializedWithType("""["a","b","c"]""", mySet) 76 } 77 78 @Test 79 fun testMapWithT() { 80 val myMap = mapOf("string" to StringData("foo"), "string2" to StringData("bar")) 81 assertSerializedWithType("""{"string":{"data":"foo"},"string2":{"data":"bar"}}""", myMap) 82 } 83 84 @Test 85 fun testNestedLists() { 86 val myList = listOf(listOf(listOf(1, 2, 3)), listOf()) 87 assertSerializedWithType("[[[1,2,3]],[]]", myList) 88 } 89 90 @Test 91 fun testListSubtype() { 92 val myList = arrayListOf(1, 2, 3) 93 assertSerializedWithType<ArrayList<Int>>("[1,2,3]", myList) 94 assertSerializedWithType<List<Int>>("[1,2,3]", myList) 95 } 96 97 @Test 98 fun testListProjection() { 99 val myList = arrayListOf(1, 2, 3) 100 assertSerializedWithType<List<Int>>("[1,2,3]", myList) 101 assertSerializedWithType<MutableList<out Int>>("[1,2,3]", myList) 102 assertSerializedWithType<ArrayList<in Int>>("[1,2,3]", myList) 103 } 104 105 @Test 106 fun testStarProjectionsAreProhibited() { 107 val expectedMessage = "Star projections in type arguments are not allowed" 108 assertFailsWithMessage<IllegalArgumentException>(expectedMessage) { 109 serializer<Box<*>>() 110 } 111 assertFailsWithMessage<IllegalArgumentException>(expectedMessage) { 112 serializer(typeOf<Box<*>>()) 113 } 114 assertFailsWithMessage<IllegalArgumentException>(expectedMessage) { 115 serializerOrNull(typeOf<Box<*>>()) 116 } 117 } 118 119 @Test 120 fun testNullableTypes() { 121 val myList: List<Int?> = listOf(1, null, 3) 122 assertSerializedWithType("[1,null,3]", myList) 123 assertSerializedWithType<List<Int?>?>("[1,null,3]", myList) 124 } 125 126 @Test 127 fun testPair() { 128 val myPair = "42" to 42 129 assertSerializedWithType("""{"first":"42","second":42}""", myPair) 130 } 131 132 @Test 133 fun testTriple() { 134 val myTriple = Triple("1", 2, Box(42)) 135 assertSerializedWithType("""{"first":"1","second":2,"third":{"boxed":42}}""", myTriple) 136 } 137 138 @Test 139 fun testLookupDuration() { 140 assertNotNull(serializerOrNull(typeOf<Duration>())) 141 assertSame(Duration.serializer(), serializer<Duration>()) 142 } 143 144 @Test 145 fun testCustomGeneric() { 146 val intBox = Box(42) 147 val intBoxSerializer = serializer<Box<Int>>() 148 assertEquals(Box.serializer(Int.serializer()).descriptor, intBoxSerializer.descriptor) 149 assertSerializedWithType("""{"boxed":42}""", intBox) 150 val dataBox = Box(StringData("foo")) 151 assertSerializedWithType("""{"boxed":{"data":"foo"}}""", dataBox) 152 } 153 154 @Test 155 fun testRecursiveGeneric() { 156 val boxBox = Box(Box(Box(IntData(42)))) 157 assertSerializedWithType("""{"boxed":{"boxed":{"boxed":{"intV":42}}}}""", boxBox) 158 } 159 160 @Test 161 fun testMixedGeneric() { 162 val listOfBoxes = listOf(Box("foo"), Box("bar")) 163 assertSerializedWithType("""[{"boxed":"foo"},{"boxed":"bar"}]""", listOfBoxes) 164 val boxedList = Box(listOf("foo", "bar")) 165 assertSerializedWithType("""{"boxed":["foo","bar"]}""", boxedList) 166 } 167 168 @Test 169 fun testReferenceArrays() { 170 assertSerializedWithType("[1,2,3]", Array<Int>(3) { it + 1 }, default) 171 assertSerializedWithType("""["1","2","3"]""", Array<String>(3) { (it + 1).toString() }, default) 172 assertSerializedWithType("[[0],[1],[2]]", Array<Array<Int>>(3) { cnt -> Array(1) { cnt } }, default) 173 assertSerializedWithType("""[{"boxed":"foo"}]""", Array(1) { Box("foo") }, default) 174 assertSerializedWithType("""[[{"boxed":"foo"}]]""", Array(1) { Array(1) { Box("foo") } }, default) 175 } 176 177 @Test 178 fun testPrimitiveArrays() { 179 assertSerializedWithType("[1,2,3]", intArrayOf(1, 2, 3), default) 180 assertSerializedWithType("[1,2,3]", longArrayOf(1, 2, 3), default) 181 assertSerializedWithType("[1,2,3]", byteArrayOf(1, 2, 3), default) 182 assertSerializedWithType("[1,2,3]", shortArrayOf(1, 2, 3), default) 183 assertSerializedWithType("[true,false]", booleanArrayOf(true, false), default) 184 assertSerializedWithType("""["a","b","c"]""", charArrayOf('a', 'b', 'c'), default) 185 } 186 187 @Test 188 fun testSerializableObject() { 189 assertSerializedWithType("{}", SampleObject) 190 } 191 192 class IntBox(val i: Int) 193 194 class CustomIntSerializer(isNullable: Boolean) : KSerializer<IntBox?> { 195 override val descriptor: SerialDescriptor 196 197 init { 198 val d = PrimitiveSerialDescriptor("CIS", PrimitiveKind.INT) 199 descriptor = if (isNullable) d.nullable else d 200 } 201 202 override fun serialize(encoder: Encoder, value: IntBox?) { 203 if (value == null) encoder.encodeInt(41) 204 else encoder.encodeInt(42) 205 } 206 207 override fun deserialize(decoder: Decoder): IntBox? { 208 TODO() 209 } 210 } 211 212 class GenericHolder<T>(value: T) 213 214 class GenericSerializer<T>(typeSerializer: KSerializer<T>) : KSerializer<GenericHolder<T>> { 215 override val descriptor: SerialDescriptor = 216 PrimitiveSerialDescriptor( 217 "Generic Serializer parametrized by ${typeSerializer.descriptor}", 218 PrimitiveKind.STRING 219 ) 220 221 override fun deserialize(decoder: Decoder): GenericHolder<T> { 222 TODO() 223 } 224 225 override fun serialize(encoder: Encoder, value: GenericHolder<T>) { 226 TODO() 227 } 228 } 229 230 @Test 231 fun testContextualLookup() { 232 val module = SerializersModule { contextual(CustomIntSerializer(false).cast<IntBox>()) } 233 val json = Json { serializersModule = module } 234 val data = listOf(listOf(IntBox(1))) 235 assertEquals("[[42]]", json.encodeToString(data)) 236 } 237 238 @Test 239 fun testGenericOfContextual() { 240 val module = SerializersModule { 241 contextual(CustomIntSerializer(false).cast<IntBox>()) 242 contextual(GenericHolder::class) { args -> GenericSerializer(args[0]) } 243 } 244 245 val listSerializer = module.serializerOrNull(typeOf<List<IntBox>>()) 246 assertNotNull(listSerializer) 247 assertEquals("kotlin.collections.ArrayList(PrimitiveDescriptor(CIS))", listSerializer.descriptor.toString()) 248 249 val genericSerializer = module.serializerOrNull(typeOf<GenericHolder<IntBox>>()) 250 assertNotNull(genericSerializer) 251 assertEquals( 252 "PrimitiveDescriptor(Generic Serializer parametrized by PrimitiveDescriptor(CIS))", 253 genericSerializer.descriptor.toString() 254 ) 255 } 256 257 @Test 258 fun testContextualLookupNullable() { 259 val module = SerializersModule { contextual(CustomIntSerializer(true).cast<IntBox>()) } 260 val serializer = module.serializer<List<List<IntBox?>>>() 261 assertEquals("[[41]]", Json.encodeToString(serializer, listOf(listOf<IntBox?>(null)))) 262 } 263 264 @Test 265 fun testContextualLookupNonNullable() { 266 val module = SerializersModule { contextual(CustomIntSerializer(false).cast<IntBox>()) } 267 val serializer = module.serializer<List<List<IntBox?>>>() 268 assertEquals("[[null]]", Json.encodeToString(serializer, listOf(listOf<IntBox?>(null)))) 269 } 270 271 @Test 272 fun testCompiledWinsOverContextual() { 273 val contextual = object : KSerializer<Int> { 274 override val descriptor: SerialDescriptor = Int.serializer().descriptor 275 276 override fun serialize(encoder: Encoder, value: Int) { 277 fail() 278 } 279 280 override fun deserialize(decoder: Decoder): Int { 281 fail() 282 } 283 } 284 val json = Json { serializersModule = SerializersModule { contextual(contextual) } } 285 assertEquals("[[1]]", json.encodeToString(listOf(listOf<Int>(1)))) 286 assertEquals("42", json.encodeToString(42)) 287 } 288 289 class NonSerializable 290 291 class NonSerializableBox<T>(val boxed: T) 292 293 @Test 294 fun testSealedFromOtherFileLookup() { 295 assertNotNull(serializerOrNull(typeOf<SealedParent>())) 296 assertNotNull(serializerOrNull(typeOf<SealedChild>())) 297 } 298 299 @Test 300 fun testLookupFail() { 301 assertNull(serializerOrNull(typeOf<NonSerializable>())) 302 assertNull(serializerOrNull(typeOf<NonSerializableBox<String>>())) 303 assertNull(serializerOrNull(typeOf<Box<NonSerializable>>())) 304 305 assertFailsWithMessage<SerializationException>("for class 'NonSerializable'") { 306 serializer(typeOf<NonSerializable>()) 307 } 308 309 assertFailsWithMessage<SerializationException>("for class 'NonSerializableBox'") { 310 serializer(typeOf<NonSerializableBox<String>>()) 311 } 312 313 assertFailsWithMessage<SerializationException>("for class 'NonSerializable'") { 314 serializer(typeOf<Box<NonSerializable>>()) 315 } 316 } 317 318 private inline fun <reified T> assertSerializedWithType( 319 expected: String, 320 value: T, 321 json: StringFormat = default 322 ) { 323 val serial = serializer<T>() 324 assertEquals(expected, json.encodeToString(serial, value)) 325 val serial2 = requireNotNull(serializerOrNull(typeOf<T>())) { "Expected serializer to be found" } 326 assertEquals(expected, json.encodeToString(serial2, value)) 327 } 328 329 @Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") 330 inline fun <T> KSerializer<*>.cast(): KSerializer<T> = this as KSerializer<T> 331 332 } 333