使用 Kotlin 进行 Gson 反序列化,未调用初始化程序 block

标签 gson kotlin

当我创建我的对象时,我的初始化程序 block 工作得非常好

class ObjectToDeserialize(var someString: String = "") : Serializable {
    init{
        someString += " initialized"
    }
}

这样:

@Test
fun createObject_checkIfInitialized() {
      assertEquals("someString initialized",ObjectToDeserialize("someString").someString)
}

但是当我用 Gson 反序列化对象时,初始化 block 没有被执行:

@Test
fun deserializeObject_checkIfInitialized(){
    val someJson: String = "{\"someString\":\"someString\" }"
    val jsonObject = Gson().fromJson(someJson, ObjectToDeserialize::class.java)

    assertEquals("someString initialized",jsonObject.someString)

    // Expected :someString initialized
    // Actual   :someString
}

我认为GSON正在以与执行主构造函数不同的方式创建对象。尽管如此,是否有可能有类似初始化 block 之类的东西?


最佳答案

Gson 旨在用于纯 Java,不能正确解释 Kotlin 主构造函数。

如果有一个默认的无参数构造函数,它会被调用(在你的情况下,有一个:具有默认值 "" for someString 的主构造函数) , otherwise Gson calls no constructor at all .

然后 Gson 设置属性值(同样,它绕过 Kotlin 属性的实际 setter 并直接设置字段,这有时可能会导致意外行为)。


您也可以使用 jackson-module-kotlin ,它应该适用于您的情况(它理解 Kotlin 主构造函数,使用 Kotlin setter 并支持默认参数值以及自 2.8.x 以来)。

这个例子比较了 jackson-module-kotlin 和 Kotson行为:

class SomeClass(val id: Int = -1) {
    init { println("init $id") }
}

class SomeClassNoDefault(val id: Int) {
    init { println("init $id") }
}

fun main(args: Array<String>) {
    val mapper = jacksonObjectMapper()
    val gson = Gson()

    val idDefault = "{}"
    val id123 = "{\"id\": 123 }"

    println("jackson-module-kotlin, { }:")
    val o1 = mapper.readValue<SomeClass>(idDefault)
    println("after construction: ${o1.id}\n")

    println("jackson-module-kotlin, { \"id\" = 123 }:")
    val o2 = mapper.readValue<SomeClass>(id123)
    println("after construction: ${o2.id}\n")

    println("kotson, { }:")
    val o3 = gson.fromJson<SomeClass>(idDefault)
    println("after construction: ${o3.id}\n")

    println("kotson, { \"id\" = 123 }:")
    val o4 = gson.fromJson<SomeClass>(id123)
    println("after construction: ${o4.id}\n")

    println("---\n")

    println("jackson-module-kotlin, no default value, { \"id\" = 123 }:")
    val o5 = mapper.readValue<SomeClassNoDefault>(id123)
    println("after construction: ${o5.id}\n")

    println("kotson, no default value, { \"id\" = 123 }:")
    val o6 = gson.fromJson<SomeClassNoDefault>(id123)
    println("after construction: ${o6.id}\n")
}

输出是

jackson-module-kotlin, { }:
init -1
after construction: -1

jackson-module-kotlin, { "id" = 123 }:
init 123
after construction: 123

kotson, { }:
init -1
after construction: -1

kotson, { "id" = 123 }:
init -1
after construction: 123

---

jackson-module-kotlin, no default value, { "id" = 123 }:
init 123
after construction: 123

kotson, no default value, { "id" = 123 }:
after construction: 123

关于使用 Kotlin 进行 Gson 反序列化,未调用初始化程序 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39962284/

相关文章:

kotlin - Kotlin 中的保留关键字是什么?

java - 无法将 Zookeeper 对象转换为 json,反之亦然

java - 如何从Gson获取变量的值

android - 在 ViewModel 中观察 LiveData 最佳实践

Kotlin with-statement 作为表达式

java - 当 flutter 应用程序自动启动处于 BOOT_COMPLETED 时,在后台执行 Dart 函数?

java - 如何使用 gson 库将字符串转换为 JsonObject

java - 如果元素有时以 jsonobject 形式出现,有时以 jsonarray 形式出现,如何解析 JSON

java - 无法从 url 解析 JSON

android - 无法为 org.gradle.api.internal.tasks.DefaultSourceSetContainer 类型的 SourceSet 容器获取未知属性 'main'