1
+ /*
2
+ * Copyright 2017-2024 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.descriptors.*
8
+ import kotlinx.serialization.encoding.*
9
+ import kotlinx.serialization.json.*
10
+ import kotlin.jvm.*
11
+ import kotlin.test.*
12
+
13
+ class KeepGeneratedSerializerTest {
14
+ @Serializable(with = ValueSerializer ::class )
15
+ @KeepGeneratedSerializer
16
+ @JvmInline
17
+ value class Value (val i : Int )
18
+
19
+ object ValueSerializer: KSerializer<Value> {
20
+ override val descriptor = PrimitiveSerialDescriptor (" ValueSerializer" , PrimitiveKind .INT )
21
+ override fun deserialize (decoder : Decoder ): Value {
22
+ val value = decoder.decodeInt()
23
+ return Value (value - 42 )
24
+ }
25
+ override fun serialize (encoder : Encoder , value : Value ) {
26
+ encoder.encodeInt(value.i + 42 )
27
+ }
28
+ }
29
+
30
+ @Test
31
+ fun testValueClass () {
32
+ test(Value (1 ), " 43" , " 1" , Value .serializer(), Value .generatedSerializer())
33
+ }
34
+
35
+
36
+
37
+ @Serializable(with = DataSerializer ::class )
38
+ @KeepGeneratedSerializer
39
+ data class Data (val i : Int )
40
+
41
+ object DataSerializer: KSerializer<Data> {
42
+ override val descriptor = PrimitiveSerialDescriptor (" DataSerializer" , PrimitiveKind .INT )
43
+ override fun deserialize (decoder : Decoder ): Data {
44
+ val value = decoder.decodeInt()
45
+ return Data (value)
46
+ }
47
+ override fun serialize (encoder : Encoder , value : Data ) {
48
+ encoder.encodeInt(value.i)
49
+ }
50
+ }
51
+
52
+ @Test
53
+ fun testDataClass () {
54
+ test(Data (2 ), " 2" , " {\" i\" :2}" , Data .serializer(), Data .generatedSerializer())
55
+ }
56
+
57
+
58
+ @Serializable(with = ParentSerializer ::class )
59
+ @KeepGeneratedSerializer
60
+ open class Parent (val p : Int ) {
61
+ override fun equals (other : Any? ): Boolean {
62
+ if (this == = other) return true
63
+ if (other !is Parent ) return false
64
+
65
+ if (p != other.p) return false
66
+
67
+ return true
68
+ }
69
+
70
+ override fun hashCode (): Int {
71
+ return p
72
+ }
73
+ }
74
+
75
+ object ParentSerializer: KSerializer<Parent> {
76
+ override val descriptor = PrimitiveSerialDescriptor (" ParentSerializer" , PrimitiveKind .INT )
77
+ override fun deserialize (decoder : Decoder ): Parent {
78
+ val value = decoder.decodeInt()
79
+ return Parent (value - 1 )
80
+ }
81
+ override fun serialize (encoder : Encoder , value : Parent ) {
82
+ encoder.encodeInt(value.p + 1 )
83
+ }
84
+ }
85
+
86
+ @Serializable
87
+ data class Child (val c : Int ): Parent(0 )
88
+
89
+ @Serializable(with = ChildSerializer ::class )
90
+ @KeepGeneratedSerializer
91
+ data class ChildWithCustom (val c : Int ): Parent(0 )
92
+
93
+ object ChildSerializer: KSerializer<ChildWithCustom> {
94
+ override val descriptor = PrimitiveSerialDescriptor (" ChildSerializer" , PrimitiveKind .INT )
95
+ override fun deserialize (decoder : Decoder ): ChildWithCustom {
96
+ val value = decoder.decodeInt()
97
+ return ChildWithCustom (value - 2 )
98
+ }
99
+
100
+ override fun serialize (encoder : Encoder , value : ChildWithCustom ) {
101
+ encoder.encodeInt(value.c + 2 )
102
+ }
103
+ }
104
+
105
+ @Test
106
+ fun testInheritance () {
107
+ test(Parent (3 ), " 4" , " {\" p\" :3}" , Parent .serializer(), Parent .generatedSerializer())
108
+ test(Child (4 ), " {\" p\" :0,\" c\" :4}" , " " , Child .serializer(), null )
109
+ test(ChildWithCustom (5 ), " 7" , " {\" p\" :0,\" c\" :5}" , ChildWithCustom .serializer(), ChildWithCustom .generatedSerializer())
110
+ }
111
+
112
+
113
+ @Serializable(with = MyEnumSerializer ::class )
114
+ @KeepGeneratedSerializer
115
+ enum class MyEnum {
116
+ A ,
117
+ B ,
118
+ FALLBACK
119
+ }
120
+
121
+ @Serializable
122
+ data class EnumHolder (val e : MyEnum )
123
+
124
+ object MyEnumSerializer: KSerializer<MyEnum> {
125
+ val defaultSerializer = MyEnum .generatedSerializer()
126
+
127
+ override val descriptor = PrimitiveSerialDescriptor (" MyEnumSerializer" , PrimitiveKind .INT )
128
+
129
+ override fun deserialize (decoder : Decoder ): MyEnum {
130
+ decoder.decodeString()
131
+ return MyEnum .A
132
+ }
133
+
134
+ override fun serialize (encoder : Encoder , value : MyEnum ) {
135
+ // always encode FALLBACK entry by generated serializer
136
+ defaultSerializer.serialize(encoder, MyEnum .FALLBACK )
137
+ }
138
+ }
139
+
140
+ @Test
141
+ fun testEnum () {
142
+ test(MyEnum .A , " \" FALLBACK\" " , " \" A\" " , MyEnum .serializer(), MyEnum .generatedSerializer())
143
+ assertTrue(serializer<MyEnum >() is MyEnumSerializer , " serializer<MyEnum> illegal = " + serializer<MyEnum >())
144
+ assertTrue(MyEnum .serializer() is MyEnumSerializer , " MyEnum.serializer() illegal = " + MyEnum .serializer())
145
+ assertEquals(" kotlinx.serialization.internal.EnumSerializer<kotlinx.serialization.KeepGeneratedSerializerTest.MyEnum>" , MyEnum .generatedSerializer().toString(), " MyEnum.generatedSerializer() illegal" )
146
+ assertSame(MyEnum .generatedSerializer(), MyEnum .generatedSerializer(), " MyEnum.generatedSerializer() instance differs" )
147
+ }
148
+
149
+
150
+ @Serializable(with = ParametrizedSerializer ::class )
151
+ @KeepGeneratedSerializer
152
+ data class ParametrizedData <T >(val t : T )
153
+
154
+ class ParametrizedSerializer (val serializer : KSerializer <Any >): KSerializer<ParametrizedData<Any>> {
155
+ override val descriptor = PrimitiveSerialDescriptor (" ParametrizedSerializer" , PrimitiveKind .INT )
156
+
157
+ override fun deserialize (decoder : Decoder ): ParametrizedData <Any > {
158
+ val value = serializer.deserialize(decoder)
159
+ return ParametrizedData (value)
160
+ }
161
+
162
+ override fun serialize (encoder : Encoder , value : ParametrizedData <Any >) {
163
+ serializer.serialize(encoder, value.t)
164
+ }
165
+ }
166
+
167
+ @Test
168
+ fun testParametrized () {
169
+ test(
170
+ ParametrizedData <Data >(Data (6 )), " 6" , " {\" t\" :6}" , ParametrizedData .serializer(Data .serializer()), ParametrizedData .generatedSerializer(
171
+ Data .serializer()))
172
+ }
173
+
174
+
175
+ @Serializable(WithCompanion .Companion ::class )
176
+ @KeepGeneratedSerializer
177
+ data class WithCompanion (val value : Int ) {
178
+ @Serializer(WithCompanion ::class )
179
+ companion object {
180
+ override val descriptor = PrimitiveSerialDescriptor (" WithCompanionDesc" , PrimitiveKind .INT )
181
+ override fun deserialize (decoder : Decoder ): WithCompanion {
182
+ val value = decoder.decodeInt()
183
+ return WithCompanion (value)
184
+ }
185
+
186
+ override fun serialize (encoder : Encoder , value : WithCompanion ) {
187
+ encoder.encodeInt(value.value)
188
+ }
189
+ }
190
+ }
191
+
192
+ @Test
193
+ fun testCompanion () {
194
+ test(WithCompanion (7 ), " 7" , " {\" value\" :7}" , WithCompanion .serializer(), WithCompanion .generatedSerializer())
195
+ }
196
+
197
+
198
+ @Serializable(with = ObjectSerializer ::class )
199
+ @KeepGeneratedSerializer
200
+ object Object
201
+
202
+ object ObjectSerializer: KSerializer<Object> {
203
+ override val descriptor = PrimitiveSerialDescriptor (" ObjectSerializer" , PrimitiveKind .INT )
204
+
205
+ override fun deserialize (decoder : Decoder ): Object {
206
+ decoder.decodeInt()
207
+ return Object
208
+ }
209
+ override fun serialize (encoder : Encoder , value : Object ) {
210
+ encoder.encodeInt(8 )
211
+ }
212
+ }
213
+
214
+ @Test
215
+ fun testObject () {
216
+ test(Object , " 8" , " {}" , Object .serializer(), Object .generatedSerializer())
217
+ assertEquals(" kotlinx.serialization.KeepGeneratedSerializerTest.Object()" , Object .generatedSerializer().descriptor.toString(), " Object.generatedSerializer() illegal" )
218
+ assertSame(Object .generatedSerializer(), Object .generatedSerializer(), " Object.generatedSerializer() instance differs" )
219
+ }
220
+
221
+
222
+
223
+ inline fun <reified T : Any > test (
224
+ value : T ,
225
+ customJson : String ,
226
+ keepJson : String ,
227
+ serializer : KSerializer <T >,
228
+ generatedSerializer : KSerializer <T >?
229
+ ) {
230
+ val implicitJson = Json .encodeToString(value)
231
+ assertEquals(customJson, implicitJson, " Json.encodeToString(value: ${T ::class .simpleName} )" )
232
+ val implicitDecoded = Json .decodeFromString<T >(implicitJson)
233
+ assertEquals(value, implicitDecoded, " Json.decodeFromString(json): ${T ::class .simpleName} " )
234
+
235
+ val exlicitJson = Json .encodeToString(serializer, value)
236
+ assertEquals(customJson, exlicitJson, " Json.encodeToString(${T ::class .simpleName} .serializer(), value)" )
237
+ val explicitDecoded = Json .decodeFromString(serializer, exlicitJson)
238
+ assertEquals(value, explicitDecoded, " Json.decodeFromString(${T ::class .simpleName} .serializer(), json)" )
239
+
240
+ if (generatedSerializer == null ) return
241
+ val keep = Json .encodeToString(generatedSerializer, value)
242
+ assertEquals(keepJson, keep, " Json.encodeToString(${T ::class .simpleName} .generatedSerializer(), value)" )
243
+ val keepDecoded = Json .decodeFromString(generatedSerializer, keep)
244
+ assertEquals(value, keepDecoded, " Json.decodeFromString(${T ::class .simpleName} .generatedSerializer(), json)" )
245
+ }
246
+
247
+ }
0 commit comments