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