Java 如何使用gson调用默认反序列化

Java 如何使用gson调用默认反序列化,java,android,gson,json,Java,Android,Gson,Json,我得到一个带有“field”字段的json 如果“字段”有数据,则存在一个对象,该对象有许多(大约20个)其他字段也是对象。我可以毫无问题地反序列化它们 但若“field”并没有数据,那个么它就是一个空数组(我知道这很疯狂,但这是服务器的响应,我无法更改它)。 大概是这样的: 空时: "extras":[ ] 有一些数据: "extras": { "22":{ "name":"some name" }, "59":{ "name":"some other name" },

我得到一个带有“field”字段的json
如果“字段”有数据,则存在一个对象,该对象有许多(大约20个)其他字段也是对象。我可以毫无问题地反序列化它们
但若“field”并没有数据,那个么它就是一个空数组(我知道这很疯狂,但这是服务器的响应,我无法更改它)。 大概是这样的:

空时:

"extras":[

]
有一些数据:

"extras": {
    "22":{ "name":"some name" },
    "59":{ "name":"some other name" },
    and so on...
}
因此,如果没有数据(空数组),我显然会得到异常

Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 4319
我尝试使用自定义JavaDeserializer:

public class ExtrasAdapter implements JsonDeserializer<Extras> {
    @Override
    public Extras deserialize(JsonElement json, Type typeOf,
        JsonDeserializationContext context) throws JsonParseException {
        try {
            JsonObject jsonObject = json.getAsJsonObject();
            // deserialize normally

            // the following does not work, as it makes recursive calls
            // to the same function
            //return context.deserialize(jsonObject,
            //                       new TypeToken<Object>(){}.getType());
        } catch (IllegalStateException e) {
            return null;
        }
    }
}
我不想手动反序列化所有20个字段(我知道这是一个选项),我只想调用context.defaultDeserialize()之类的函数
再一次:我对反序列化普通json、创建自定义对象、注册自定义TypeAdapter、自定义JavaDeserializer没有任何问题。一切都已经开始了。我只需要一些处理数据的解决方案,可以是数组和对象
谢谢你的帮助

======================



乔伊的答案很完美。那正是我要找的东西。 我将在这里发布我的代码

public class SafeTypeAdapterFactory implements TypeAdapterFactory {
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        return new TypeAdapter<T>() {
            public void write(JsonWriter out, T value) throws IOException {
                try {
                    delegate.write(out, value);
                } catch (IOException e) {
                    delegate.write(out, null);
                }
            }
            public T read(JsonReader in) throws IOException {
                try {
                    return delegate.read(in);
                } catch (IOException e) {
                    Log.w("Adapter Factory", "IOException. Value skipped");
                    in.skipValue();
                    return null;
                } catch (IllegalStateException e) {
                    Log.w("Adapter Factory", "IllegalStateException. Value skipped");
                    in.skipValue();
                    return null;
                } catch (JsonSyntaxException e) {
                    Log.w("Adapter Factory", "JsonSyntaxException. Value skipped");
                    in.skipValue();
                    return null;
                }
            }
        };
    }
}
公共类SafeTypeAdapterFactory实现TypeAdapterFactory{
公共类型适配器创建(Gson Gson,TypeToken类型){
final-TypeAdapter-delegate=gson.getDelegateAdapter(这个,类型);
返回新的TypeAdapter(){
public void write(JsonWriter out,T值)抛出IOException{
试一试{
委托。写出(输出、值);
}捕获(IOE异常){
委托。写入(输出,空);
}
}
公共T读取(JsonReader in)引发IOException{
试一试{
返回delegate.read(in);
}捕获(IOE异常){
Log.w(“适配器工厂”,“IOException.Value跳过”);
in.skipValue();
返回null;
}捕获(非法状态){
Log.w(“适配器工厂”,“IllegalStateException.Value跳过”);
in.skipValue();
返回null;
}捕获(JsonSyntaxException e){
w(“适配器工厂”,“跳过JsonSyntaxException.Value”);
in.skipValue();
返回null;
}
}
};
}
}

尝试使用GSON>=2.2.1并查找类

这将使您能够在反序列化对象和应用自定义代码之前检查对象,同时避免递归

下面是一个可以使用的示例。

公共类ExtrasAdapter实现JsonDeserializer{
public class ExtrasAdapter implements JsonDeserializer<Extras> {
@Override
public Extras deserialize(JsonElement json, Type typeOf, 
              JsonDeserializationContext context) throws JsonParseException {
    try {
        JsonObject jsonObject = json.getAsJsonObject();
        return new Gson().fromJson(jsonObject , Extras.class); // default deserialization

    } catch (IllegalStateException e) {
        return null;
    }
}
@凌驾 公共附加反序列化(JsonElement json,类型typeOf, JsonDeserializationContext)抛出JsonParseException{ 试一试{ JsonObject JsonObject=json.getAsJsonObject(); 返回新的Gson().fromJson(jsonObject,Extras.class);//默认反序列化 }捕获(非法状态){ 返回null; } }
对于任何迟到的人,您不需要实现TypeAdapter来解决这个问题,尽管这样做是一个非常有效的解决方案

这个问题的答案其实在原来的问题中:

public class ExtrasAdapter implements JsonDeserializer<Extras> {

@Override
public Extras deserialize(JsonElement json, Type typeOf, 
          JsonDeserializationContext context) throws JsonParseException {
    try {
        JsonObject jsonObject = json.getAsJsonObject();
        // deserialize normally

        // the following does not work, as it makes recursive calls 
        // to the same function 
        //return context.deserialize(jsonObject, new TypeToken<Object>(){}.getType());
    } catch (IllegalStateException e) {
        return null;
    }
}
因此,将其传递到context.deserialize()将创建递归,并最终创建OOM。这里的解决方案是解析出jsonObject内部的对象

这就引出了第二个问题,这里有两种东西混合在一起。“Extras”是一种对象类型,大概有一个具体的类支持它(可能是一个空数组)。“Extra”是一个映射。试图将“Extra”解析为“Extras”是行不通的。为此,我建议使用以下“Extras”的定义:

公共类附加{
地图附加;
//您还可以为“Extra”创建一个具体的类
//这是一张地图吗
}
在这种情况下,使用context.deserialize解决问题变得微不足道


如上所述,TypeAdatper是解决此问题的一个非常有效的解决方案。我只是相信它超出了您的需要。

我根据需要创建了另一个TypeAdapter,让空数组反序列化为null,但仅针对我指定的类:

class EmptyArraysAsNullTypeAdapterFactory @Inject constructor() : TypeAdapterFactory {

companion object {

    // Add classes here as needed
    private val classesAllowedEmptyArrayAsNull = arrayOf(Location::class.java,
                                                         Results::class.java)

    private fun isAllowedClass(rawType: Class<*>): Boolean {
        return classesAllowedEmptyArrayAsNull.find { rawType.isAssignableFrom(it) } != null
    }
}

override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
    val delegate = gson.getDelegateAdapter(this, type)

    val rawType = type.rawType as Class<T>

    return object : TypeAdapter<T>() {

        override fun write(out: JsonWriter, value: T?) {
            delegate.write(out, value)
        }

        override fun read(reader: JsonReader): T? {
            return if (reader.peek() === JsonToken.BEGIN_ARRAY && isAllowedClass(rawType)) {
                reader.beginArray()

                // If the array is empty, assume it is signifying null
                if (!reader.hasNext()) {
                    reader.endArray()
                    null
                } else {
                    throw JsonParseException("Not expecting a non-empty array when deserializing: ${type.rawType.name}")
                }

            } else {
                delegate.read(reader)
            }
        }
    }
}
类EmptyArraySNullTypeAdapterFactory@Inject构造函数():TypeAdapterFactory{
伴星{
//根据需要在此处添加类
private val classes allowedEmptyArrayasNull=arrayOf(Location::class.java,
结果::class.java)
private fun isAllowedClass(rawType:Class):布尔值{
返回类AllowedEmptyArrayasNull.find{rawType.isAssignableFrom(it)}!=null
}
}
重写趣味创建(gson:gson,type:TypeToken):TypeAdapter{
val delegate=gson.getDelegateAdapter(此类型)
val rawType=type.rawType作为类
返回对象:TypeAdapter(){
重写有趣的写入(输出:JsonWriter,值:T?){
委托。写入(输出、值)
}
重写趣味阅读(reader:JsonReader):T{
返回if(reader.peek()==JsonToken.BEGIN\u数组和isAllowedClass(rawType)){
reader.beginArray()
//如果数组为空,则假定它表示null
如果(!reader.hasNext()){
reader.endArray()
无效的
}否则{
抛出JsonParseException(“反序列化时不需要非空数组:${type.rawType.name}”)
}
}否则{
委托阅读(读卡器)
}
}
}
}

}

粘贴在数组可用时反序列化数据的代码。数组不可用。它只能为空。如果需要反序列化数组,我会在catch块中执行。getDelegateAdapter()的+1是好的
return context.deserialize(jsonObject, new TypeToken<Object>(){}.getType());
JsonObject jsonObject = json.getAsJsonObject();
public class Extras {
    Map<String, Map<String, String>> extras;
    // you could also create a concrete class for "Extra"
    //and have this be a Map<String, Extra>
}
class EmptyArraysAsNullTypeAdapterFactory @Inject constructor() : TypeAdapterFactory {

companion object {

    // Add classes here as needed
    private val classesAllowedEmptyArrayAsNull = arrayOf(Location::class.java,
                                                         Results::class.java)

    private fun isAllowedClass(rawType: Class<*>): Boolean {
        return classesAllowedEmptyArrayAsNull.find { rawType.isAssignableFrom(it) } != null
    }
}

override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
    val delegate = gson.getDelegateAdapter(this, type)

    val rawType = type.rawType as Class<T>

    return object : TypeAdapter<T>() {

        override fun write(out: JsonWriter, value: T?) {
            delegate.write(out, value)
        }

        override fun read(reader: JsonReader): T? {
            return if (reader.peek() === JsonToken.BEGIN_ARRAY && isAllowedClass(rawType)) {
                reader.beginArray()

                // If the array is empty, assume it is signifying null
                if (!reader.hasNext()) {
                    reader.endArray()
                    null
                } else {
                    throw JsonParseException("Not expecting a non-empty array when deserializing: ${type.rawType.name}")
                }

            } else {
                delegate.read(reader)
            }
        }
    }
}