问题类似于this
但不同之处在于type
不包含在要反序列化的JSON对象中,而是包含在外部层(根)中。
像这样:
{
"type": "A",
"myObject" : { <- type is NOT stored in here
...
}
}
目的是将此JSON对象映射到Blah
// Code is in Kotlin
interface Foo {
...
}
class Bar : Foo { // Map to this if 'type' is A
...
}
class Baz : Foo { // Map to this if 'type' is B
...
}
class Blah {
val type : String? = null
val myObject : Foo? = null
}
如果myObject
为Bar
,如何将type
映射到A
,如果Baz
为type
,如何使B
映射到Blah
?
暂时,我不得不手动读取JSON根对象。任何帮助将非常感激。谢谢。
编辑:
当尝试使用Gson
fromJson
方法将根JSON对象映射到Unable to invoke no-args constructor for class Foo
时,出现此错误:myObject
。 -但这仍然是不正确的,因为我需要Baz
才能专门映射到Bar
或Caman('#canvas', function () {
this.colorize(25, 180, 200, 20);
this.render();
});
。
答案 0 :(得分:1)
这与您提到的问题非常相似。
您可以为Blah
定义一个反序列化器,并确定应使用哪个类。
代码如下所示。
import com.google.gson.*
interface Foo {
fun bark()
}
class Bar : Foo { // Map to this if 'type' is A
override fun bark() {
print("bar")
}
}
class Baz : Foo { // Map to this if 'type' is B
override fun bark() {
print("baz")
}
}
class Blah(val type : String? = null, val myObject : Foo? = null) {
companion object {
const val TYPE_A = "A"
const val TYPE_B = "B"
}
}
class BlahJsonDeserializer: JsonDeserializer<Blah> {
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): Blah {
val root = json?.asJsonObject
val type = root?.get("type")?.asString
var obj: Foo? = null
when(type ?: "") {
Blah.TYPE_A -> { obj = Bar() }
Blah.TYPE_B -> { obj = Baz() }
}
val blah = Blah(type, obj)
return blah
}
}
val json = "{'type': 'A', 'myObject': {}}"
val gsonBuilder = GsonBuilder()
gsonBuilder.registerTypeAdapter(Blah::class.java, BlahJsonDeserializer())
val gson = gsonBuilder.create()
val item = gson.fromJson<Blah>(json, Blah::class.java)
item.myObject?.bark() // bar
答案 1 :(得分:0)
这是我的解决方案。解决方案在Kotlin。
编辑课程Blah
:
class Blah {
val type : String? = null
@ExcludeOnDeserialization // <- add this
val myObject : Foo? = null
}
在一些静态类中:
inline fun <T : Annotation>findAnnotatedFields(
annotation: Class<T>,
clazz : Class<*>,
onFind : (Field) -> Unit
){
for(field in clazz.declaredFields){
if(field.getAnnotation(annotation)!=null){
field.isAccessible = true
onFind(field)
}
}
}
创建新的类和注释:
@Target(AnnotationTarget.FIELD)
annotation class ExcludeOnDeserialization
class GsonExclusionStrategy : ExclusionStrategy {
override fun shouldSkipClass(clazz: Class<*>?): Boolean {
return clazz?.getAnnotation(ExcludeOnDeserialization::class.java) != null
}
override fun shouldSkipField(f: FieldAttributes?): Boolean {
return f?.getAnnotation(ExcludeOnDeserialization::class.java) != null
}
}
读取json根对象:
...
val gson = GsonBuilder()
.addDeserializationExclusionStrategy(GsonExclusionStrategy())
.create()
val rootJsonObject = JsonParser().parse(rootJsonObjectAsString)
val blah = gson.fromJson(rootJsonObject, Blah::class.java)
findAnnotatedFields(
ExcludeOnDeserialization::class.java,
Blah::class.java
){ foundExcludedField -> // foundExcludedField = 'myObject' declared in 'Blah' class
val myObjectAsJsonObject
= rootJsonObject.asJsonObject.getAsJsonObject(foundExcludedField.name)
when (foundExcludedField.type) {
Foo::class.java -> {
when (blah.type) {
"A" -> {
foundExcludedField.set(
blah,
gson.fromJson(myObjectAsJsonObject, Bar::class.java)
)
}
"B" -> {
foundExcludedField.set(
blah,
gson.fromJson(myObjectAsJsonObject, Baz::class.java)
)
}
else -> return null
}
}
}
}
// The root json object has now fully been mapped into 'blah'
此解决方案的灵感来自this article