Kotlinx.Serializer - создайте быстрый JSON для отправки
Я играл с Kotlinx.serialisation. Я пытался найти быстрый способ использовать Kotlinx.serialisation для создания простого простого JSON (в основном, чтобы отправить его), с минимальным беспорядком кода.
Для простой строки, такой как:
{"Album": "Foxtrot", "Year": 1972}
Я делал что-то вроде:
val str:String = Json.stringify(mapOf(
"Album" to JsonPrimitive("Foxtrot"),
"Year" to JsonPrimitive(1972)))
Что далеко не приятно. Мои элементы в основном примитивны, поэтому я хотел бы иметь что-то вроде:
val str:String = Json.stringify(mapOf(
"Album" to "Sergeant Pepper",
"Year" to 1967))
Кроме того, я был бы рад иметь решение с вложенным JSON. Что-то вроде:
Json.stringify(JsonObject("Movies", JsonArray(
JsonObject("Name" to "Johnny English 3", "Rate" to 8),
JsonObject("Name" to "Grease", "Rate" to 1))))
Это даст:
{
"Movies": [
{
"Name":"Johnny English 3",
"Rate":8
},
{
"Name":"Grease",
"Rate":1
}
]
}
(не обязательно предварительно, даже лучше нет)
Есть что-нибудь подобное?
Примечание. Важно использовать сериализатор, а не прямую строку, такую как
"""{"Name":$name, "Val": $year}"""
потому что небезопасно объединять строки. Любой незаконный символ может разрушить JSON! Я не хочу иметь дело с побегом нелегальных символов:-(
Спасибо
1 ответ
Дает ли этот набор методов расширения то, что вы хотите?
@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
аннотации, поскольку она использует отражение, чтобы выяснить, какой сериализатор использовать для каждого бита. Это все еще экспериментальная функциональность, которая может измениться в будущем.