Using kotlinx.serialization utilities for construc...
# serialization
s
Using kotlinx.serialization utilities for constructing JSON representations, I wonder, I got an incoming type with the signature
Map<String, Any?>
and I want to turn it into JSON to then pass somewhere else. With the type-safe builders I only see that I can do stuff like
put(key:Any, value: JsonElement)
but I don’t know how to turn my
Any? -> JsonElement
. I can do stuff like
Copy code
fun Any.toJsonElement() : JsonElement {
  when(this) {
    is Map<*, *> -> ...
    is Collection<*> -> ...
  }
}
and so on but I’ll most definitely do it wrong so I was looking if there’s some API I’m missing here.
m
You could do this I think:
Copy code
val jsonConfig = Json() // Add any configuration here if you want.
val element = jsonConfig.encodeToJsonElement(map)
s
Yeah tried that but I get
Serializer for class 'Any' is not found.
Whipped this up real quick
Copy code
internal fun Any?.toJsonElement(): JsonElement {
    return when (this) {
        null -> JsonNull
        is String -> JsonPrimitive(this)
        is Boolean -> JsonPrimitive(this)
        is Int -> JsonPrimitive(this)
        is Long -> JsonPrimitive(this)
        is Double -> JsonPrimitive(this)
        is List<*> -> {
            buildJsonArray {
                for (value in this@toJsonElement) {
                    add(value.toJsonElement())
                }
            }
        }

        is Map<*, *> -> {
            buildJsonObject {
                for ((key, value) in this@toJsonElement as Map<String, *>) {
                    put(key, value.toJsonElement())
                }
            }
        }

        else -> error("Unsupported Any? -> JsonElement conversion for value: '$this' of type: '${this::class}'")
    }
}
Heavily inspired from apollo-kotlin but I can’t help but think there must be a better way to do this when I can’t simply annotate my stuff with
@Serializable
since the incoming data is unstructured.
e
as there's no way to handle
Any
safely, I doubt it'll be added kotlinx.serialization.json. https://github.com/Kotlin/kotlinx.serialization/issues/296
s
Yeah as I see there’s people just doing the same-ish implementation basically to at least replicate this as closely as possible. I think I’ll just go with this for the time being as I feel like it’s fulfilling my current needs
Copy code
internal fun Any?.toJsonElement(): JsonElement {
  return when (this) {
    null -> JsonNull
    is String -> JsonPrimitive(this)
    is Boolean -> JsonPrimitive(this)
    is Number -> JsonPrimitive(this)
    is Iterable<*> -> buildJsonArray {
      for (value in this@toJsonElement) {
        add(value.toJsonElement())
      }
    }
    is Map<*, *> -> buildJsonObject {
      for ((key, value) in this@toJsonElement) {
        put(key.toString(), value.toJsonElement())
      }
    }
    else -> error("Unsupported Any? -> JsonElement conversion for value: '$this' of type: '${this::class}'")
  }
}
I sort of understand why it’s not there, but also have to deal with the fact that we do get some data as just “Any?” and we have to deal with it 🤷‍♂️
r
I sort of understand why it’s not there, but also have to deal with the fact that we do get some data as just “Any?” and we have to deal with it 🤷‍♂️
I've grumbled about this in the past. I understand why they don't do it, but I really don't think leaving people to develop their own ad-hoc subpar implementations is actually making things safer. https://kotlinlang.slack.com/archives/C7A1U5PTM/p1637210163135100?thread_ts=1637204827.132800&amp;cid=C7A1U5PTM
s
Ah thanks for sharing this thread. Yeah so many interesting thoughts in there, and I sort of agree that in the end what happens is that we all end up with some sort of weird implementation (just like I did) which isn't even consistent with each other. Because the problem is never solved this way, we just pretend it doesn't exist until we then have to deal with it with hacks 😅
e
it's possible to create a format which will serialize anything (including
JsonElement
) to a
Map<String, Any?>
and vice-versa. complete overkill, though.