My initializer block is working perfectly fine when I create my Object

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

this way:

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

But when I deserialize the object with Gson, the initializer block does not get executed:

@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创建对象的方式与执行主构造函数不同.然而,是否有可能有类似的初始值设定块?


推荐答案

Gson is intended for usage with pure Java and doesn't interpret Kotlin primary constructors properly.

If there is a default no-argument constructor, it is called (in your case, there is one: the primary constructor with default value "" for someString), otherwise Gson calls no constructor at all.

Then Gson sets the property values (also, it bypasses actual setters of Kotlin properties and sets the fields directly, which may sometimes lead to unexpected behavior).


As an alternative, you can use jackson-module-kotlin, it should work good in your case (it understands Kotlin primary constructors, uses Kotlin setters and supports default parameter values as well since 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")
}

The output is

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相关问答推荐

为什么Kotlin函数参数名会 destruct 方法调用?

协程子作业(job)取消

Kotlin:调用 CoroutineScope.launch 与在协程内启动之间的区别

将 Integer 转换为 Unit 编译成功

有没有一种简单的方法可以将数组/列表中的每个元素相互相乘 - Kotlin?

即使 Kotlin 的 `Map` 不是 `Iterable`,它如何以及为什么是可迭代的?

Kotlin 条件格式字符串

如何在 Kotlin 中使用具有继承的泛型

未为任务启用 Gradle 构建缓存

来自类型参数的属性的自定义 getter

Kotlin 中的 Java Scanner 相当于什么?

在粘贴时将 java 转换为 kotlin

API 'variant.getJavaCompile()' 已过时

Kotlin 顶级函数与对象函数

取消信号上的kotlin流量采集

Kapt不适用于Android Studio 3.0中的AutoValue

Kotlin val difference getter override vs assignment

Android 上的 Kotlin:将map到list

我应该使用Kotlin数据类作为JPA实体吗?

为什么在 Kotlin 中return可以返回一个return?