我们有一个将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?如果我们尝试添加此新卡,但应用程序不支持该卡,则我想忽略它。
答案 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");
...