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

时间:2012-05-15 08:14:17

标签: java android gson json

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

空时:

"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;
        }
    }
}

我按照以下方式阅读json

Gson gsonDecoder = new GsonBuilder().registerTypeAdapter(Extras.class, new ExtrasAdapter();
// httpResponse contains json with extras filed. 
Reader reader = new InputStreamReader(httpResponse.getEntity().getContent());
Extras response = gsonDecoder.fromJson(reader, Extras.class);

我不想手动反序列化所有20个字段(我知道这是一个选项),我只想调用context.defaultDeserialize()或类似的东西。
再一次:我没有任何问题反序列化普通的json,创建自定义对象,注册自定义TypeAdapter,自定义JavaDeserializers。这一切都已经有效了。我只需要一些处理数据的解决方案,可以是ARRAY和OBJECT。
谢谢你的帮助。

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


乔伊的回答非常完美。这是我正在寻找的东西。 我会在这里发布我的代码。

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;
                }
            }
        };
    }
}

4 个答案:

答案 0 :(得分:22)

尝试使用GSON&gt; = 2.2.1并查找TypeAdapterFactory类。

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

以下是您可以使用的getDelegateAdapter示例。

答案 1 :(得分:12)

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;
    }
}

答案 2 :(得分:3)

对于迟到的人来说,你不需要实现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;
    }
}

注释掉了

return context.deserialize(jsonObject, new TypeToken<Object>(){}.getType());

几乎是解决方案。这个问题有两个问题。首先,jsonObject是最初传递给该函数的确切对象。

JsonObject jsonObject = json.getAsJsonObject();

因此将其传递给context.deserialize()将创建递归,并最终创建OOM。这里的解决方案是解析jsonObject中的对象。

这引出了我们的第二个问题,即有两件事情在这里混合。 “Extras”是一种对象类型,可能是支持它的具体类(可能是一个空数组)。 “额外”是地图。试图将“Extra”解析为“Extras”是行不通的。为此,我建议以下“额外”的定义:

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>
}

在这种情况下,使用context.deserialize解决问题变得微不足道。

如上所述,TypeAdatper是解决此问题的完美有效解决方案。我只相信这比你需要的更多。

答案 3 :(得分:0)

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

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)
            }
        }
    }
}

}