【问题标题】:Gson Enum serializationGson 枚举序列化
【发布时间】:2017-02-07 08:46:22
【问题描述】:

我在我的 java web 应用程序中使用gson 将我的 api 模型序列化为 json 对象。
我已成功地将其注释用于版本化模型,但我无法序列化 Enum 对象。

动作类

public enum Action {

    @SerializedName("create") CREATE,
    @SerializedName("read") READ;

}

尝试序列化 Hashtable 或另一个使用此枚举的 pojo,我得到大写字母的字符串。

...
Gson gson = new GsonBuilder.create();
Hashtable<Action, String> table = new Hashtable<>();
table.put(Action.CREATE, "");
gson.toJson(table) // => { "CREATE" : "" } instead of { "create" : "" }
...

我做错了什么?

【问题讨论】:

  • 如果你有一个值为枚举的字段会发生什么? (另外,Hashtable 几乎不应该在新代码中使用;您可能需要HashMap。)
  • 将枚举用作另一个类的字段。序列化函数将枚举转换为小写。顺便说一句,我正在处理现有代码,因此将哈希表更改为 hashmap 可能会破坏一些代码,所以我现在不会触及它。
  • 所以听起来使用@SerializedName 作为地图键存在特定问题?
  • Lower case enum Gson的可能重复
  • 好吧,这不可能是重复的,因为那里写的答案对我来说不起作用......

标签: java serialization enums gson


【解决方案1】:

当您将enableComplexMapKeySerialization 选项添加到您的 Gson 实例时,您的代码将按预期工作。

https://google.github.io/gson/apidocs/com/google/gson/GsonBuilder.html#enableComplexMapKeySerialization--

Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create();

【讨论】:

    【解决方案2】:

    除了您的问题的 cmets(MapTypeAdapterFactory 不是 @SerializedName-aware)解释了为什么它不适用于地图并建议尽可能更改您的数据交换模型,您可以使用自定义 @987654323 @如果你真的必须使用像MapHashtable这样的数据包:

    private static final TypeToken<?> actionToUnknownHashtableTypeToken = new TypeToken<Hashtable<Action, ?>>() {
    };
    

    请注意,类型标记用于更精确地定位可序列化枚举并缓存内部序列化名称映射:

    final Gson gson = new GsonBuilder()
            .registerTypeAdapter(actionToUnknownHashtableTypeToken.getType(), getSerializedNameEnumHashtableJsonSerializer(Action.class))
            .create();
    final Hashtable<Action, String> table = new Hashtable<>();
    table.put(CREATE, "item");
    out.println(gson.toJson(table, actionToUnknownHashtableTypeToken.getType()));
    

    还要注意toJson 方法的使用。因此,您创建的每个特定枚举 @SerializedName-aware 都可以单独注册。还有序列化器本身:

    final class SerializedNameEnumHashtableJsonSerializer<K extends Enum<K>, V>
            implements JsonSerializer<Hashtable<K, V>> {
    
        private final Map<K, String> serializedNames;
    
        private SerializedNameEnumHashtableJsonSerializer(final Map<K, String> serializedNames) {
            this.serializedNames = serializedNames;
        }
    
        static <K extends Enum<K>, V> JsonSerializer<Hashtable<K, V>> getSerializedNameEnumHashtableJsonSerializer(final Class<K> enumClass) {
            try {
                final Map<K, String> serializedNames = new HashMap<>();
                for ( final K enumConstant : enumClass.getEnumConstants() ) {
                    final String enumName = enumConstant.name();
                    final Field field = enumClass.getField(enumName);
                    final SerializedName serializedName = field.getAnnotation(SerializedName.class);
                    if ( serializedName != null ) {
                        serializedNames.put(enumConstant, serializedName.value());
                    }
                }
                return new SerializedNameEnumHashtableJsonSerializer<>(unmodifiableMap(serializedNames));
            } catch ( final NoSuchFieldException ex ) {
                throw new AssertionError(ex);
            }
        }
    
        @Override
        public JsonElement serialize(final Hashtable<K, V> hashtable, final Type type, final JsonSerializationContext context) {
            final JsonObject jsonObject = new JsonObject();
            for ( final Entry<K, V> e : hashtable.entrySet() ) {
                final K key = e.getKey();
                final String nameCandidate = serializedNames.get(key);
                final String serializedName = nameCandidate != null ? nameCandidate : key.name();
                jsonObject.add(serializedName, context.serialize(e.getValue()));
            }
            return jsonObject;
        }
    
    }
    

    还要注意上面的序列化器只处理SerializedName.value,并不关心SerializedName.alternate。输出:

    {"创建":"项目"}

    请注意,这仅适用于键,不会影响@SerializedName,它可能出现在作为序列化映射中的值的枚举中。上面的示例也可以重新设计以自动处理任何枚举,并且不需要在 GsonBuilders 中注册每个这样的映射或哈希表(必须重新分析每个 serialize 方法中的 @SerializedName 注释,可能使用缓存机制),但它会为您提供一些设计选择。

    【讨论】:

      猜你喜欢
      • 2021-11-28
      • 2013-05-20
      • 2015-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-22
      • 2017-04-07
      相关资源
      最近更新 更多