Hi, all I’ve a java rpc library that take data as...
# server
t
Hi, all I’ve a java rpc library that take data as Map<String, Obect> and return as the same type. I try to convert it to data class to make code readable. I’m finding a solution to serialize a map to object and deserialize it. Currently I found that we can use json convert object to the json and deserialize to map. But it quite a bit tricky. 🫥 I also found that kotlinx serialization has properties data serialization but the limitation is it convert nested object to flat key. 😢 Does anyone found this similar issue? How do you solve it?
r
Jackson can turn a
Map<String, Object>
into a data class without turning it into JSON as an intermediate: https://stackoverflow.com/questions/16428817/convert-a-mapstring-string-to-a-pojo
🙇‍♂️ 1
t
Wow. Look interesting. 🙏
e
you could use the generated kotlinx.serialization serializers and replace Json with your own format, e.g. https://github.com/ephemient/kotlinx-serialization-contrib/blob/main/json-java/src/commonJvmMain/kotlin/JSON.kt
🙇‍♂️ 1
but it'll be easier to (unsafely) map between
JsonObject
and
Map<String, Object>
j
Why not just do it in code? What was the constraint that made you think of going via json?
t
@James Richardson my current implementation is converting it field by field from object. It’s quite huge task and boring (legacy system have 80 fields per rpc method, not fun). So i start looking serialization tp help me convert it easier. The json conversion method look solve the problem but it seem to have overhead because of json encode/decode. So I try to find another ways for this solution.
Writing encoder/decoder on kotlinx serialzation looks interesting but it seems they have a little bit details on writing custom serialization
j
It might be boring sure. I was wondering though, are the names of the fields the same? What about the types? Do you use strong types in your system? Are you importing the types from the rpc code into your code? It might well be that you could just do it yourself with reflection, or perhaps if everything is different, it might be really just as easy to do it in code, else you'll just have to map the fields anyway... and then you'll have to use somebody else's annotations etc.
👍 1
e
the conversion between
JsonElement
and "`Object` that is primitive or string or list or map" is pretty straightforward,
Copy code
fun JsonElement.toObject(): Any? = when (this) {
    is JsonPrimitive -> booleanOrNull ?: intOrNull ?: longOrNull ?: doubleOrNull ?: contentOrNull
    is JsonArray -> map { it.toObject() }
    is JsonObject -> mapValues { it.value.toObject() }
}

@Suppress("UNCHECKED_CAST")
fun Any?.toJson(): JsonElement = when (this) {
    null -> JsonNull
    is Boolean -> JsonPrimitive(this)
    is Number -> JsonPrimitive(this)
    is String -> JsonPrimitive(this)
    is Iterable<*> -> buildJsonArray {
        forEach { add(it.toJson()) }
    }
    is Map<*, *> -> buildJsonObject {
        forEach { put(it.key as String, it.value.toJson()) }
    }
    else -> throw IllegalArgumentException()
}