使用 Gson 映射密封类

问题描述 投票:0回答:1

我在尝试将 Json 中传入的 REST-api 结果映射到对象时遇到以下错误:

failed to invoke private kotlinx.serialization.json.jsonelement() with no args

经过一些搜索,问题似乎是我试图实例化一个 Value() 对象,而它是一个密封类。 现在我不确定如何解决这个问题?

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

sealed class Value {
    class BoolValue(val value: Boolean)  : Value()
    class DoubleValue(val value: Double) : Value()
    class IntegerValue(val value: Long)  : Value()
    class StringValue(val value: String) : Value()
}

问题出现在构造deviceSettings映射的时候。因为它可能包含多种类型的数据,所以定义了 Value 密封类。但正如所提到的,这只会在解析生物时崩溃......

想法是 DeviceSettings Map 是动态的,这就是为什么它实际上没有被解析为预定义数据类的原因!它可能包含一个键值对,但也可能有三十个!

@cutiko 没错,特此收到一些 json :

"DeviceSettings": {
    "ToneLevel": 80.0,
    "AutoLogging": false,
    "OrientationLandscape": false,
    "AudioDuration": 2500.0,
    "ShoutLevel": 1.0,
    "SipExtension": 0.0,
    "SipServerAuthenticationKey": "",
    "SipServerPort": 5060.0,
    "SipServerUri": ""
}
android kotlin gson sealed-class
1个回答
0
投票

您将必须编写自定义

TypeAdapter
来查看 JSON 数据的类型,并根据它选择正确的
Value
子类进行实例化。例如:

object ValueTypeAdapter : TypeAdapter<Value>() {
    override fun write(writer: JsonWriter, value: Value?) {
        throw UnsupportedOperationException()
    }

    override fun read(reader: JsonReader): Value {
        return when (val token = reader.peek()) {
            JsonToken.BOOLEAN -> Value.BoolValue(reader.nextBoolean())
            JsonToken.STRING -> Value.StringValue(reader.nextString())
            JsonToken.NUMBER -> {
                // Read the string representation of the number
                val numberAsStr = reader.nextString()
                // If number contains decimal point or exponent prefix 'e', parse as Double
                if (numberAsStr.any { c -> c == '.' || c == 'e' || c == 'E' }) {
                    Value.DoubleValue(numberAsStr.toDouble())
                } else {
                    Value.IntegerValue(numberAsStr.toLong())
                }
            }
            else -> throw IllegalArgumentException("Unexpected value type $token at ${reader.path}")
        }
    }
}

然后您可以像这样在

GsonBuilder
上注册适配器:

val gson = GsonBuilder()
    .registerTypeAdapter(Value::class.java, ValueTypeAdapter)
    .create()

然而,有几件事需要考虑,因此您可能需要调整此代码:

  • 你想怎么治疗
    -0
    ?使用上面的代码,它将被解析为
    Long
    并且
    -
    符号将丢失。也许您想将其解析为
    Double
    -0.0
  • 在您的示例 JSON 数据中,所有数字都有小数点;应该将这些都解析为
    Double
    ,还是您有不同的逻辑来决定什么是
    Double
    Long
  • 您显示的原始异常消息似乎与您提到的问题无关,至少与
    kotlinx.serialization
    的联系尚不清楚。
© www.soinside.com 2019 - 2024. All rights reserved.