Дает ли этот набор методов расширения то, что вы хотите?
@ImplicitReflectionSerializer
fun Map<*, *>.toJson() = Json.stringify(toJsonObject())
@ImplicitReflectionSerializer
fun Map<*, *>.toJsonObject(): JsonObject = JsonObject(map {
it.key.toString() to it.value.toJsonElement()
}.toMap())
@ImplicitReflectionSerializer
fun Any?.toJsonElement(): JsonElement = when (this) {
null -> JsonNull
is Number -> JsonPrimitive(this)
is String -> JsonPrimitive(this)
is Boolean -> JsonPrimitive(this)
is Map<*, *> -> this.toJsonObject()
is Iterable<*> -> JsonArray(this.map { it.toJsonElement() })
is Array<*> -> JsonArray(this.map { it.toJsonElement() })
else -> JsonPrimitive(this.toString()) // Or throw some "unsupported" exception?
}
Это позволяет вам передавать Map
с различными типами ключей / значений в нем и возвращать его в JSON-представлении. На карте каждое значение может быть примитивом (строка, число или логическое значение), нулем, другой картой (представляющей дочерний узел в JSON) или массивом или коллекцией любого из вышеперечисленного.
Вы можете назвать это следующим образом:
val json = mapOf(
"Album" to "Sergeant Pepper",
"Year" to 1967,
"TestNullValue" to null,
"Musicians" to mapOf(
"John" to arrayOf("Guitar", "Vocals"),
"Paul" to arrayOf("Bass", "Guitar", "Vocals"),
"George" to arrayOf("Guitar", "Sitar", "Vocals"),
"Ringo" to arrayOf("Drums")
)
).toJson()
Возвращает следующий JSON, без предварительного подтверждения, как вы хотели:
{"Album":"Sergeant Pepper","Year":1967,"TestNullValue":null,"Musicians":{"John":["Guitar","Vocals"],"Paul":["Bass","Guitar","Vocals"],"George":["Guitar","Sitar","Vocals"],"Ringo":["Drums"]}}
Возможно, вы также хотите добавить обработку для некоторых других типов, например, даты.
Но могу ли я просто проверить, что вы хотите вручную создать JSON в коде, а не создавать классы данных для всех ваших структур JSON и сериализовывать их таким образом? Я думаю, что это обычно более стандартный способ обработки такого рода вещей. Хотя, возможно, ваш вариант использования этого не позволяет.
Также ничего не стоит, чтобы код использовал аннотацию ImplicitReflectionSerializer
, так как он использует отражение, чтобы выяснить, какой сериализатор использовать для каждого бита. Это все еще экспериментальная функциональность, которая может измениться в будущем.