忽略RuntimeTypeAdapterFactory

时间:2018-09-14 13:39:21

标签: java android json gson retrofit

我们有一个将GSON用作转换器的Retrofit API,它要求将卡片列表显示给用户。卡遵循以下格式:

[
    {
        "cardType": "user",
        "data": {}
    },
    {
        "cardType": "content",
        "data": {}
    }
]

data属性在卡片之间有所不同,因此,为了解决此问题,我们使用GSON的RuntimeTypeAdapterFactory

final RuntimeTypeAdapterFactory<Card> factory = RuntimeTypeAdapterFactory
        .of(Card.class, "cardType")
        .registerSubtype(UserCard.class, "user")
        ...
        .registerSubtype(ContentCard.class, "content");

但是,我们发现,如果将API更新为包含我们不期望的 new cardType,则它会自动反序列化。我的意思是,response.isSuccessful()仍然返回true,但是response.body()为null。我们能够确定新卡类型的唯一方法是通过反复试验来解决问题。

有什么办法让GSON忽略我们尚未注册的任何cardType?如果我们尝试添加此新卡,但应用程序不支持该卡,则我想忽略它。

1 个答案:

答案 0 :(得分:1)

我们遇到了类似的问题,但GSON并没有那么沉默。我们遇到了错误:

  

无法反序列化名为Y的X子类型;你忘了注册一个   亚型?

要实现@pirho的解决方案,我们将RuntimeTypeAdapterFactory复制到了我们的项目中。

1。)添加一个新字段

private final Map<String, Class<?>> labelToSubtype = new LinkedHashMap<String, Class<?>>();
private final Map<Class<?>, String> subtypeToLabel = new LinkedHashMap<Class<?>, String>();
private final List<String> labelsToIgnore = new ArrayList<>(); // ADD THIS LINE

2。)添加新方法:

public RuntimeTypeAdapterFactory<T> ignoreSubtype(String label) {
    labelsToIgnore.add(label);
    return this;
}

3。)更新read中的TypeAdapter方法:

public R read(final JsonReader in) {
    JsonElement jsonElement = Streams.parse(in);
    JsonElement labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName);
    if (labelJsonElement == null) {
        throw new JsonParseException("cannot deserialize " + baseType
                + " because it does not define a field named " + typeFieldName);
    }
    String label = labelJsonElement.getAsString();
    @SuppressWarnings("unchecked") // registration requires that subtype extends T
            TypeAdapter<R> delegate = (TypeAdapter<R>) labelToDelegate.get(label);
    if (delegate == null) {
        // ------------- ADD THIS:
        if (labelsToIgnore.contains(label)) {
            return null;
        } else {
            throw new JsonParseException("cannot deserialize " + baseType + " subtype named "
                    + label + "; did you forget to register a subtype?");
        }
        // -------------
    }
    return delegate.fromJsonTree(jsonElement);
}

最后像这样使用它:

RuntimeTypeAdapterFactory<BaseClass> myTypeAdapterFactory 
= RuntimeTypeAdapterFactory
                .of(BaseClass.class, "type")
                .ignoreSubtype("type to ignore") // ADD THIS LINE
                .registerSubtype(SubtypeA.class, "type_a")
                .registerSubtype(SubtypeB.class, "type_b");          
                ...