json - kotlinx反序列化: different types && scalar && arrays

标签 json kotlin deserialization kotlinx.serialization

我正在尝试反序列化这样的 JSON(更复杂,但这是重要的部分):

[
    {
        "field": "field1",
        "value": [1000, 2000]
    },
    {
        "field": "field2",
        "value": 1
    },
    {
        "field": "field2",
        "value":["strval2","strval3"]
    },
    {
        "field": "field4",
        "value": "strval1"
    }
]

我试图弄清楚如何在不同的变体中使用 JsonContentPolymorphicSerializer 但结果都是一样的: 类 java.util.ArrayList 无法转换为类 myorg.ConditionValue (java.util.ArrayList 位于加载器“bootstrap”的 java.base 模块中;myorg.ConditionValue 位于加载器“app”的未命名模块中)

@Serializable
sealed class ConditionValue

@Serializable(with = StringValueSerializer::class)
data class StringValue(val value: String) : ConditionValue()

@Serializable(with = StringListValueSerializer::class)
data class StringListValue(val value: List<StringValue>) : ConditionValue()

object ConditionSerializer : JsonContentPolymorphicSerializer<Any>(Any::class) {
    override fun selectDeserializer(element: JsonElement) = when (element) {
        is JsonPrimitive -> StringValueSerializer
        is JsonArray -> ListSerializer(StringValueSerializer)
        else -> StringValueSerializer
    }
}

object StringValueSerializer : KSerializer<StringValue> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("StringValue")

    override fun deserialize(decoder: Decoder): StringValue {
        require(decoder is JsonDecoder)
        val element = decoder.decodeJsonElement()
        return StringValue(element.jsonPrimitive.content)
    }

    override fun serialize(encoder: Encoder, value: StringValue) {
        encoder.encodeString(value.value)
    }
}

我错过了什么?以及如何处理它?<​​/p>

最佳答案

这确实是一个难题。

可能最快、最清晰的方法是避免陷​​入“正确”Kotlinx 序列化器方式的困境,而只需将多态类型解码为 JsonElement

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement


@Serializable
data class MyData(
  val field: String,
  val value: JsonElement, // polymorphism is hard, JsonElement is easy
)

以下代码产生正确的输出

import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json

fun main() {

  val json = /*language=json*/ """
    [
        {
            "field": "field1",
            "value": [1000, 2000]
        },
        {
            "field": "field2",
            "value": 1
        },
        {
            "field": "field2",
            "value":["strval2","strval3"]
        },
        {
            "field": "field4",
            "value": "strval1"
        }
    ]
  """.trimIndent()

  val result = Json.decodeFromString<List<MyData>>(json)

  println(result)
}
[
  MyData(field=field1, value=[1000,2000]), 
  MyData(field=field2, value=1), 
  MyData(field=field2, value=["strval2","strval3"]), 
  MyData(field=field4, value="strval1")
]

现在您可以手动将 MyData 转换为更正确的实例。

  val converted = results.map { result ->

    val convertedValue: ConditionValue = when (val value = result.value) {
      is JsonPrimitive -> convertPrimitive(value)
      is JsonArray     -> convertJsonArray(value)
      else             -> error("cannot convert $value")
    }

    MyDataConverted(
      field = result.field,
      value = convertedValue
    )
  }

...


fun convertJsonArray(array: JsonArray): ConditionValueList<*> =
  TODO()

fun convertPrimitive(primitive: JsonPrimitive): ConditionValuePrimitive = 
  TODO()

最后一点,我建议使用 inline classes来代表你的值(value)观。如果您确实想使用 Kotlinx 序列化,then they work better而不是为原始类型创建自定义序列化器。

以下是我在您的示例中对数据进行建模的方式:

sealed interface ConditionValue

sealed interface ConditionValuePrimitive : ConditionValue

sealed interface ConditionValueCollection<T : ConditionValuePrimitive> : ConditionValue

@JvmInline
value class StringValue(val value: String) : ConditionValuePrimitive

@JvmInline
value class IntegerValue(val value: Int) : ConditionValuePrimitive

@JvmInline
value class ConditionValueList<T : ConditionValuePrimitive>(
  val value: List<T>
) : ConditionValueCollection<T>

data class MyDataConverted(
  val field: String,
  val value: ConditionValue,
)

版本:

  • Kotlin 1.7.10
  • Kotlinx 序列化 1.3.3

关于json - kotlinx反序列化: different types && scalar && arrays,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72813812/

相关文章:

javascript - 如何防止搜索显示整个 JSON 数据库?

python - 使用 Marshmallow 反序列化复杂的 JSON

c# - unity 序列化字典 `Index Out Of Range` 后12项

c++ - 如何知道 QDataStream 不能反序列化某些东西?

javascript - 在服务器端处理 Node 中的异步响应

javascript - 如何将对象列表数组合并为单个数组

arrays - 为什么 set.average 返回的值与 array.average 不同?

java - Kotlin 胶囊 Gradle 错误

java - 动态创建新变量或使用数组

python - Python 中无法解析 JSON 错误