2
2
3
3
package com.segment.analytics.kotlin.core.utilities
4
4
5
+ import kotlinx.serialization.ExperimentalSerializationApi
6
+ import kotlinx.serialization.KSerializer
7
+ import kotlinx.serialization.builtins.BooleanArraySerializer
8
+ import kotlinx.serialization.builtins.ByteArraySerializer
9
+ import kotlinx.serialization.builtins.CharArraySerializer
10
+ import kotlinx.serialization.builtins.DoubleArraySerializer
11
+ import kotlinx.serialization.builtins.FloatArraySerializer
12
+ import kotlinx.serialization.builtins.IntArraySerializer
13
+ import kotlinx.serialization.builtins.LongArraySerializer
14
+ import kotlinx.serialization.builtins.ShortArraySerializer
15
+ import kotlinx.serialization.builtins.serializer
5
16
import kotlinx.serialization.json.Json
6
17
import kotlinx.serialization.json.JsonArray
7
18
import kotlinx.serialization.json.JsonElement
19
+ import kotlinx.serialization.json.JsonNull
8
20
import kotlinx.serialization.json.JsonObject
9
21
import kotlinx.serialization.json.JsonObjectBuilder
10
22
import kotlinx.serialization.json.JsonPrimitive
@@ -17,6 +29,7 @@ import kotlinx.serialization.json.intOrNull
17
29
import kotlinx.serialization.json.jsonObject
18
30
import kotlinx.serialization.json.longOrNull
19
31
import kotlinx.serialization.json.put
32
+ import kotlin.reflect.KClass
20
33
21
34
val EncodeDefaultsJson = Json {
22
35
encodeDefaults = true
@@ -204,4 +217,207 @@ operator fun MutableMap<String, JsonElement>.set(key:String, value: Number) {
204
217
205
218
operator fun MutableMap <String , JsonElement >.set (key : String , value : Boolean ) {
206
219
this [key] = JsonPrimitive (value)
220
+ }
221
+
222
+
223
+ @OptIn(ExperimentalSerializationApi ::class , ExperimentalUnsignedTypes ::class )
224
+ val primitiveSerializers = mapOf (
225
+ String ::class to String .serializer(),
226
+ Char ::class to Char .serializer(),
227
+ CharArray ::class to CharArraySerializer (),
228
+ Double ::class to Double .serializer(),
229
+ DoubleArray ::class to DoubleArraySerializer (),
230
+ Float ::class to Float .serializer(),
231
+ FloatArray ::class to FloatArraySerializer (),
232
+ Long ::class to Long .serializer(),
233
+ LongArray ::class to LongArraySerializer (),
234
+ Int ::class to Int .serializer(),
235
+ IntArray ::class to IntArraySerializer (),
236
+ Short ::class to Short .serializer(),
237
+ ShortArray ::class to ShortArraySerializer (),
238
+ Byte ::class to Byte .serializer(),
239
+ ByteArray ::class to ByteArraySerializer (),
240
+ Boolean ::class to Boolean .serializer(),
241
+ BooleanArray ::class to BooleanArraySerializer (),
242
+ Unit ::class to Unit .serializer(),
243
+ UInt ::class to UInt .serializer(),
244
+ ULong ::class to ULong .serializer(),
245
+ UByte ::class to UByte .serializer(),
246
+ UShort ::class to UShort .serializer()
247
+ )
248
+
249
+ /* *
250
+ * Experimental API that can be used to convert primitive
251
+ * values to their equivalent JsonElement representation.
252
+ */
253
+ inline fun <reified T : Any > serializerFor (value : KClass <out T >): KSerializer <T >? {
254
+ val serializer = primitiveSerializers[value] ? : return null
255
+ return serializer as KSerializer <T >
256
+ }
257
+
258
+ /* *
259
+ * Experimental API that can be used to convert Map
260
+ * values to their equivalent JsonElement representation.
261
+ */
262
+ fun Map <String , Any >.toJsonElement (): JsonElement {
263
+ return buildJsonObject {
264
+ for ((key, value) in this @toJsonElement) {
265
+ if (value is JsonElement ) {
266
+ put(key, value)
267
+ } else {
268
+ put(key, value.toJsonElement())
269
+ }
270
+ }
271
+ }
272
+ }
273
+
274
+ /* *
275
+ * Experimental API that can be used to convert Array
276
+ * values to their equivalent JsonElement representation.
277
+ */
278
+ fun Array<Any>.toJsonElement (): JsonArray {
279
+ return buildJsonArray {
280
+ for (item in this @toJsonElement) {
281
+ if (item is JsonElement ) {
282
+ add(item)
283
+ } else {
284
+ add(item.toJsonElement())
285
+ }
286
+ }
287
+ }
288
+ }
289
+
290
+ /* *
291
+ * Experimental API that can be used to convert Collection
292
+ * values to their equivalent JsonElement representation.
293
+ */
294
+ fun Collection<Any>.toJsonElement (): JsonArray {
295
+ // Specifically chose Collection over Iterable, bcos
296
+ // Iterable is more widely overriden, whereas Collection
297
+ // is more in line with our target types eg: Lists, Sets etc
298
+ return buildJsonArray {
299
+ for (item in this @toJsonElement) {
300
+ if (item is JsonElement ) {
301
+ add(item)
302
+ } else {
303
+ add(item.toJsonElement())
304
+ }
305
+ }
306
+ }
307
+ }
308
+
309
+ /* *
310
+ * Experimental API that can be used to convert Pair
311
+ * values to their equivalent JsonElement representation.
312
+ */
313
+ fun Pair <Any , Any >.toJsonElement (): JsonElement {
314
+ val v1 = first.toJsonElement()
315
+ val v2 = second.toJsonElement()
316
+ return buildJsonObject {
317
+ put(" first" , v1)
318
+ put(" second" , v2)
319
+ }
320
+ }
321
+
322
+ /* *
323
+ * Experimental API that can be used to convert Triple
324
+ * values to their equivalent JsonElement representation.
325
+ */
326
+ fun Triple <Any , Any , Any >.toJsonElement (): JsonElement {
327
+ val v1 = first.toJsonElement()
328
+ val v2 = second.toJsonElement()
329
+ val v3 = third.toJsonElement()
330
+ return buildJsonObject {
331
+ put(" first" , v1)
332
+ put(" second" , v2)
333
+ put(" third" , v3)
334
+ }
335
+ }
336
+
337
+ /* *
338
+ * Experimental API that can be used to convert Map.Entry
339
+ * values to their equivalent JsonElement representation.
340
+ */
341
+ fun Map.Entry <Any , Any >.toJsonElement (): JsonElement {
342
+ val key = key.toJsonElement()
343
+ val value = value.toJsonElement()
344
+ return buildJsonObject {
345
+ put(" key" , key)
346
+ put(" value" , value)
347
+ }
348
+ }
349
+
350
+ /* *
351
+ * Experimental API that can be used to convert most kotlin
352
+ * primitive values to their equivalent JsonElement representation.
353
+ * Primitive here should mean any types declared in Kotlin SDK or JVM,
354
+ * and not brought in by an external library.
355
+ *
356
+ * Any unknown custom type will be representated as JsonNull
357
+ *
358
+ * Currently supported types
359
+ * - String
360
+ * - Char
361
+ * - CharArray
362
+ * - Double
363
+ * - DoubleArray
364
+ * - Float
365
+ * - FloatArray
366
+ * - Long
367
+ * - LongArray
368
+ * - Int
369
+ * - IntArray
370
+ * - Short
371
+ * - ShortArray
372
+ * - Byte
373
+ * - ByteArray
374
+ * - Boolean
375
+ * - BooleanArray
376
+ * - Unit
377
+ * - UInt
378
+ * - ULong
379
+ * - UByte
380
+ * - UShort
381
+ * - Collection<Any>
382
+ * - Map<String, Any>
383
+ * - Array<Any>
384
+ * - Pair<Any, Any>
385
+ * - Triple<Any, Any>
386
+ * - Map.Entry<Any, Any>
387
+ *
388
+ * Happy to accept more supported types in the future
389
+ */
390
+ fun Any.toJsonElement (): JsonElement {
391
+ when (this ) {
392
+ is Map <* , * > -> {
393
+ val value = this as Map <String , Any >
394
+ return value.toJsonElement()
395
+ }
396
+ is Array <* > -> {
397
+ val value = this as Array <Any >
398
+ return value.toJsonElement()
399
+ }
400
+ is Collection <* > -> {
401
+ val value = this as Collection <Any >
402
+ return value.toJsonElement()
403
+ }
404
+ is Pair <* , * > -> {
405
+ val value = this as Pair <Any , Any >
406
+ return value.toJsonElement()
407
+ }
408
+ is Triple <* , * , * > -> {
409
+ val value = this as Triple <Any , Any , Any >
410
+ return value.toJsonElement()
411
+ }
412
+ is Map .Entry <* , * > -> {
413
+ val value = this as Map .Entry <Any , Any >
414
+ return value.toJsonElement()
415
+ }
416
+ else -> {
417
+ serializerFor(this ::class )?.let {
418
+ return Json .encodeToJsonElement(it, this )
419
+ }
420
+ }
421
+ }
422
+ return JsonNull
207
423
}
0 commit comments