All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.pylons.lib.JsonModelSerializer.kt Maven / Gradle / Ivy

Go to download

Library providing common functionality for interacting with the Pylons ecosystem

The newest version!
package tech.pylons.lib

import com.beust.klaxon.Json
import com.beust.klaxon.JsonArray
import com.beust.klaxon.JsonObject
import kotlin.reflect.KProperty1
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties


object JsonModelSerializer {
    fun serialize (mode : SerializationMode, obj: Any?) : String {
        val jo = processObject(mode, obj)
        return jo?.toJsonString(
                prettyPrint = mode == SerializationMode.FOR_BROADCAST,
                canonical = true
        ).orEmpty().replace("{}", "null")
        // HACK! this is used to not serialize empty maps atm.
        // TODO: write proper map handling so we don't need Bullshit here
    }

    private fun processObject (mode : SerializationMode, obj: Any?) : JsonObject? {
        if (obj != null) {
            val kClass = obj::class
            val o = JsonObject()
            kClass.memberProperties.forEach { prop ->
                val json = prop.findAnnotation()
                if (json != null) {
                    var value = prop.getter.call(obj)
                    if (prop.returnType == String::class.java) value = value.toString()
                    when (prop.returnType.classifier) {
                        // HACK: klaxon's serialization of byte values is actually broken!
                        // We have to do this b/c if we just set value w/o doing the Bullshit
                        // it'll be serialized as... an empty object. Thanks, klaxon!
                        Byte::class -> o[json.name] = (value as Byte).toInt()
                        Int::class -> {
                            val q = prop.findAnnotation()
                            val n = prop.findAnnotation()
                            if ((q != null || mode == SerializationMode.FOR_BROADCAST) && n == null)
                                o[json.name] = (value as Int).toString()
                            else o[json.name] = value
                        }
                        Long::class -> {
                            val q = prop.findAnnotation()
                            val n = prop.findAnnotation()
                            if ((q != null || mode == SerializationMode.FOR_BROADCAST) && n == null)
                                o[json.name] = (value as Long).toString()
                            else o[json.name] = value
                        }
                        Number::class -> o[json.name] = value
                        Float::class -> o[json.name] = value
                        Double::class -> o[json.name] = value
                        Boolean::class -> o[json.name] = value
                        String::class -> o[json.name] = value
                        else -> o[json.name] = handleComplexValues(mode, prop, value)
                    }
                }
            }
            return o
        }
        else return null
    }

    private fun handleComplexValues (mode : SerializationMode, prop : KProperty1, value : Any?) : Any? {
        return when {
            value == null -> null
            Regex("kotlin.Array<.*>").matches(prop.returnType.toString()) -> handleArrays(mode, prop, value)
            Regex("kotlin.collections.List<.*>").matches(prop.returnType.toString()) -> handleLists(mode, prop, value)
            Regex("kotlin.collections.Map<.*>").matches(prop.returnType.toString()) -> handleMaps(mode, prop, value)
            else -> processObject(mode, value) // serialize nested object
        }
    }

    private fun  numeralArrayElement (mode: SerializationMode, it : T, q : QuotedJsonNumeral?, arr: JsonArray) {
        if (q != null && (q.serializationMode == SerializationMode.ALL || q.serializationMode == mode))
            arr.add(it.toString())
        else arr.add(it)
    }

    private fun handleArrays (mode : SerializationMode, prop : KProperty1, value : Any?) : JsonArray<*>? {
        if ((value as Array<*>).size == 0) return null
        else {
            val jsonArray = JsonArray()
            val q = prop.findAnnotation()
            when (prop.returnType.toString()) {
                "kotlin.Array" -> (value as Array).forEach { jsonArray.add(it) }
                "kotlin.Array" -> (value as Array).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.Array" -> (value as Array).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.Array" -> (value as Array).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.Array" -> (value as Array).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.Array" -> (value as Array).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.Array" -> (value as Array).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.Array" -> (value as Array).forEach { jsonArray.add(it) }
                else -> value.forEach { jsonArray.add(processObject(mode, it)) }
            }
            return jsonArray
        }
    }

    private fun handleLists (mode : SerializationMode, prop : KProperty1, value : Any?) : JsonArray<*>? {
        if ((value as List<*>).size == 0) {
            return if (prop.findAnnotation() != null) {
                JsonArray()
            } else {
                null
            }
        }
        else {
            val jsonArray = JsonArray()
            val q = prop.findAnnotation()
            when (prop.returnType.toString()) {
                "kotlin.collections.List" -> (value as List).forEach { jsonArray.add(it) }
                "kotlin.collections.List" -> (value as List).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.collections.List" -> (value as List).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.collections.List" -> (value as List).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.collections.List" -> (value as List).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.collections.List" -> (value as List).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.collections.List" -> (value as List).forEach { numeralArrayElement(mode, it, q, jsonArray) }
                "kotlin.collections.List" -> (value as List).forEach { jsonArray.add(it) }
                else -> value.forEach { jsonArray.add(processObject(mode, it)) }
            }
            return jsonArray
        }
    }

    private fun handleMaps(mode : SerializationMode, prop : KProperty1, value : Any?): JsonArray<*>? {
        if ((value as Map).size == 0) return null
        else {
            val jsonArray = JsonArray()
            val q = prop.findAnnotation()
            when (prop.returnType.toString()) {
                "kotlin.collections.Map" -> (value as Map).forEach {
                    val obj = JsonObject()
                    obj["Key"] = it.key

                    // broadcast has to be string format "1" while signing has to be number 1
                    obj["Value"] = if (mode == SerializationMode.FOR_BROADCAST) {
                        it.value.toString()
                    } else {
                        it.value
                    }

                    jsonArray.add(obj)
                }
                "kotlin.collections.Map" -> (value as Map).forEach {
                    val obj = JsonObject()
                    obj["Key"] = it.key
                    obj["Value"] = it.value
                    jsonArray.add(obj)
                }
                else -> value.forEach {
                    val obj = JsonObject()
                    obj["Key"] = it.key
                    obj["Value"] = if (q != null && (q.serializationMode == SerializationMode.ALL || q.serializationMode == mode)) {
                        it.value.toString()
                    } else {
                        it.value
                    }
                    jsonArray.add(obj)
                }
            }

            return if (jsonArray.isNotEmpty()) {
                jsonArray
            } else {
                // must return null for empty array
                null
            }

        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy