Using Enums to parse JSON using GSON

This is related to the previous question I asked here earlier

Parsing JSON using Gson

I am trying to parse the same JSON, but now I have slightly modified my classes.

{ "lower": 20, "upper": 40, "delimiter": " ", "scope": ["${title}"] } 

Now my class is as follows:

 public class TruncateElement { private int lower; private int upper; private String delimiter; private List<AttributeScope> scope; // getters and setters } public enum AttributeScope { TITLE("${title}"), DESCRIPTION("${description}"), private String scope; AttributeScope(String scope) { this.scope = scope; } public String getScope() { return this.scope; } } 

This code throws an exception,

 com.google.gson.JsonParseException: The JsonDeserializer EnumTypeAdapter failed to deserialized json object "${title}" given the type class com.amazon.seo.attribute.template.parse.data.AttributeScope at 

The exception is clear because, according to the solution to my previous question, GSON expects Enum objects to actually be created as

 ${title}("${title}"), ${description}("${description}"); 

But since this is syntactically impossible, what are the recommended solutions, workarounds?

+93
java json gson
Nov 21 2018-11-11T00:
source share
7 answers

From the documentation for Gson :

Gson provides default serialization and deserialization for Enums ... If you prefer to change the default view, you can do this by registering a type adapter with GsonBuilder.registerTypeAdapter (Type, Object).

The following is one such approach.

 import java.io.FileReader; import java.lang.reflect.Type; import java.util.List; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; public class GsonFoo { public static void main(String[] args) throws Exception { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(AttributeScope.class, new AttributeScopeDeserializer()); Gson gson = gsonBuilder.create(); TruncateElement element = gson.fromJson(new FileReader("input.json"), TruncateElement.class); System.out.println(element.lower); System.out.println(element.upper); System.out.println(element.delimiter); System.out.println(element.scope.get(0)); } } class AttributeScopeDeserializer implements JsonDeserializer<AttributeScope> { @Override public AttributeScope deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { AttributeScope[] scopes = AttributeScope.values(); for (AttributeScope scope : scopes) { if (scope.scope.equals(json.getAsString())) return scope; } return null; } } class TruncateElement { int lower; int upper; String delimiter; List<AttributeScope> scope; } enum AttributeScope { TITLE("${title}"), DESCRIPTION("${description}"); String scope; AttributeScope(String scope) { this.scope = scope; } } 
+48
Nov 22 '11 at 7:44
source share

I want to reveal a little answer NAZIK / user2724653 (for my case). Here is the Java code:

 public class Item { @SerializedName("status") private Status currentState = null; // other fields, getters, setters, constructor and other code... public enum Status { @SerializedName("0") BUY, @SerializedName("1") DOWNLOAD, @SerializedName("2") DOWNLOADING, @SerializedName("3") OPEN } } 

in the json file you only have the "status": "N", field "status": "N", ,, where N = 0,1,2,3 - depends on the status values. So that’s it, GSON works great with values ​​for the enum nested class. In my case, I parsed the list of Items array from json :

 List<Item> items = new Gson().<List<Item>>fromJson(json, new TypeToken<List<Item>>(){}.getType()); 
+247
Sep 17 '13 at 13:32
source share

Use @SerializedName annotation:

 @SerializedName("${title}") TITLE, @SerializedName("${description}") DESCRIPTION 
+23
Aug 28 '13 at 8:52
source share

With GSON version 2.2.2, enumeration will be easy to sort without problems.

 import com.google.gson.annotations.SerializedName; enum AttributeScope { @SerializedName("${title}") TITLE("${title}"), @SerializedName("${description}") DESCRIPTION("${description}"); private String scope; AttributeScope(String scope) { this.scope = scope; } public String getScope() { return scope; } } 
+7
Nov 10
source share

The following snippet eliminates the need for explicit Gson.registerTypeAdapter(...) using the @JsonAdapter(class) annotation, available with Gson 2.3 (see pm_labs comment).

 @JsonAdapter(Level.Serializer.class) public enum Level { WTF(0), ERROR(1), WARNING(2), INFO(3), DEBUG(4), VERBOSE(5); int levelCode; Level(int levelCode) { this.levelCode = levelCode; } static Level getLevelByCode(int levelCode) { for (Level level : values()) if (level.levelCode == levelCode) return level; return INFO; } static class Serializer implements JsonSerializer<Level>, JsonDeserializer<Level> { @Override public JsonElement serialize(Level src, Type typeOfSrc, JsonSerializationContext context) { return context.serialize(src.levelCode); } @Override public Level deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { try { return getLevelByCode(json.getAsNumber().intValue()); } catch (JsonParseException e) { return INFO; } } } } 
+3
Mar 16 '18 at 9:57
source share

If you really want to use the ordinal value of Enum, you can register a type adapter factory to override the default Gson factory.

    EnumTypeAdapter < T extends Enum <T> >  TypeAdapter <T> {      <  , T > nameToConstant = new HashMap >();      < T, Integer > constantToName = new HashMap <>();  public EnumTypeAdapter ( <T> classOfT) {       for (T constant: classOfT.getEnumConstants()) {           Integer name = constant.ordinal();           nameToConstant.put(, );           constantToName.put(, );       }   }   @Override public T read (JsonReader in)  IOException {       if (in.peek() == JsonToken.NULL) {           in.nextNull();           return null;       }       return nameToConstant.get(in.nextInt());   }  @Override public void write (JsonWriter out,  T)  IOException {       out.value(value == null? null: constantToName.get());   }  public static final TypeAdapterFactory ENUM_FACTORY =  TypeAdapterFactory() {       @SuppressWarnings ({ "rawtypes", "unchecked" })       @Override public <T> TypeAdapter <  > create (Gson gson, TypeToken <T> typeToken) {            <?  T > rawType = typeToken.getRawType();           if (! Enum.class.isAssignableFrom(rawType) || rawType == Enum.class) {               return null;           }           if (! rawType.isEnum()) {               rawType = rawType.getSuperclass();//             }           return (TypeAdapter <T>)  EnumTypeAdapter (rawType);       }   }; } > 

Then just register the factory.

  Gson gson = new GsonBuilder()              .registerTypeAdapterFactory(EnumTypeAdapter.ENUM_FACTORY)              .(); > 
+1
Mar 09 '18 at 17:28
source share

use this method

 GsonBuilder.enableComplexMapKeySerialization(); 
-one
Aug 11 '18 at 18:29
source share



All Articles