150 votes

Utilisation des Enums lors de l'analyse JSON avec GSON

Cette question est liée à une autre que j'ai déjà posée ici.

Analyse JSON avec Gson

J'essaie d'analyser le même JSON, mais j'ai légèrement modifié mes classes.

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

Ma classe se présente maintenant comme suit :

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

Ce code lance une 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 

L'exception est compréhensible, car selon la solution à ma question précédente, GSON s'attend à ce que les objets Enum soient créés en tant que

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

Mais puisque c'est syntaxiquement impossible, quelles sont les solutions recommandées, les solutions de contournement ?

364voto

validcat Points 1371

Je souhaite développer un peu la réponse de NAZIK/user2724653 (pour mon cas). Voici un code 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
     }
}

dans le fichier json vous n'avez qu'un champ "status": "N", où N=0,1,2,3 - dépend des valeurs du statut. C'est tout, GSON fonctionne correctement avec les valeurs de l'élément imbriqué enum classe. Dans mon cas, j'ai analysé une liste de Items de json de la gamme :

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

63voto

Programmer Bruce Points 16306

De la documentation pour Gson :

Gson fournit une sérialisation et une désérialisation par défaut pour les Enums... Si vous préférez changer la représentation par défaut, vous pouvez le faire en enregistrant un adaptateur de type via GsonBuilder.registerTypeAdapter(Type, Object).

Voici l'une de ces approches.

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

36voto

Inc Points 89

Utiliser une annotation @SerializedName :

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

13voto

Wout Points 106

L'extrait suivant supprime la nécessité d'une déclaration explicite de Gson.registerTypeAdapter(...) à l'aide de l'outil @JsonAdapter(class) annotation, disponible depuis Gson 2.3 (voir commentaire pm_labs ).

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

10voto

user2601995 Points 641

Avec la version 2.2.2 du GSON, les enums pourront être marshallés et démarshallés facilement.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X