【问题标题】:json Enum deserialization breakes kotlin null-safetyjson 枚举反序列化破坏了 kotlin 空安全性
【发布时间】:2019-07-11 00:46:27
【问题描述】:

我使用 Kotlin data classesGSON 反序列化 JSON 模式,并实现默认值以防止 JSON 中的空对象。此外,JSON int 枚举使用 @SerializedName 注释映射到 Kotlin 枚举值:

data class Person(@SerializedName("name")
           val name: String = ",
           @SerializedName("age")
           val age: Int = 0,
           @SerializedName("hairColor")
           val hairColor: Color = Color.NONE)

enum class Color{
    @SerializedName("1")
    BROWN,
    @SerializedName("2")
    BLONDE,
    NONE
}

专注于枚举反序列化 - 这适用于字段与已知枚举匹配或 JSON 中完全不存在该字段的情况,在这种情况下将实现默认枚举。

但是 - 如果 JSON 中接收到的枚举 映射到我的 kotlin 枚举中的已知枚举值 - 生成的反序列化枚举将为空!!

{"name":"Joe","age":10,"hairColor":1} ->
Person(name=Joe, age=10, hairColor=BROWN)

{"name":"Jim"} ->
Person(name=Jim, age=0, hairColor=NONE)

{"name":"Jeff", "age":8,"hairColor":3) ->
Person(name=Jane, age=8, hairColor=null)

Gson 通过将 null 分配给非 null 类型来欺骗 Kotlin 的 null 安全机制。 问题 - 如何将未知的 JSON 枚举映射到默认的 Kotlin 枚举?我的目标是通过简单的实现来保持空值安全。

附: - 我知道我可以将 JSON 枚举解析为 Ints,然后反序列化它们,或者使用支持字段和自定义 getter,但我喜欢直接解析为 Kotlin 枚举的优雅和类型安全。

【问题讨论】:

标签: android json kotlin enums gson


【解决方案1】:

我为 Gson 编写了一个 Kotlin 包装器(称为 Arson),它将缺失的默认值添加到反序列化的对象中。除此之外,它还检查违反 Kotlin 非空安全性的空值。

查看:https://github.com/taskbase/arson

在你的项目中使用它:

<dependency>
    <groupId>com.taskbase.arson</groupId>
    <artifactId>arson</artifactId>
    <version>1.0</version>
</dependency>

class ArsonTest {

    @Test
    fun testEnumDeserialization() {
        val json = "{'name':'Jim', 'hairColor':'3'}"

        // Gson deserializes the value to null
        val p1 = Gson().fromJson(json, Person::class.java)
        assertNull(p1.hairColor)

        // The wrapper replaces null with the default value
        val p2 = Arson(gson = Gson()).fromJson(json, Person::class.java)
        assertEquals(Color.NONE, p2.hairColor)
    }
}

data class Person(
    val name: String = "",
    val age: Int = 0,
    val hairColor: Color = Color.NONE
)

enum class Color {
    @SerializedName("1")
    BROWN,
    @SerializedName("2")
    BLONDE,
    NONE
}

我也在为 Gson 缺乏 Kotlin 支持而苦苦挣扎。 Gson 是一个 Java 库,不了解 Kotlin 的类型系统。我测试了其他几个 JSON 库,但没有一个运行得足够好。因此,我编写了一个函数,该函数使用 Kotlin 反射库来创建添加缺失默认值的对象的深层副本。

【讨论】:

    猜你喜欢
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    • 2013-09-04
    • 1970-01-01
    • 1970-01-01
    • 2018-10-11
    相关资源
    最近更新 更多