2012-01-30 108 views
22

我有一個枚舉:GSON不區分大小寫的枚舉反序列

enum Type { 
    LIVE, UPCOMING, REPLAY 
} 

和一些JSON:

{ 
    "type": "live" 
} 

和A類:

class Event { 
    Type type; 
} 

當我嘗試反序列化JSON,使用GSON,我收到nullEvent類型字段,因爲類型字段的情況在JSON與該枚舉的不匹配。

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()); 
    } 
} 

回答

18

便利對你來說,這是非常接近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); 
    } 
} 
+0

請注意,上述代碼僅對小寫值的精確匹配才正確_serializes_小寫的Enum值和_deserializes_。 要執行不區分大小寫的反序列化,請修改read()方法: 'return lowercaseToConstant.get(toLowercase(reader.nextString()))''。 要使用原始大小寫序列化,請修改write()方法: 'out.value(value.toString())'。 – nivs 2017-10-24 23:33:05

86

更簡單的方法,我發現(剛纔)要做到這一點是使用@SerializedName註解。我發現它在這裏的EnumTest.java(約LN 195 Gender類):

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

這是假設所有的類型將前來爲小寫字母而不是作爲「不區分大小寫」

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

    @SerializedName("upcoming") 
    UPCOMING, 

    @SerializedName("replay") 
    REPLAY; 
} 

這是我發現的最簡單最普通的方式。希望它可以幫助你。

+2

如果只有我可以給你更多的積分......或者像啤酒或棒棒糖。 – Spedge 2014-01-16 15:42:44

+0

這真的很整齊。以整個安卓團隊的名義:thx :) – balazsbalazs 2014-01-23 11:57:08

+2

這應該是被接受的答案 – 2014-11-18 10:36:21

5

這是一個相當古老的問題,但接受的答案並不適用於我,並且使用@SerializedName還不夠,因爲我想確保我可以匹配"value""Value""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; 
     } 
    } 
} 

,並使用它:

GsonBuilder gsonBuilder = new GsonBuilder(); 
gsonBuilder.registerTypeAdapter(MyEnum.class, new UppercaseEnumAdapter()); 
Gson gson = gsonBuilder.create(); 
6

現在你可以像這樣@SerializedName添加多個值:

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

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

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

我覺得對你有點遲,但我希望它能幫助其他人!