@@ -13,60 +13,348 @@ import kotlin.test.*
13
13
class ReorderingCompositeEncoderTest {
14
14
@Test
15
15
fun shouldReorderWell () {
16
- val first = 42
17
- val second = " string"
18
- val third = true
19
- val value = OuterToBeReordered (Middle (Inner (second, third)), first)
16
+ val value = AllTypesExample (
17
+ int = 1 ,
18
+ nullableInt = null ,
19
+ intWrapped = IntValue (2 ),
20
+ nullableIntWrapped = IntNullableValue (null ),
21
+ intWrappedNullable = IntValue (3 ),
20
22
21
- val encoder = ReorderingEncoder ().apply {
22
- encodeSerializableValue(OuterToBeReordered .serializer(), value)
23
- }
23
+ string = " Hello" ,
24
+ nullableString = null ,
25
+ stringWrapped = StringValue (" World" ),
26
+ nullableStringWrapped = StringNullableValue (null ),
27
+ stringWrappedNullable = StringValue (" !!!" ),
28
+
29
+ boolean = true ,
30
+ nullableBoolean = null ,
31
+ booleanWrapped = BooleanValue (true ),
32
+ nullableBooleanWrapped = BooleanNullableValue (null ),
33
+ booleanWrappedNullable = BooleanValue (false ),
34
+
35
+ double = 1.0 ,
36
+ nullableDouble = null ,
37
+ doubleWrapped = DoubleValue (2.0 ),
38
+ nullableDoubleWrapped = DoubleNullableValue (null ),
39
+ doubleWrappedNullable = DoubleValue (3.0 ),
40
+
41
+ nonReorderedList = listOf (1 , 2 , 3 ),
42
+ nonReorderedNullableList = null ,
43
+ nonReorderedListWrapped = ListValue (listOf (4 , 5 , 6 )),
44
+ nonReorderedNullableListWrapped = ListNullableValue (null ),
45
+ nonReorderedListWrappedNullable = ListNullableValue (listOf (7 , 8 , 9 )),
46
+ nonReorderedListWrappedNullableValues = ListNullableValues (listOf (null , 8 , 9 )),
47
+
48
+ float = 1.0f ,
49
+ nullableFloat = null ,
50
+ floatWrapped = FloatValue (2.0f ),
51
+ nullableFloatWrapped = FloatNullableValue (null ),
52
+ floatWrappedNullable = FloatValue (3.0f ),
53
+
54
+ long = 1L ,
55
+ nullableLong = null ,
56
+ longWrapped = LongValue (2L ),
57
+ nullableLongWrapped = LongNullableValue (null ),
58
+ longWrappedNullable = LongValue (3L ),
59
+
60
+ short = 1 ,
61
+ nullableShort = null ,
62
+ shortWrapped = ShortValue (2 ),
63
+ nullableShortWrapped = ShortNullableValue (null ),
64
+ shortWrappedNullable = ShortValue (3 ),
65
+
66
+ nonReorderedSubStructure = SubStructure (
67
+ a = IntValue (10 ),
68
+ b = " Sub" ,
69
+ c = null ,
70
+ d = null
71
+ ),
72
+ nonReorderedNullableSubStructure = null ,
73
+ nonReorderedSubStructureWrapped = SubStructureValue (
74
+ SubStructure (
75
+ a = IntValue (11 ),
76
+ b = " Wrapped" ,
77
+ c = 12L ,
78
+ d = 13 .toByte()
79
+ )
80
+ ),
81
+ nonReorderedNullableSubStructureWrapped = SubStructureNullableValue (null ),
82
+ nonReorderedSubStructureWrappedNullable = SubStructureValue (
83
+ SubStructure (
84
+ a = IntValue (14 ),
85
+ b = " Nullable Wrapped" ,
86
+ c = 15L ,
87
+ d = 16 .toByte()
88
+ )
89
+ ),
90
+
91
+ byte = 1 ,
92
+ nullableByte = null ,
93
+ byteWrapped = ByteValue (2 ),
94
+ nullableByteWrapped = ByteNullableValue (null ),
95
+ byteWrappedNullable = ByteValue (3 ),
24
96
25
- assertContentEquals(actual = encoder.encodedValues, expected = listOf (first, second, third))
97
+ char = ' A' ,
98
+ nullableChar = null ,
99
+ charWrapped = CharValue (' B' ),
100
+ nullableCharWrapped = CharNullableValue (null ),
101
+ charWrappedNullable = CharValue (' C' )
102
+ )
103
+
104
+ val output = StringBuilder ()
105
+ val encoder = LightJsonEncoder (
106
+ output,
107
+ descriptorToReorder = AllTypesExample .serializer().descriptor
108
+ ) { descriptor, index -> descriptor.elementsCount - 1 - index }
109
+
110
+ encoder.encodeSerializableValue(AllTypesExample .serializer(), value)
111
+
112
+ // the final output should encode the fields in the reverse order, but should not reorder sub-structures
113
+ assertEquals(
114
+ actual = output.toString(),
115
+ expected = """
116
+ {charWrappedNullable:"C", nullableCharWrapped:null, charWrapped:"B", nullableChar:null, char:"A", byteWrappedNullable:3, nullableByteWrapped:null, byteWrapped:2, nullableByte:null, byte:1, nonReorderedSubStructureWrappedNullable:{a:14, b:"Nullable Wrapped", c:15, d:16}, nonReorderedNullableSubStructureWrapped:null, nonReorderedSubStructureWrapped:{a:11, b:"Wrapped", c:12, d:13}, nonReorderedNullableSubStructure:null, nonReorderedSubStructure:{a:10, b:"Sub", c:null, d:null}, shortWrappedNullable:3, nullableShortWrapped:null, shortWrapped:2, nullableShort:null, short:1, longWrappedNullable:3, nullableLongWrapped:null, longWrapped:2, nullableLong:null, long:1, floatWrappedNullable:3.0, nullableFloatWrapped:null, floatWrapped:2.0, nullableFloat:null, float:1.0, nonReorderedListWrappedNullableValues:[0:null, 1:8, 2:9], nonReorderedListWrappedNullable:[0:7, 1:8, 2:9], nonReorderedNullableListWrapped:null, nonReorderedListWrapped:[0:4, 1:5, 2:6], nonReorderedNullableList:null, nonReorderedList:[0:1, 1:2, 2:3], doubleWrappedNullable:3.0, nullableDoubleWrapped:null, doubleWrapped:2.0, nullableDouble:null, double:1.0, booleanWrappedNullable:false, nullableBooleanWrapped:null, booleanWrapped:true, nullableBoolean:null, boolean:true, stringWrappedNullable:"!!!", nullableStringWrapped:null, stringWrapped:"World", nullableString:null, string:"Hello", intWrappedNullable:3, nullableIntWrapped:null, intWrapped:2, nullableInt:null, int:1}
117
+ """ .trimIndent(),
118
+ )
26
119
}
120
+ }
27
121
28
- private class ReorderingEncoder (
29
- val encodedValues : MutableList <Any ?> = mutableListOf()
30
- ) : AbstractEncoder() {
31
- override val serializersModule: SerializersModule
32
- get() = EmptySerializersModule ()
122
+ @Serializable
123
+ data class AllTypesExample (
124
+ val int : Int ,
125
+ val nullableInt : Int? ,
126
+ val intWrapped : IntValue ,
127
+ val nullableIntWrapped : IntNullableValue ,
128
+ val intWrappedNullable : IntValue ? ,
33
129
34
- override fun encodeValue (value : Any ) {
35
- encodedValues.add(value)
36
- }
130
+ val string : String ,
131
+ val nullableString : String? ,
132
+ val stringWrapped : StringValue ,
133
+ val nullableStringWrapped : StringNullableValue ,
134
+ val stringWrappedNullable : StringValue ? ,
135
+
136
+ val boolean : Boolean ,
137
+ val nullableBoolean : Boolean? ,
138
+ val booleanWrapped : BooleanValue ,
139
+ val nullableBooleanWrapped : BooleanNullableValue ,
140
+ val booleanWrappedNullable : BooleanValue ? ,
141
+
142
+ val double : Double ,
143
+ val nullableDouble : Double? ,
144
+ val doubleWrapped : DoubleValue ,
145
+ val nullableDoubleWrapped : DoubleNullableValue ,
146
+ val doubleWrappedNullable : DoubleValue ? ,
147
+
148
+ val nonReorderedList : List <Int >,
149
+ val nonReorderedNullableList : List <Int >? ,
150
+ val nonReorderedListWrapped : ListValue ,
151
+ val nonReorderedNullableListWrapped : ListNullableValue ,
152
+ val nonReorderedListWrappedNullable : ListNullableValue ? ,
153
+ val nonReorderedListWrappedNullableValues : ListNullableValues ? ,
154
+
155
+ val float : Float ,
156
+ val nullableFloat : Float? ,
157
+ val floatWrapped : FloatValue ,
158
+ val nullableFloatWrapped : FloatNullableValue ,
159
+ val floatWrappedNullable : FloatValue ? ,
160
+
161
+ val long : Long ,
162
+ val nullableLong : Long? ,
163
+ val longWrapped : LongValue ,
164
+ val nullableLongWrapped : LongNullableValue ,
165
+ val longWrappedNullable : LongValue ? ,
166
+
167
+ val short : Short ,
168
+ val nullableShort : Short? ,
169
+ val shortWrapped : ShortValue ,
170
+ val nullableShortWrapped : ShortNullableValue ,
171
+ val shortWrappedNullable : ShortValue ? ,
172
+
173
+ val nonReorderedSubStructure : SubStructure ,
174
+ val nonReorderedNullableSubStructure : SubStructure ? ,
175
+ val nonReorderedSubStructureWrapped : SubStructureValue ,
176
+ val nonReorderedNullableSubStructureWrapped : SubStructureNullableValue ,
177
+ val nonReorderedSubStructureWrappedNullable : SubStructureValue ? ,
178
+
179
+ val byte : Byte ,
180
+ val nullableByte : Byte? ,
181
+ val byteWrapped : ByteValue ,
182
+ val nullableByteWrapped : ByteNullableValue ,
183
+ val byteWrappedNullable : ByteValue ? ,
184
+
185
+ val char : Char ,
186
+ val nullableChar : Char? ,
187
+ val charWrapped : CharValue ,
188
+ val nullableCharWrapped : CharNullableValue ,
189
+ val charWrappedNullable : CharValue ? ,
190
+ )
191
+
192
+ @Serializable
193
+ data class SubStructure (
194
+ val a : IntValue ,
195
+ val b : String ,
196
+ val c : Long? ,
197
+ val d : Byte? ,
198
+ )
199
+
200
+ @Serializable
201
+ @JvmInline
202
+ value class IntValue (val value : Int )
203
+
204
+ @Serializable
205
+ @JvmInline
206
+ value class StringValue (val value : String )
207
+
208
+ @Serializable
209
+ @JvmInline
210
+ value class BooleanValue (val value : Boolean )
211
+
212
+ @Serializable
213
+ @JvmInline
214
+ value class DoubleValue (val value : Double )
215
+
216
+ @Serializable
217
+ @JvmInline
218
+ value class FloatValue (val value : Float )
219
+
220
+ @Serializable
221
+ @JvmInline
222
+ value class LongValue (val value : Long )
223
+
224
+ @Serializable
225
+ @JvmInline
226
+ value class ShortValue (val value : Short )
227
+
228
+ @Serializable
229
+ @JvmInline
230
+ value class ByteValue (val value : Byte )
231
+
232
+ @Serializable
233
+ @JvmInline
234
+ value class CharValue (val value : Char )
37
235
38
- override fun encodeNull () {
39
- encodedValues.add(null )
236
+ @Serializable
237
+ @JvmInline
238
+ value class SubStructureValue (val value : SubStructure )
239
+
240
+ @Serializable
241
+ @JvmInline
242
+ value class ListValue (val value : List <Int >)
243
+
244
+
245
+
246
+
247
+
248
+ @Serializable
249
+ @JvmInline
250
+ value class IntNullableValue (val value : Int? )
251
+
252
+ @Serializable
253
+ @JvmInline
254
+ value class StringNullableValue (val value : String? )
255
+
256
+ @Serializable
257
+ @JvmInline
258
+ value class BooleanNullableValue (val value : Boolean? )
259
+
260
+ @Serializable
261
+ @JvmInline
262
+ value class DoubleNullableValue (val value : Double? )
263
+
264
+ @Serializable
265
+ @JvmInline
266
+ value class FloatNullableValue (val value : Float? )
267
+
268
+ @Serializable
269
+ @JvmInline
270
+ value class LongNullableValue (val value : Long? )
271
+
272
+ @Serializable
273
+ @JvmInline
274
+ value class ShortNullableValue (val value : Short? )
275
+
276
+ @Serializable
277
+ @JvmInline
278
+ value class ByteNullableValue (val value : Byte? )
279
+
280
+ @Serializable
281
+ @JvmInline
282
+ value class CharNullableValue (val value : Char? )
283
+
284
+ @Serializable
285
+ @JvmInline
286
+ value class SubStructureNullableValue (val value : SubStructure ? )
287
+
288
+ @Serializable
289
+ @JvmInline
290
+ value class ListNullableValue (val value : List <Int >? )
291
+
292
+ @Serializable
293
+ @JvmInline
294
+ value class ListNullableValues (val value : List <Int ?>)
295
+
296
+
297
+
298
+
299
+
300
+ private class LightJsonEncoder (
301
+ val sb : StringBuilder ,
302
+ val descriptorToReorder : SerialDescriptor ,
303
+ val mapElementIndex : (SerialDescriptor , Int ) -> Int ,
304
+ ) : AbstractEncoder() {
305
+ override val serializersModule: SerializersModule = EmptySerializersModule ()
306
+ var previousDescriptor: SerialDescriptor ? = null
307
+
308
+ override fun beginStructure (descriptor : SerialDescriptor ): CompositeEncoder {
309
+ if (descriptor.kind == StructureKind .LIST ) {
310
+ sb.append(' [' )
311
+ } else {
312
+ sb.append(' {' )
313
+ }
314
+ previousDescriptor = null
315
+ if (descriptor == descriptorToReorder) {
316
+ return ReorderingCompositeEncoder (descriptor, this , mapElementIndex)
40
317
}
318
+ return this
319
+ }
41
320
42
- override fun beginStructure (descriptor : SerialDescriptor ): CompositeEncoder {
43
- return BasicCompositeEncoder ().encodeReorderingElements(descriptor ) { _, index ->
44
- // invert fields
45
- if (index == 0 ) 1 else 0
46
- }
321
+ override fun endStructure (descriptor : SerialDescriptor ) {
322
+ if (descriptor.kind == StructureKind . LIST ) {
323
+ sb.append( ' ] ' )
324
+ } else {
325
+ sb.append( ' } ' )
47
326
}
327
+ }
48
328
49
- private inner class BasicCompositeEncoder : AbstractEncoder () {
50
- override val serializersModule: SerializersModule
51
- get() = EmptySerializersModule ()
329
+ override fun encodeElement (descriptor : SerialDescriptor , index : Int ): Boolean {
330
+ if (previousDescriptor == null ) {
331
+ previousDescriptor = descriptor
332
+ } else {
333
+ previousDescriptor = descriptor
334
+ sb.append(" , " )
335
+ }
336
+ sb.append(descriptor.getElementName(index))
337
+ sb.append(' :' )
338
+ return true
339
+ }
52
340
53
- override fun encodeValue ( value : Any ) {
54
- encodedValues.add(value )
55
- }
341
+ override fun encodeNull ( ) {
342
+ sb.append( " null " )
343
+ }
56
344
57
- override fun encodeNull () {
58
- encodedValues.add(null )
59
- }
60
- }
345
+ override fun encodeValue (value : Any ) {
346
+ sb.append(value)
61
347
}
62
348
63
- @Serializable
64
- private data class OuterToBeReordered (val a : Middle , val b : Int )
349
+ override fun encodeString (value : String ) {
350
+ sb.append(' "' )
351
+ sb.append(value)
352
+ sb.append(' "' )
353
+ }
65
354
66
- @JvmInline
67
- @Serializable
68
- private value class Middle ( val i : Inner )
355
+ override fun encodeInline ( descriptor : SerialDescriptor ): Encoder {
356
+ return super .encodeInline(descriptor)
357
+ }
69
358
70
- @Serializable
71
- private data class Inner (val c : String , val d : Boolean )
359
+ override fun encodeChar (value : Char ) = encodeString(value.toString())
72
360
}
0 commit comments