【问题标题】:Change default enum serialization & deserialization in gson更改 gson 中的默认枚举序列化和反序列化
【发布时间】:2014-06-09 17:27:41
【问题描述】:

我正在以稍微“不同”的方式使用 Gson,我想知道以下是否可行...

我想更改枚举的默认序列化/反序列化格式,以便它使用完全限定的类名,但保持对所述枚举上的 @SerializedName 注释的支持。基本上,给定以下枚举...

package com.example;
public class MyClass {
    public enum MyEnum {

        OPTION_ONE, 

        OPTION_TWO, 

        @SerializedName("someSpecialName")
        OPTION_THREE
    }
}

我希望以下内容属实……

gson.toJson(MyEnum.OPTION_ONE) == "com.example.MyClass.MyEnum.OPTION_ONE"
&&
gson.toJson(MyEnum.OPTION_TWO) == "com.example.MyClass.MyEnum.OPTION_TWO"
&&
gson.toJson(MyEnum.OPTION_THREE) == "someSpecialName"

反之亦然。

(对于那些好奇的人,我正在尝试构建一个小库,让我可以将 android 的意图操作视为枚举,这样我就可以编写 switch 语句而不是一堆丑陋的 if-else + 字符串比较,而且我希望支持注释,以便我还可以在同一个枚举中包含自定义的预先存在的操作字符串,如 Intent.ACTION_VIEW 等)。

那么有谁知道如果存在@SerializedName 字段,是否可以注册一个可以回退的类型适配器?我是否只需要自己在自己的 TypeAdapter 中检查该注释?

提前致谢。

【问题讨论】:

    标签: java serialization enums gson


    【解决方案1】:

    我为这个问题创建了非常好的解决方案:

    package your.package.name
    import com.google.gson.Gson;
    import com.google.gson.TypeAdapter;
    import com.google.gson.TypeAdapterFactory;
    import com.google.gson.reflect.TypeToken;
    import com.google.gson.stream.JsonReader;
    import com.google.gson.stream.JsonWriter;
    import java.io.IOException;
    import java.lang.reflect.Field;
    
    public class EnumAdapterFactory implements TypeAdapterFactory {
    
        @Override
        public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
            Class<? super T> rawType = type.getRawType();
            if (rawType.isEnum()) {
                return new EnumTypeAdapter<T>();
            }
            return null;
        }
    
        public class EnumTypeAdapter<T> extends TypeAdapter<T> {
    
            public void write(JsonWriter out, T value) throws IOException {
                if (value == null) {
                    out.nullValue();
                    return;
                }
                Enum<?> realEnums = Enum.valueOf(value.getClass().asSubclass(Enum.class), value.toString());
                Field[] enumFields = realEnums.getClass().getDeclaredFields();
                out.beginObject();
                out.name("name");
                out.value(realEnums.name());
                for (Field enumField : enumFields) {
                    if (enumField.isEnumConstant() || enumField.getName().equals("$VALUES")) {
                        continue;
                    }
                    enumField.setAccessible(true);
                    try {
                        out.name(enumField.getName());
                        out.value(enumField.get(realEnums).toString());
                    } catch (Throwable th) {
                        out.value("");
                    }
                }
                out.endObject();
            }
    
            public T read(JsonReader in) throws IOException {
                return null;
            }
        }
    }
    

    当然还有:

    new GsonBuilder().registerTypeAdapterFactory(new EnumAdapterFactory()).create();
    

    希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      做了一些 google-ing 并在这里找到了 Gson 的 EnumTypeAdapter 和相关 AdapterFactory 的来源:https://code.google.com/p/google-gson/source/browse/trunk/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java#717

      从外观上看,事实上,我必须手动检查@SerializedName 属性,但它看起来很简单。我计划复制适配器和适配器工厂(几乎是逐行)并修改name(第724行)的默认值以包含完整的类名。

      生成的 TypeAdapter 看起来像这样......

      private static final class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
          private final Map<String, T> nameToConstant = new HashMap<String, T>();
          private final Map<T, String> constantToName = new HashMap<T, String>();
      
          public EnumTypeAdapter(Class<T> classOfT) {
            try {
              String classPrefix = classOfT.getName() + ".";
              for (T constant : classOfT.getEnumConstants()) {
                String name = constant.name();
                SerializedName annotation = classOfT.getField(name).getAnnotation(SerializedName.class);
                if (annotation != null) {
                  name = annotation.value();
                } else {
                  name = classPrefix + name;
                }
                nameToConstant.put(name, constant);
                constantToName.put(constant, name);
              }
            } catch (NoSuchFieldException e) {
              throw new AssertionError();
            }
          }
      
          public T read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
              in.nextNull();
              return null;
            }
            return nameToConstant.get(in.nextString());
          }
      
          public void write(JsonWriter out, T value) throws IOException {
            out.value(value == null ? null : constantToName.get(value));
          }
      }
      

      【讨论】:

      猜你喜欢
      • 2013-05-20
      • 1970-01-01
      • 2021-11-28
      • 1970-01-01
      • 1970-01-01
      • 2021-11-30
      • 1970-01-01
      • 2012-09-10
      相关资源
      最近更新 更多