GSON多态反序列化列表<baseclass>如果嵌套则不映射到子类

时间:2018-11-29 11:02:17

标签: json kotlin gson

我写了一个JsonDeserializer通过从json读取子类类型来映射到子类。除嵌套类型为BaseClass的类型包含BaseClass的类型外,此方法效果很好。当发生这种情况时,绝不会为嵌套类调用反序列化器。我已经提交了bug report,但想确认它实际上是一个错误,还是想知道是否有解决此问题的方法。

随附完整示例。 Gson版本2.8.5。 Kotlin版本1.3.10

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import java.lang.reflect.Type


open class BaseClass {
    var myType: String? = null
    var myList = mutableListOf<BaseClass>()
    var dep: BaseClass? = null
}

open class ClassA : BaseClass() {
    val astuff: String? = null
}

open class ClassB : BaseClass() {
    val bstuff: String? = null
}

open class Resources {
    val myList = mutableListOf<BaseClass>()
}


val json1 = """
{
  "myList": [
    {
      "myType": "ClassA",
      "astuff": "a stuff"
    },
    {
      "myType" : "ClassB",
      "bstuff" : "things b needs"
    }
  ]
}
""".trimIndent()

val json2 = """
          {
            "myType" : "ClassA",
            "astuff" : "a stuff",
            "myList" : [
              {
                "myType" : "ClassB",
                "bstuff" : "things b needs"
              }
            ]
          }
""".trimIndent()

val json3 = """
          {
            "myType" : "ClassA",
            "astuff" : "a stuff",
            "dep" :               {
                "myType" : "ClassB",
                "bstuff" : "things b needs"
              },
            "myList" : [
              {
                "myType" : "ClassB",
                "bstuff" : "things b needs"
              }
            ]
          }
""".trimIndent()


fun main(args: Array<String>) {

    val gson = getGson()

    // working example
    val test1 = gson.fromJson(json1, Resources::class.java)
    if (!(test1.myList[0] is ClassA)) {
        println("Test1 Error: first array entry should be ClassA but is ${test1.myList[0]::class.java}")
    }

    if (!(test1.myList[1] is ClassB)) {
        println("Test1 Error: first array entry should be ClassB but is ${test1.myList[1]::class.java}")
    }

    // broken examples
    val test2 = gson.fromJson(json2, BaseClass::class.java)
    if (!(test2.myList[0] is ClassA)) {
        println("Test3 Error: first array entry should be ClassA but is ${test2.myList[0]::class.java}")
    }

    val test3 = gson.fromJson(json3, BaseClass::class.java)

}

fun getGson(): Gson {
    return GsonBuilder()
            .registerTypeAdapter(BaseClass::class.java, ClassDeserializerAdapter1<BaseClass>("myType"))
            .create()
}

class ClassDeserializerAdapter1<T> internal constructor(private val typeName: String) : JsonDeserializer<T> {
    private val gson: Gson

    init {
        gson = GsonBuilder()
                .create()
    }

    @Throws(JsonParseException::class)
    override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): T {
        val jsonObject = json.asJsonObject
        val typeElement = jsonObject.get(typeName)
        val method = typeElement.asString
        val classType = Class.forName("com.juicelabs.fhir.base.$method") as Class<out T>
        return gson.fromJson(json, classType)
    }
}

0 个答案:

没有答案