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