java-Json Multiset与ArrayList

我有Multiset< String>对象,我将其序列化为Json.我正在使用Gson进行以下操作:

Multiset<String> mset = ... ;
Gson gson = new Gson();
Files.write(Gson.toJson(mset), new File(abosulte_path_string), Charset.defaultCharset());

当我尝试对其进行反序列化时,请执行以下操作:

String json_string = ... // read from file
Type type = new TypeToken<Multiset<String>>(){}.getType();
Multiset<String> treated = gson.fromJson(json_string, type);

我收到此错误:

java.lang.ClassCastException: java.util.ArrayList cannot be cast to com.google.common.collect.Multiset

当我打开json文件时,我看到Multiset< String>实际上,对象是用ArrayList([string1,string2,…])表示的,重复计数的计数大于等于2的字符串.多重集中的1.

我当然可以将其转换为ArrayList,然后使用create(Iterable<>)构造函数来获取我的多重集,但这似乎是一种回旋方式.有没有更直接的方法来反序列化json对象以检索我的多集?

解决方法:

编辑:看起来在这种情况下,有一个更简单的方法来解决此问题,即通过为多集注册一个instance creator

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

基本思想是注册一个custom deserialiser,它基本上会执行您已经发现的可能的解决方案:反序列化为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,只要它具有一个类型参数和一个默认构造函数即可.

也可能有更简单的方法来实现相同的目的,例如,您可以通过使用isJsonArray()之类的方法检查JsonElement来手动进行一些解析.这样可以避免创建ArrayList,然后立即丢弃它.

上一篇:c++关于multiset的头文件包含问题


下一篇:Maximal Intersection CodeForces - 1029C(贪心+multiset)