使用Kotlin进行Gson反序列化,不调用初始化程序块

时间:2016-10-10 16:03:38

标签: gson kotlin

我创建对象时,我的初始化程序块工作正常

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

这样:

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

但是当我用Gson反序列化对象时,初始化块不会被执行:

@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以不同于执行主构造函数的方式创建对象。是否有可能像初始化块一样有类似的东西?

2 个答案:

答案 0 :(得分:12)

Gson适用于纯Java,并不能正确解释Kotlin主要构造函数。

如果存在默认的无参数构造函数,则会调用它(在您的情况下,有一个:""的默认值为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

答案 1 :(得分:0)

我在 Gson 上遇到了类似的问题。我的数据类有一些序列化的参数和一些非序列化的。我想用默认值制作我的非序列化参数。我找到的最简单的解决方案是使我的非序列化参数可选。这是我的解决方法:

data class MyClass(
@SerializedName("name") val name: String // All Serialize goes here
) { // Non serialized
    var status: String?
        get {
            return if (field == null) {
                "Nice status"
            } else {
                field
            }
        }
}