22
33package com.segment.analytics.kotlin.core.utilities
44
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
516import kotlinx.serialization.json.Json
617import kotlinx.serialization.json.JsonArray
718import kotlinx.serialization.json.JsonElement
19+ import kotlinx.serialization.json.JsonNull
820import kotlinx.serialization.json.JsonObject
921import kotlinx.serialization.json.JsonObjectBuilder
1022import kotlinx.serialization.json.JsonPrimitive
@@ -17,6 +29,7 @@ import kotlinx.serialization.json.intOrNull
1729import kotlinx.serialization.json.jsonObject
1830import kotlinx.serialization.json.longOrNull
1931import kotlinx.serialization.json.put
32+ import kotlin.reflect.KClass
2033
2134val EncodeDefaultsJson = Json {
2235 encodeDefaults = true
@@ -204,4 +217,207 @@ operator fun MutableMap<String, JsonElement>.set(key:String, value: Number) {
204217
205218operator fun MutableMap <String , JsonElement >.set (key : String , value : Boolean ) {
206219 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
207423}
0 commit comments