2011-11-21 11 views
69

Esto se relaciona con una pregunta anterior que pedí aquí anteriormenteEl uso de enumeraciones al analizar JSON con GSON

JSON parsing using Gson

Estoy tratando de analizar el mismo JSON, pero ahora he cambiado mis clases un poco .

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

Mi clase ahora se ve así:

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

Este código genera una excepción,

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 

La excepción es comprensible, porque de acuerdo con la solución a mi pregunta anterior, GSON es esperando que los objetos Enum sean realmente creados como

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

Pero como esto es sintácticamente imposible, ¿cuáles son las soluciones recomendadas, las soluciones?

Respuesta

37

De the documentation for Gson:

Gson ofrece la serialización y deserialización por defecto para enumeraciones ... Si prefiere cambiar la representación por defecto, puede hacerlo mediante el registro de un adaptador tipo a través GsonBuilder.registerTypeAdapter (Tipo, Objeto).

El siguiente es uno de estos enfoques.

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

Muchas gracias. Esto funcionó. –

+0

¡Funciona! ¡¡Gracias!! –

20

Uso anotación @SerializedName:

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

quiero ampliar una respuesta poco nazik/user2724653 (en mi caso). Aquí hay un código 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 
    } 
} 

en el archivo JSON que tiene sólo un campo "status": "N",, donde N = 0,1,2,3 - depende de los valores de estado. Así que eso es todo, GSON funciona bien con los valores para la clase anidada enum. En mi caso he analizado sintácticamente una lista de Items de json matriz:

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

¡Esta respuesta resuelve todo perfectamente, sin necesidad de adaptadores de tipo! –

+1

Livesaver aquí :) –

+0

@SerializedName (N) para la enumeración hizo el trabajo;) – GuilhE

4

Con la versión 2.2.2 GSON enumeración a estar movilizados y unmarshalled fácilmente.

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

Si realmente desea utilizar valor ordinal de la enumeración se puede registrar un generador de adaptadores de tipo anular de fábrica por defecto de 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); 
     } 
    }; 
} 

Luego solo registre la fábrica.

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