2011-11-21 70 views
69

解析JSON這與前一個問題,我在這裏問早些時候使用枚舉而與GSON

JSON parsing using Gson

我試圖解析相同的JSON,但現在我已經改變了我班一點點。

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

我班現在看起來像:

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

此代碼拋出一個異常,

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 

唯一的例外是可以理解的,因爲每個解決我剛纔的問題是,GSON是預計Enum對象實際上被創建爲

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

但由於這在語法上是不可能的,因此建議的解決方案是什麼?

回答

37

the documentation for Gson

GSON提供枚舉默認序列化和反序列化......如果您希望更改默認的表示,你可以通過註冊一個GsonBuilder.registerTypeAdapter型適配器這樣做(類型,目的)。

以下是一種這樣的方法。

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; 
    } 
} 
+0

非常感謝。這工作。 –

+0

它的工作原理!謝謝!! –

20

使用註釋@SerializedName

@SerializedName("${title}") 
TITLE, 
@SerializedName("${description}") 
DESCRIPTION 
195

我想擴大一點NAZIK/user2724653答案(我的情況)。這裏是一個Java代碼:

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 
    } 
} 

在JSON文件你只有場"status": "N",,其中N = 0,1,2,3 - 取決於狀態值。就這樣,GSON與嵌套的enum類的值正常工作。在我的情況我已經分析的Items列表從json陣列:

List<Item> items = new Gson().<List<Item>>fromJson(json, 
              new TypeToken<List<Item>>(){}.getType()); 
+14

這個答案完美地解決了所有問題,不需要類型適配器! –

+1

Livesaver here :) –

+0

@SerializedName(N)爲枚舉做了這項工作;) – GuilhE

4

隨着GSON版本2.2.2枚舉將被整理,輕鬆地解組。

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; 
    } 
} 
0

如果你真的想用枚舉的序號值,你可以一個類型的適配器工廠來覆蓋GSON的默認出廠登記。

public class EnumTypeAdapter <T extends Enum<T>> extends TypeAdapter<T> { 
    private final Map<Integer, T> nameToConstant = new HashMap<>(); 
    private final Map<T, Integer> constantToName = new HashMap<>(); 

    public EnumTypeAdapter(Class<T> classOfT) { 
     for (T constant : classOfT.getEnumConstants()) { 
      Integer name = constant.ordinal(); 
      nameToConstant.put(name, constant); 
      constantToName.put(constant, name); 
     } 
    } 
    @Override public T read(JsonReader in) throws IOException { 
     if (in.peek() == JsonToken.NULL) { 
      in.nextNull(); 
      return null; 
     } 
     return nameToConstant.get(in.nextInt()); 
    } 

    @Override public void write(JsonWriter out, T value) throws IOException { 
     out.value(value == null ? null : constantToName.get(value)); 
    } 

    public static final TypeAdapterFactory ENUM_FACTORY = new TypeAdapterFactory() { 
     @SuppressWarnings({"rawtypes", "unchecked"}) 
     @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { 
      Class<? super T> rawType = typeToken.getRawType(); 
      if (!Enum.class.isAssignableFrom(rawType) || rawType == Enum.class) { 
       return null; 
      } 
      if (!rawType.isEnum()) { 
       rawType = rawType.getSuperclass(); // handle anonymous subclasses 
      } 
      return (TypeAdapter<T>) new EnumTypeAdapter(rawType); 
     } 
    }; 
} 

然後只需註冊工廠。

Gson gson = new GsonBuilder() 
       .registerTypeAdapterFactory(EnumTypeAdapter.ENUM_FACTORY) 
       .create();