Сериализовать JSON строку как JSON объект - PullRequest
1 голос
/ 28 мая 2020

Я пишу собственный сериализатор для kotlin .serialization, который интерпретирует переменную JSON как строку независимо от ее типа. Десериализация работает нормально. Но у меня возникли проблемы с сериализацией String снова в исходную структуру.

На данный момент я просто десериализую значение как String. Но это добавляет дополнительные кавычки вокруг значения и приводит к проблемам.

Вот быстрый пример:

//
//Custom serializer:
//
object JsonToStringSerializer : KSerializer<String> {
    override val descriptor: SerialDescriptor = PrimitiveDescriptor("JsonToStringSerializer", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: String) {
        if(value.startsWith("[") || value.startsWith("{")) {
            encoder.encodeString(value) //<-- bad solution
            println("Oh no! Object has been turned into a String!")
        }
        else //will also encode Int, Float, Boolean, ... into String - but that is ok
            encoder.encodeString(value)
    }

    override fun deserialize(decoder: Decoder): String {
        val output = (decoder as JsonInput).decodeJson().toString()
        return if(output.startsWith("\""))
            output.substring(1, output.length-1)
        else output
    }
}

//
//Data structure for test:
//
@Serializable
class Test (
    @Serializable(with = JsonToStringSerializer::class) val objValue: String,
    val stringValue: String
)

//
//test logic:
//
fun test() {
    val jsonString = "{\"objValue\": [1,2], \"stringValue\": \"test\"}"
    val obj = Json(JsonConfiguration.Stable).parse(Test.serializer(), json)
    val newJsonString = Json(JsonConfiguration.Stable).stringify(Test.serializer(), obj)

    println(newJsonString)
    //expected result:  {"objValue": [1,2], "stringValue": "test"}
    //actual result:    {"objValue": "[1,2]", "stringValue": "test"}
}

После некоторого рытья я обнаружил, что encoder в serialize() принадлежит класс StreamingJsonOutput. Я могу придумать три возможных решения. Но я столкнулся с стеной с каждым из них:

  1. Если бы у меня был способ напрямую print() на composer из StreamingJsonOutput, я мог бы добавить String вручную к выходным данным. Но, к сожалению, composer является частным (и StreamingJsonOutput также внутренним).
  2. Другой способ - использовать конфигурацию unquotedPrint, которая будет создавать строки без кавычек. Но тогда и в stringValue не было бы кавычек. Так что мне нужен способ просто изменить конфигурацию только временно.
  3. Я мог бы просто десериализовать value String из serialize() в реальный объект, а затем просто позволить кодировщику правильно сериализовать его. Проблема, помимо накладных расходов на производительность, заключается в том, что я не знаю, какую структуру данных ожидать в value. Поэтому я не могу десериализовать его.

Надеюсь, у кого-то есть идея, как с этим бороться. Большое спасибо! :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...