使用Kotlin进行Gson反序列化,未调用初始值设定项块

eiee3dmh  于 2022-11-06  发布在  Kotlin
关注(0)|答案(2)|浏览(258)

当我创建Object时,我的初始化程序块工作得非常好

  1. class ObjectToDeserialize(var someString: String = "") : Serializable {
  2. init{
  3. someString += " initialized"
  4. }
  5. }

这样:

  1. @Test
  2. fun createObject_checkIfInitialized() {
  3. assertEquals("someString initialized",ObjectToDeserialize("someString").someString)
  4. }

但是,当我用Gson反序列化对象时,初始化程序块没有得到执行:

  1. @Test
  2. fun deserializeObject_checkIfInitialized(){
  3. val someJson: String = "{\"someString\":\"someString\" }"
  4. val jsonObject = Gson().fromJson(someJson, ObjectToDeserialize::class.java)
  5. assertEquals("someString initialized",jsonObject.someString)
  6. // Expected :someString initialized
  7. // Actual :someString
  8. }

我认为gson创建对象的方式与执行主构造函数的方式不同,但是否有可能有类似的初始化程序块?

dzhpxtsq

dzhpxtsq1#

Gson是为纯Java设计的,不能正确解释Kotlin主构造函数。
如果有默认的无参数构造函数,则调用它(在您的示例中,有一个:主构造函数,默认值为someString),otherwise Gson calls no constructor at all
然后Gson设置属性值(同时,它绕过Kotlin属性的实际设置者,直接设置字段,这有时可能导致意外行为)。
作为一种替代方法,您可以使用jackson-module-kotlin,它在您的情况下应该能很好地工作(它理解Kotlin主构造函数,使用Kotlin设置器,并且自2.8.x以来也支持默认参数值)。
此示例比较了jackson-module-Kotlin和Kotson的行为:

  1. class SomeClass(val id: Int = -1) {
  2. init { println("init $id") }
  3. }
  4. class SomeClassNoDefault(val id: Int) {
  5. init { println("init $id") }
  6. }
  7. fun main(args: Array<String>) {
  8. val mapper = jacksonObjectMapper()
  9. val gson = Gson()
  10. val idDefault = "{}"
  11. val id123 = "{\"id\": 123 }"
  12. println("jackson-module-kotlin, { }:")
  13. val o1 = mapper.readValue<SomeClass>(idDefault)
  14. println("after construction: ${o1.id}\n")
  15. println("jackson-module-kotlin, { \"id\" = 123 }:")
  16. val o2 = mapper.readValue<SomeClass>(id123)
  17. println("after construction: ${o2.id}\n")
  18. println("kotson, { }:")
  19. val o3 = gson.fromJson<SomeClass>(idDefault)
  20. println("after construction: ${o3.id}\n")
  21. println("kotson, { \"id\" = 123 }:")
  22. val o4 = gson.fromJson<SomeClass>(id123)
  23. println("after construction: ${o4.id}\n")
  24. println("---\n")
  25. println("jackson-module-kotlin, no default value, { \"id\" = 123 }:")
  26. val o5 = mapper.readValue<SomeClassNoDefault>(id123)
  27. println("after construction: ${o5.id}\n")
  28. println("kotson, no default value, { \"id\" = 123 }:")
  29. val o6 = gson.fromJson<SomeClassNoDefault>(id123)
  30. println("after construction: ${o6.id}\n")
  31. }

输出为

  1. jackson-module-kotlin, { }:
  2. init -1
  3. after construction: -1
  4. jackson-module-kotlin, { "id" = 123 }:
  5. init 123
  6. after construction: 123
  7. kotson, { }:
  8. init -1
  9. after construction: -1
  10. kotson, { "id" = 123 }:
  11. init -1
  12. after construction: 123
  13. ---
  14. jackson-module-kotlin, no default value, { "id" = 123 }:
  15. init 123
  16. after construction: 123
  17. kotson, no default value, { "id" = 123 }:
  18. after construction: 123
展开查看全部
inn6fuwd

inn6fuwd2#

我在Gson中遇到了类似的问题。我的数据类有一些序列化参数和一些非序列化参数。我想让我的非序列化参数具有默认值。我找到的最简单的解决方案是让我的非序列化参数成为可选的。下面是我的解决方法:

  1. data class MyClass(
  2. @SerializedName("name") val name: String // All Serialize goes here
  3. ) { // Non serialized
  4. var status: String?
  5. get {
  6. return if (field == null) {
  7. "Nice status"
  8. } else {
  9. field
  10. }
  11. }
  12. }

相关问题