2011-11-21 35 views
69

này liên quan đến một câu hỏi trước mà tôi hỏi ở đây trướcSử dụng Enums trong khi phân tích JSON với GSON

JSON parsing using Gson

Tôi cố gắng để phân tích cú pháp JSON như nhau, nhưng bây giờ tôi đã thay đổi lớp học của tôi một chút .

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

lớp của tôi bây giờ trông giống như:

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

Mã này ném một ngoại lệ,

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 

Trường hợp ngoại lệ là điều dễ hiểu, bởi vì theo giải pháp cho câu hỏi trước đây của tôi, GSON là mong các đối tượng Enum thực sự được tạo thành

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

Nhưng vì đây là cú pháp không thể, các giải pháp được đề xuất, giải pháp là gì?

Trả lời

37

Từ the documentation for Gson:

Gson cung cấp serialization mặc định và deserialization cho Enums ... Nếu bạn muốn thay đổi đại diện mặc định, bạn có thể làm như vậy bằng cách đăng ký một bộ chuyển đổi loại hình thông qua GsonBuilder.registerTypeAdapter (Type, Vật).

Sau đây là một cách tiếp cận như vậy.

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

Cảm ơn rất nhiều. Điều này làm việc. –

+0

Nó hoạt động !! Cảm ơn!! –

20

Sử dụng chú thích @SerializedName:

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

tôi muốn mở rộng một câu trả lời chút NAZIK/user2724653 (đối với trường hợp của tôi). Đây là một mã 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 
    } 
} 

trong tệp json bạn chỉ có một trường "status": "N",, trong đó N = 0,1,2,3 - phụ thuộc vào giá trị Trạng thái. Vì vậy, đó là tất cả, GSON hoạt động tốt với các giá trị cho lớp lồng nhau enum. Trong trường hợp của tôi, tôi đã phân tích một danh sách các Items từ json mảng:

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

Câu trả lời này giải quyết mọi thứ một cách hoàn hảo, không cần bộ điều hợp loại! –

+1

Livesaver ở đây :) –

+0

@SerializedName (N) cho enum đã làm công việc;) – GuilhE

4

Với phiên bản 2.2.2 GSON enum sẽ được marshalled và unmarshalled dễ dàng.

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

Nếu bạn thực sự muốn sử dụng giá trị thứ tự của Enum, bạn có thể đăng ký nhà máy bộ chuyển đổi loại để ghi đè nhà máy mặc định của 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); 
     } 
    }; 
} 

Sau đó, chỉ cần đăng ký nhà máy.

Gson gson = new GsonBuilder() 
       .registerTypeAdapterFactory(EnumTypeAdapter.ENUM_FACTORY) 
       .create(); 
Các vấn đề liên quan