• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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