繁体   English   中英

使用gson序列化具有泛型类型的类?

[英]Serialize class with generic type using gson?

我有以下课程

private static class ClassWithGenericType<T> {
    Set<T> values;
}

如果我现在用一Set Enum初始化类,使用 gson 序列化和反序列化对象,则反序列化对象的Set不包含Enum值,但值为String

我认为这是因为通过序列化丢弃了泛型类型。 我看到,我可以使用new TypeToken<...>(){}.getType(); ,但问题是,上面的类是更大对象的一部分,所以我不能直接调用gson.fromJson(classWithGenericType, typeToken)

有没有聪明的方法来解决这个问题? 我想到了一个TypeAdapter ,它不仅序列化Set的值,而且序列化它的类型。

我现在找到了一个解决方案并创建了一个TypeAdapter

public class SetTypeAdapterFactory implements TypeAdapterFactory {
    @Override
    public <T> TypeAdapter<T> create(Gson gson, @NonNull TypeToken<T> type) {
        if (!Set.class.isAssignableFrom(type.getRawType())) {
            return null;
        }
        return (TypeAdapter<T>) new SetTypeAdapter(gson);
    }
}

public class SetTypeAdapter extends TypeAdapter<Set<?>> {
    public static final String TYPE = "@type";
    public static final String DATA = "@data";
    private final Gson gson;

    public SetTypeAdapter(@NonNull Gson gson) {
        this.gson = gson;
    }

    @Override
    public void write(final JsonWriter out, final Set<?> set
    ) throws IOException {
        out.beginArray();
        for (Object item : set) {
            out.beginObject();
            out.name(TYPE).value(item.getClass().getName());
            out.name(DATA).jsonValue(gson.toJson(item));
            out.endObject();
        }
        out.endArray();
    }

    @Override
    public Set<?> read(final JsonReader in) throws IOException {
        final Set<Object> set = Sets.newHashSet();
        in.beginArray();
        while (in.hasNext()) {
            in.beginObject();
            set.add(readNextObject(in));
            in.endObject();
        }
        in.endArray();
        return set;
    }

    private Object readNextObject(JsonReader in) throws IOException {
        try {
            checkNextName(in, TYPE);
            Class<?> cls = Class.forName(in.nextString());
            checkNextName(in, DATA);
            return gson.fromJson(in, cls);
        } catch (ClassNotFoundException exception) {
            throw new IOException(exception);
        }
    }

    private void checkNextName(JsonReader in, String name) throws IOException {
        if (!in.nextName().equals(name)) {
            throw new IOException("Name was not: " + name);
        }
    }
}

我们可以将工厂添加到GsonBuilder ,然后我们可以使用泛型类型序列化Set

var gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapterFactory(new SetTypeAdapterFactory());
var gson = gsonBuilder.create();

序列化的Set具有以下结构:

[
  {
    "@type":<class_name_first_element>,
    "@data":<first_element_as_json>
  }, 
  ...
]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM