Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使Gson为外场确定的接口类型工作_Java_Android_Kotlin_Gson_Deserialization - Fatal编程技术网

Java 使Gson为外场确定的接口类型工作

Java 使Gson为外场确定的接口类型工作,java,android,kotlin,gson,deserialization,Java,Android,Kotlin,Gson,Deserialization,问题类似于 但不同之处在于,类型不包含在反序列化的JSON对象中,而是包含在外部级别(根)中 像这样: { "type": "A", "myObject" : { <- type is NOT stored in here ... } } 如果type是A和Baz如果type是B,如何将myObject映射到Bar 暂时,我求助于手动读取根JSON对象。任何帮助都将不胜感激。谢谢 编辑: 当尝试使用GsonfromJson方法将根JSON对象映射到

问题类似于 但不同之处在于,
类型
不包含在反序列化的JSON对象中,而是包含在外部级别(根)中

像这样:

{
    "type": "A",
    "myObject" : { <- type is NOT stored in here
        ...
    }
}
如果
type
A
Baz
如果
type
B
,如何将
myObject
映射到
Bar

暂时,我求助于手动读取根JSON对象。任何帮助都将不胜感激。谢谢

编辑:


当尝试使用
Gson
fromJson
方法将根JSON对象映射到
Blah
时,我遇到以下错误:
无法为类Foo调用无参数构造函数
-但无论如何,这是不正确的,因为我需要
myObject
专门映射到
Baz
Bar

这与您提到的问题非常相似

您可以为
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
导入com.google.gson* 接口Foo{ 风趣的树皮 } 类栏:Foo{//如果“type”是 覆盖有趣的树皮(){ 打印(“条”) } } 类Baz:Foo{//如果“type”是B,则映射到此 覆盖有趣的树皮(){ 打印(“baz”) } } 类Blah(val类型:String?=null,val myObject:Foo?=null){ 伴星{ const val TYPE_A=“A” const val TYPE_B=“B” } } 类BlahJsonDeserializer:JsonDeserializer{ 重写有趣的反序列化(json:JsonElement?、typeOfT:Type?、context:JsonDeserializationContext?):Blah{ val root=json?.asJsonObject val type=root?.get(“type”)?.asString 变量obj:Foo?=null 何时(键入?:“”){ Blah.TYPE_A->{obj=Bar()} Blah.TYPE_B->{obj=Baz()} } val blah=blah(类型,obj) 回音 } } val json=“{'type':'A','myObject':{}” val gsonBuilder=gsonBuilder() gsonBuilder.registerTypeAdapter(Blah::class.java,BlahJsonDeserializer()) val gson=gsonBuilder.create() val item=gson.fromJson(json,Blah::class.java) item.myObject?.bark()//条
这是我的解决方案。解决方案在科特林

编辑类
Blah

class Blah {

    val type : String? = null

    @ExcludeOnDeserialization // <- add this
    val myObject : Foo? = null
}

这个解决方案的灵感来自

谢谢,但我避免了这样做,因为这意味着我必须手动映射
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
    }
}
...

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'