【发布时间】:2015-03-15 02:43:57
【问题描述】:
我需要使用 Gson 输出枚举值,由于客户端限制需要小写。
例如,CLOSE_FILE 将是 close_file。
有没有一种简单的方法可以做到这一点?我看过创建一个实现JsonSerializer 的类,但看起来我必须手动序列化整个类(这很复杂)是这种情况吗?
【问题讨论】:
我需要使用 Gson 输出枚举值,由于客户端限制需要小写。
例如,CLOSE_FILE 将是 close_file。
有没有一种简单的方法可以做到这一点?我看过创建一个实现JsonSerializer 的类,但看起来我必须手动序列化整个类(这很复杂)是这种情况吗?
【问题讨论】:
如果您可以控制enum 类型,请使用@SerializedName 注释其成员并为其赋予适当的序列化值。例如,
enum Action {
@SerializedName("close_file")
CLOSE_FILE;
}
如果您无法控制enum,请在创建Gson 实例时提供自定义TypeAdapter。例如,
Gson gson = new GsonBuilder().registerTypeAdapter(Action.class, new TypeAdapter<Action>() {
@Override
public void write(JsonWriter out, Action value) throws IOException {
out.value(value.name().toLowerCase());
}
@Override
public Action read(JsonReader in) throws IOException {
return Action.valueOf(in.nextString().toUpperCase());
}
}).create();
【讨论】:
Action 枚举注册。哦。 :P 是否可以注册所有枚举类型?
Enum 是所有枚举类型的超类型。序列化可能很容易,只需小写 name(),但反序列化需要更多关于反序列化到的实际类型的信息。
如果要将所有枚举序列化为小写,可以使用此代码
Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(Enum.class, new EnumToLowerCaseJsonConverter()).create();
public final class EnumToLowerCaseJsonConverter implements JsonSerializer<Enum<?>>, JsonDeserializer<Enum<?>> {
private static Map<String, Class<? extends Enum<?>>> typesToClass = new HashMap<>();
@Override
public JsonElement serialize(final Enum<?> src, final Type typeOfSrc,
final JsonSerializationContext context) {
if (src == null) {
return JsonNull.INSTANCE;
}
return new JsonPrimitive(src.name().toLowerCase());
}
@SuppressWarnings("unchecked")
@Override
public Enum<?> deserialize(final JsonElement json, final Type typeOfT,
final JsonDeserializationContext context) throws JsonParseException {
if (json == null || json.isJsonNull()) {
return null;
}
if (!json.isJsonPrimitive() || !json.getAsJsonPrimitive().isString()) {
throw new JsonParseException(
"Expecting a String JsonPrimitive, getting " + json.toString());
}
try {
final String enumClassName = typeOfT.getTypeName();
Class<? extends Enum<?>> clazz = typesToClass.get(enumClassName);
if (clazz == null) {
clazz = (Class<? extends Enum<?>>) Class.forName(enumClassName);
typesToClass.put(enumClassName, clazz);
}
return Enum.valueOf((Class) clazz, json.getAsString().toUpperCase());
} catch (final ClassNotFoundException e) {
throw new JsonParseException(e);
}
}
}
【讨论】:
一个易于使用的特定类型适配器:
Gson gson = new GsonBuilder().registerTypeAdapter(Action.class, new EnumToLowerCaseTypeAdapter<>(Action.class)).create();
public final class EnumToLowerCaseTypeAdapter<T extends Enum<?>> extends TypeAdapter<T> {
private final Class<T> clazz;
public EnumToLowerCaseTypeAdapter(final Class<T> clazz) {
this.clazz = clazz;
}
@Override
public void write(final JsonWriter out, final T value) throws IOException {
if (value == null) {
out.nullValue();
} else {
out.value(value.name().toLowerCase());
}
}
@SuppressWarnings("unchecked")
@Override
public T read(final JsonReader in) throws IOException {
switch (in.peek()) {
case NULL:
in.nextNull();
return null;
default:
final String value = in.nextString();
return (T) Enum.valueOf((Class) clazz, value.toUpperCase());
}
}
}
【讨论】: