编辑:在这种情况下,似乎有一种更简单的方法可以解决这个问题,即为 Multisets 注册一个实例创建者:
private static class MultisetInstanceCreator implements InstanceCreator<Multiset<?>> {
@Override
public Multiset<?> createInstance(Type type) {
return HashMultiset.create();
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(Multiset.class, new MultisetInstanceCreator())
.create();
实例创建者只定义了应该如何创建 Multiset,因为 Guava 集合没有默认构造函数(无论如何 Multiset 是接口)。
原始答案:我不确定这是否是实现您想要的最好或最简单的方法,但这是最近对我们有用的一种类似问题的方法(在我们的例子中,它是反序列化为 ImmutableMap)。
基本思想是注册一个自定义反序列化器,它基本上可以完成您已经发现的可能解决方案:反序列化为 ArrayList,然后将其转换为 Multiset。这里的优点是您只需注册一次自定义反序列化器,而不必知道任何地方首先使用 ArrayList 类型。
此自定义反序列化器如下所示:
private static class MultisetDeserializer implements JsonDeserializer<Multiset<?>> {
@Override
public Multiset<?> deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
ParameterizedType listType = new ListParameterizedType(typeArguments);
List<?> list = context.deserialize(json, listType);
return HashMultiset.create(list);
}
}
简而言之,这会将预期的类型转换为反序列化(例如new TypeToken<Multiset<String>>(){}.getType()
在您的情况下)以ParameterizedType
获取类型参数(在您的示例中为 String)。然后它创建一个新的 ParameterizedType,它是具有相同类型参数的 ArrayList 的类型(如下所示)。在使用上下文将 JSON 反序列化为这种新类型之后,您所要做的就是调用HashMultiset.create
.
ListParameterizedType
看起来像这样:
private static class ListParameterizedType implements ParameterizedType {
private final Type[] typeArguments;
private ListParameterizedType(Type[] typeArguments) {
this.typeArguments = typeArguments;
}
@Override
public Type[] getActualTypeArguments() {
return typeArguments;
}
@Override
public Type getRawType() {
return ArrayList.class;
}
@Override
public Type getOwnerType() {
return null;
}
}
请注意,您可以ArrayList
在此处替换为几乎任何列表类,只要它具有一个类型参数和一个默认构造函数。
也可能有更简单的方法来实现相同的目标,例如,您可以通过JsonElement
使用其方法(如isJsonArray()
. 这可以使您免于创建 ArrayList 之后立即丢弃。