【问题标题】:Using a value of the enum to serialize with Gson使用枚举的值与 Gson 进行序列化
【发布时间】:2020-07-08 17:11:03
【问题描述】:

我为我的 Java 项目创建了两个枚举,它们都需要使用 Gson 进行序列化和反序列化。问题是,我需要在每个枚举字段上使用一个值作为序列化值。

例如,我有这些枚举:

Options Enum

Language Enum

我希望我能够使用提供给两者的key 值来序列化这两个枚举。这是一个非常简化的示例,但它仍然完美地描述了我的情况。

我尝试对两者都使用自定义序列化程序类:

Options Serializer

Language Serializer

是的,我确实使用 registerTypeAdapter(type, adapter) 注册了两者

奇怪的是,它适用于一个枚举,序列化为正确的值,但不是另一个。我怀疑这是因为被序列化的类的格式类似于:

public class Item {
    public Language language;
    public List<Options> options;
}

在这种情况下,Language 被正确序列化,但 Options 枚举不是,只是返回枚举值名称。

我不确定我是否需要一些特殊的方法来处理这个问题,但这越来越令人沮丧。

编辑:我知道使用 @SerializedName() 注释,但我使用的两个枚举都有数百个条目,并且作为枚举一部分的键在整个程序的其他地方使用也是。使用@SerializedName(),至少在我的情况下,我认为不可行。

【问题讨论】:

    标签: java json serialization enums gson


    【解决方案1】:

    为 Item 编写一个适配器。我会添加更多,但笔记本电脑占 1%。

        static class ItemAdapter extends TypeAdapter<Item> {
    
            @Override
            public void write(JsonWriter out, Item value) throws IOException {
                out.beginObject();
                out.name("language").value(value.language.key);
                out.name("options");
                out.beginArray();
                for (Option option : value.options) {
                    out.value(option.key);
                }
                out.endArray();
                out.endObject();
            }
    
            @Override
            public Item read(JsonReader in) throws IOException {
                in.beginObject();
    
                in.nextName();
                String languageKey = in.nextString();
    
                in.nextName();
                in.beginArray();
    
                List<String> optionKeys = new ArrayList<>();
    
                while (in.hasNext()) {
                    optionKeys.add(in.nextString());
                }
                in.endArray();
    
                in.endObject();
    
                return new Item(Language.BY_KEY.get(languageKey),
                        optionKeys.stream()
                                .map(Option.BY_KEY::get)
                                .collect(Collectors.toList()));
            }
        }
    

    【讨论】:

    • 那么一个TypeAdapter而不是使用JsonSerializer和JsonDeserializer?
    • @MattChris 我否决了这个答案,因为它具有误导性,因为它没有解释您的实现与这个实现之间的区别。 JsonSerializer/JsonDeserializer 只是一种特殊的类型适配器,中间有 JSON 对象,这会降低性能。你的实现工作很好。你确定你注册了两个枚举类型的适配器吗?你真正的 JSON 结果是什么? JSON 枚举输出有什么不同?您是如何使用 GsonBuilder 创建 Gson 实例的?接受的答案如何解决这些问题?
    • 公认的答案解决方案也有很多缺陷: 1) Gson 可以处理 Item 类本身,包括 @SerializedName 等很酷的东西,字段命名策略; 2)如果你有另一个“项目”类怎么办? 3)这个解决方案是不容忍零值的; 4) 它也完全忽略了读取 JSON 属性的真实顺序; 5) 它不会将实例列表实例化委托给 Gson 核心。
    • @fluffy 我已经提出了关于 SerializedName 的答案,但作者指出他有太多的枚举元素并且使用 SerializedName 不是一个可行的解决方案。尽管如此,我很欣赏您的意见,但这是一个可行的解决方案。
    • @MattChris 是的,因此 TypeAdapter 将允许您自定义编码和解码 Enum 的方式,这正是您想要的。您不一定要始终使用给定字段对 Language 和 Option 枚举进行编码,但是在 Item 的特定情况下,您希望以特定方式进行编码和解码。这就是为什么为Item 设置TypeAdapter 是一个可行的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2013-07-17
    • 2021-11-28
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 2015-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多