我写了一个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)
}
}