GSON非区分大小写的Enum反序列化

时间:2012-01-30 13:14:29

标签: gson

我有一个枚举:

enum Type {
    LIVE, UPCOMING, REPLAY
}

还有一些JSON:

{
    "type": "live"
}

一堂课:

class Event {
    Type type;
}

当我尝试使用GSON反序列化JSON时,我收到null类型字段的Event,因为JSON中类型字段的情况与枚举的情况不匹配。< / p>

Events events = new Gson().fromJson(json, Event.class);

如果我将枚举更改为以下内容,那么一切正常:

enum Type {
    live, upcoming, replay
}

但是,我想将枚举常量保留为全部大写。

我假设我需要编写一个适配器,但没有找到任何好的文档或示例。

什么是最佳解决方案?


修改

我能够让JsonDeserializer正常工作。有没有更通用的方法来编写它,因为每次枚举值和JSON字符串之间的情况不匹配时都必须写这个。

protected static class TypeCaseInsensitiveEnumAdapter implements JsonDeserializer<Type> {
    @Override
    public Type deserialize(JsonElement json, java.lang.reflect.Type classOfT, JsonDeserializationContext context)
            throws JsonParseException {         
        return Type.valueOf(json.getAsString().toUpperCase());
    }
}

4 个答案:

答案 0 :(得分:89)

我发现(刚才)这样做的一种简单方法是使用@SerializedName注释。我在EnumTest.java这里找到了它(195左右的Gender类):

https://code.google.com/p/google-gson/source/browse/trunk/gson/src/test/java/com/google/gson/functional/EnumTest.java?r=1230

这假设您的所有类型都将以小写形式出现,而不是“#34;不区分大小写”#34;

public enum Type {
    @SerializedName("live")
    LIVE,

    @SerializedName("upcoming")
    UPCOMING,

    @SerializedName("replay")
    REPLAY;
}

这是我发现的最简单,最通用的方法。希望它可以帮到你。

答案 1 :(得分:19)

方便的是,这与TypeAdapterFactory's Javadoc中给出的示例非常接近:

public class LowercaseEnumTypeAdapterFactory implements TypeAdapterFactory {
  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    Class<T> rawType = (Class<T>) type.getRawType();
    if (!rawType.isEnum()) {
      return null;
    }

    final Map<String, T> lowercaseToConstant = new HashMap<String, T>();
    for (T constant : rawType.getEnumConstants()) {
      lowercaseToConstant.put(toLowercase(constant), constant);
    }

    return new TypeAdapter<T>() {
      public void write(JsonWriter out, T value) throws IOException {
        if (value == null) {
          out.nullValue();
        } else {
          out.value(toLowercase(value));
        }
      }

      public T read(JsonReader reader) throws IOException {
        if (reader.peek() == JsonToken.NULL) {
          reader.nextNull();
          return null;
        } else {
          return lowercaseToConstant.get(reader.nextString());
        }
      }
    };
  }

  private String toLowercase(Object o) {
    return o.toString().toLowerCase(Locale.US);
  }
}

答案 2 :(得分:10)

这是一个相当古老的问题,但接受的答案对我不起作用,使用@SerializedName是不够的,因为我想确保我可以匹配"value""Value"和{ {1}}。

我设法根据问题中发布的代码制作通用适配器:

"VALUE"

使用它:

public class UppercaseEnumAdapter implements JsonDeserializer<Enum> {
    @Override
    public Enum deserialize(JsonElement json, java.lang.reflect.Type type, JsonDeserializationContext context)
            throws JsonParseException {
        try {
            if(type instanceof Class && ((Class<?>) type).isEnum())
                return Enum.valueOf((Class<Enum>) type, json.getAsString().toUpperCase());
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

答案 3 :(得分:9)

现在您可以为@SerializedName添加多个值,如下所示:

public enum Type {
    @SerializedName(value = "live", alternate = {"LIVE"})
    LIVE,

    @SerializedName(value = "upcoming", alternate = {"UPCOMING"})
    UPCOMING,

    @SerializedName(value = "replay", alternate = {"REPLAY"})
    REPLAY;
}

我认为对你来说有点晚了,但我希望它会对其他人有所帮助!