使用GsonMap密封类

kqqjbcuj  于 2023-05-17  发布在  其他
关注(0)|答案(1)|浏览(173)

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

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()
}

构造deviceSettingsMap时出现问题。因为它可能包含几种类型的数据,所以定义了Value密封类。但如前所述,这将只是崩溃,而人解析...
这个想法是DeviceSettings Map是动态的,这就是为什么它实际上没有被解析为预定义的数据类的原因。它可能只包含一个key:value对,但也可能有30个!
@cutiko这是正确的,在此一些收到的json:

"DeviceSettings": {
    "ToneLevel": 80.0,
    "AutoLogging": false,
    "OrientationLandscape": false,
    "AudioDuration": 2500.0,
    "ShoutLevel": 1.0,
    "SipExtension": 0.0,
    "SipServerAuthenticationKey": "",
    "SipServerPort": 5060.0,
    "SipServerUri": ""
}
tyky79it

tyky79it1#

您将不得不编写一个自定义的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,或者你有不同的逻辑来决定什么是DoubleLong
  • 您显示的原始异常消息似乎与您提到的问题无关,至少与kotlinx.serialization的连接不清楚。

相关问题