2011-11-21 20 views
69

Questo è legato ad una precedente interrogazione che ho chiesto qui in precedenzaUtilizzando enumerazioni durante l'analisi JSON con GSON

JSON parsing using Gson

Sto cercando di analizzare la stessa JSON, ma ora ho cambiato le mie classi un po ' .

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

mia classe ora assomiglia:

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

Questo codice genera un'eccezione,

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 

L'eccezione è comprensibile, perché come per la soluzione alla mia precedente interrogazione, GSON è mi aspettavo che gli oggetti Enum fossero effettivamente creati come

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

Ma poiché questo è sintatticamente impossibile, quali sono le soluzioni consigliate, soluzioni alternative?

risposta

37

Da the documentation for Gson:

GSON fornisce la serializzazione di default e deserializzazione per Enums ... Se si preferisce cambiare la rappresentazione di default, è possibile farlo registrando un adattatore di tipo attraverso GsonBuilder.registerTypeAdapter (Tipo, Oggetto).

Di seguito è riportato un approccio di questo tipo.

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

Grazie mille. Questo ha funzionato. –

+0

Funziona !! Grazie!! –

20

Uso annotazione @SerializedName:

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

Voglio espandere un po 'risposta Nazik/user2724653 (per il mio caso). Ecco un codice 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 
    } 
} 

nel file JSON è sufficiente un campo "status": "N",, dove N = 0,1,2,3 - dipendono dai valori di stato. Questo è tutto, GSON funziona correttamente con i valori per la classe nidificata enum. Nel mio caso ho analizzato un elenco di Items da json array:

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

Questa risposta risolve tutto perfettamente, senza bisogno di adattatori di tipo! –

+1

Livesaver qui :) –

+0

@SerializedName (N) per l'enum ha fatto il lavoro;) – GuilhE

4

Con la versione 2.2.2 GSON enum sarò schierato e deserializzati facilmente.

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

Se davvero si desidera utilizzare valore ordinale del Enum è possibile registrare una fabbrica adattatore tipo di ignorare di fabbrica di 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); 
     } 
    }; 
} 

Quindi registrare la fabbrica.

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