Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GSON Case-Insensitive Enum Deserialization

I have an enum:

enum Type {     LIVE, UPCOMING, REPLAY }  

And some JSON:

{     "type": "live" } 

And a class:

class Event {     Type type; } 

When I try to deserialize the JSON, using GSON, I receive null for the Event type field, since the case of the type field in the JSON does not match that of the enum.

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

If I change the enum to the following, then all works fine:

enum Type {     live, upcoming, replay } 

However, I would like to leave the enum constants as all uppercase.

I'm assuming I need to write an adapter but haven't found any good documentation or examples.

What is the best solution?


Edit:

I was able to get a JsonDeserializer working. Is there a more generic way to write this though, as it would be unfortunate to have to write this each time there is a case mismatch between enum values and JSON strings.

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());     } } 
like image 290
Steve Avatar asked Jan 30 '12 13:01

Steve


2 Answers

A simpler way I found (just now) to do this is to use the @SerializedName annotation. I found it in the EnumTest.java here (the Gender class around ln 195):

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

This assumes that all of your Types will come in as lowercase as opposed to being "case insensitive"

public enum Type {     @SerializedName("live")     LIVE,      @SerializedName("upcoming")     UPCOMING,      @SerializedName("replay")     REPLAY; }  

This was the simplest and most generic way I found to do this. Hope it helps you.

like image 140
prodaea Avatar answered Oct 05 '22 01:10

prodaea


Conveniently for you, this is very close to the example given in TypeAdapterFactory's Javadoc:

public class CaseInsensitiveEnumTypeAdapterFactory 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(toLowercase(reader.nextString()));         }       }     };   }    private String toLowercase(Object o) {     return o.toString().toLowerCase(Locale.US);   } } 
like image 23
Jesse Wilson Avatar answered Oct 05 '22 02:10

Jesse Wilson