You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Gson映射Kotlin密封类时遭遇实例化错误求助

解决Kotlinx Serialization解析密封类到动态Map的崩溃问题

你遇到的错误failed to invoke private kotlinx.serialization.json.jsonelement() with no args,本质是kotlinx.serialization默认无法将JSON中的基本类型(布尔、数字、字符串)直接映射到密封类Value的子类——因为密封类本身没有无参构造,且默认序列化逻辑需要额外类型标识(比如type字段),但你的JSON结构里只有纯基本类型值,没有类型信息。

解决方案

给密封类Value实现自定义序列化器,让序列化框架能根据JSON元素的类型自动匹配对应的Value子类。

完整代码实现

import kotlinx.serialization.*
import kotlinx.serialization.json.*

@Serializable
data class Device (
    @SerializedName("DeviceSettings")
    val deviceSettings: Map<String, Value>? = null,
    @SerializedName("Id")
    val id: String
)

@Serializable(with = ValueSerializer::class)
sealed class Value {
    data class BoolValue(val value: Boolean) : Value()
    data class DoubleValue(val value: Double) : Value()
    data class IntegerValue(val value: Long) : Value()
    data class StringValue(val value: String) : Value()
}

object ValueSerializer : KSerializer<Value> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Value", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: Value) {
        val jsonEncoder = encoder as JsonEncoder
        val jsonElement = when (value) {
            is Value.BoolValue -> JsonPrimitive(value.value)
            is Value.DoubleValue -> JsonPrimitive(value.value)
            is Value.IntegerValue -> JsonPrimitive(value.value)
            is Value.StringValue -> JsonPrimitive(value.value)
        }
        jsonEncoder.encodeJsonElement(jsonElement)
    }

    override fun deserialize(decoder: Decoder): Value {
        val jsonDecoder = decoder as JsonDecoder
        val jsonElement = jsonDecoder.decodeJsonElement()
        
        return when (jsonElement) {
            is JsonPrimitive -> {
                when {
                    jsonElement.isBoolean -> Value.BoolValue(jsonElement.boolean)
                    jsonElement.isString -> Value.StringValue(jsonElement.content)
                    jsonElement.isNumber -> {
                        val number = jsonElement.double
                        // 适配JSON中如5060.0这类整数形式的浮点数
                        if (number == number.toLong().toDouble()) {
                            Value.IntegerValue(number.toLong())
                        } else {
                            Value.DoubleValue(number)
                        }
                    }
                    else -> throw SerializationException("不支持的JsonPrimitive类型")
                }
            }
            else -> throw SerializationException("仅支持JsonPrimitive类型作为Value")
        }
    }
}

关键细节说明

  1. 给Value密封类添加@Serializable(with = ValueSerializer::class)注解,指定使用自定义序列化器处理该类的序列化/反序列化逻辑。
  2. 序列化器核心逻辑:
    • 序列化:将Value的各个子类实例转换为对应的JsonPrimitive类型(布尔、数字、字符串)。
    • 反序列化:根据JsonPrimitive的类型自动创建对应的Value子类实例;针对数字额外判断是否为整数,避免把5060.0这类值错误识别为浮点数。

使用示例

// 解析示例JSON
val jsonContent = """
{
    "DeviceSettings": {
        "ToneLevel": 80.0,
        "AutoLogging": false,
        "OrientationLandscape": false,
        "AudioDuration": 2500.0,
        "ShoutLevel": 1.0,
        "SipExtension": 0.0,
        "SipServerAuthenticationKey": "",
        "SipServerPort": 5060.0,
        "SipServerUri": ""
    },
    "Id": "device_001"
}
"""

val device = Json.decodeFromString<Device>(jsonContent)

内容的提问来源于stack exchange,提问作者TiGer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 13:30:00