[英]Change default enum serialization & deserialization in gson
I'm using Gson in a slightly "different" way and I'm wondering if the following is possible... 我正在以一种略微“不同”的方式使用Gson,我想知道以下是否可行......
I'd like to change the default serialization/deserialization format for enums so that it uses fully-qualified class names, but maintain support for the @SerializedName annotation on said enums. 我想更改枚举的默认序列化/反序列化格式,以便它使用完全限定的类名,但在所述枚举上保持对@SerializedName注释的支持。 Basically, given the following enum... 基本上,鉴于以下枚举...
package com.example;
public class MyClass {
public enum MyEnum {
OPTION_ONE,
OPTION_TWO,
@SerializedName("someSpecialName")
OPTION_THREE
}
}
I'd like the following to be true... 我想以下是真实的......
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"
and vice-versa. 反之亦然。
(for those curious, I'm trying to build a small lib that allows me to treat android's intent's actions as enums, so that I can write switch statements instead of a bunch of ugly if-elses + string compares, and I want to support the annotation so that I can also include custom pre-existing action strings like Intent.ACTION_VIEW, etc in the same enum). (对于那些好奇的人,我正在尝试构建一个小的lib,它允许我将android的intent的动作视为枚举,这样我就可以编写switch语句而不是一堆丑陋的if-elses + string比较,我想支持注释,以便我也可以在同一个枚举中包含自定义的预先存在的动作字符串,如Intent.ACTION_VIEW等。
So would anyone know if it's possible to register a type adapter that can fall back if the @SerializedName field is present? 那么有人会知道是否可以注册一个类型适配器,如果@SerializedName字段存在,它可以回退? Would I just have to check for that annotation myself in my own TypeAdapter? 我是否只需要在自己的TypeAdapter中检查该注释?
Thanks in advance. 提前致谢。
I created pretty nice solution for this issue : 我为这个问题创建了非常好的解决方案:
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;
}
}
}
and of course : 而且当然 :
new GsonBuilder().registerTypeAdapterFactory(new EnumAdapterFactory()).create();
Hope this helps ! 希望这可以帮助 !
Did some google-ing and found the source for Gson's EnumTypeAdapter and the related AdapterFactory here: https://code.google.com/p/google-gson/source/browse/trunk/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java#717 做了一些google-ing并找到了Gson的EnumTypeAdapter和相关AdapterFactory的来源: https : //code.google.com/p/google-gson/source/browse/trunk/gson/src/main/java/com/谷歌/ GSON /内部/结合/ TypeAdapters.java#717
From the looks of it, I would, in fact, have to check for the @SerializedName attribute manually, but it looks pretty simple to do. 从它的外观来看,我实际上必须手动检查@SerializedName属性,但看起来很简单。 I'm planning on copying-over both the adapter and adapter factory (almost line-for-line) and modifying the default value of name
(line 724) to include the full class name. 我打算复制适配器和适配器工厂(几乎逐行)并修改name
的默认值(第724行)以包含完整的类名。
The resulting TypeAdapter would look something like this... 生成的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));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.