使用 Kotlin 限制序列化类属性的允许整数值

Limit permitted integer values for serialised class property with Kotlin

提问人:Crocodile 提问时间:10/23/2023 最后编辑:Crocodile 更新时间:10/23/2023 访问量:37

问:

我想限制类属性允许的整数值,以便在序列化为 Json(使用 gson)后,该值将表示为数字而不是字符串。

class Car(
@Expose val color: Color = Color.RED,
@Expose val seats: Seats = Seats.FIVE   // Using an enum class so only predefined values are accepted.
)

enum class Color{
     @SerializedName("red") RED,
     @SerializedName("blue") BLUE,
}

enum class Seats{
     @SerializedName("4") FOUR,
     @SerializedName("5") FIVE,
}

实际 json 输出:

{
   "color": "red",
   "seats": "5"   // This is a string. It's not what I want.
}

我需要的json输出:

{
   "color": "red",
   "seats": 5   // This is a number ✓
}
json kotlin 枚举 gson

评论

1赞 Joffrey 10/23/2023
顺便说一句,选择 Gson 作为序列化库的原因是什么?它现在处于维护模式,不太适合 Kotlin。我建议改用 kotlinx.serializationMoshi(Gson 的继任者)
0赞 Crocodile 10/23/2023
@Joffrey 感谢您的提醒。我之所以使用 gson,是因为这正是我的代码多年前实现的,我不想要撕掉它并替换它的开销。
0赞 Crocodile 10/23/2023
@Joffrey 鉴于 Kotlin 的一部分,与 Moshi 相比,您认为 kotlinx.serialization 更适合切换到 kotlin.serialization 吗?
1赞 Joffrey 10/23/2023
是的,它也是 Kotlin 优先的,因此未来的功能可能会得到更好的开箱即用支持。请注意,方法也大不相同。Kotlinx Serialization 在编译时生成序列化程序,而 Moshi 默认是基于反射的(尽管它也支持 codegen,IIRC)。此外,Kotlinx 序列化是多平台的,而 Moshi 目前只是 JVM

答:

1赞 Joffrey 10/23/2023 #1

如果你真的想坚持使用 Gson,一种方法是将整数指定为枚举的属性:

enum class Seats(val value: Int) {
    FOUR(4),
    FIVE(5);

    companion object {
        fun of(value: Int) = entries.firstOrNull { it.value == value }
    }
}

然后,使用类型适配器或自定义序列化程序,该适配器或自定义序列化程序使用此属性进行序列化,并使用函数进行反序列化:Seat.of(...)

class SeatSerializer : JsonSerializer<Seats> {
    override fun serialize(src: Seats, typeOfSrc: Type, context: JsonSerializationContext): JsonElement =
        JsonPrimitive(src.value)
}

class SeatDeserializer : JsonDeserializer<Seats> {
    override fun deserialize(element: JsonElement, type: Type, context: JsonDeserializationContext): Seats =
        Seats.of(element.asInt) ?: error("Cannot deserialize ${element.asInt} as Seats")
}