web-dev-qa-db-fra.com

Deseralizer personnalisé Gson pour une variable dans un objet

Mon exemple de problème:

Nous avons un type d'objet de Apple. Apple a quelques variables membres:

String appleName; // The apples name
String appleBrand; // The apples brand
List<Seed> seeds; // A list of seeds the Apple has

Et l'objet germe ressemble à ce qui suit.

String seedName; // The seeds name
long seedSize; // The size of the seed

Maintenant, quand je reçois un objet Apple, une pomme peut avoir plus d'une graine, ou peut-être une graine, ou peut-être pas de graines!

Exemple JSON Apple avec une graine:

{
"Apple" : {
   "Apple_name" : "Jimmy", 
   "Apple_brand" : "Awesome Brand" , 
   "seeds" : {"seed_name":"Loopy" , "seed_size":"14" }
  }
}

Exemple JSON Apple avec deux graines:

{
"Apple" : {
   "Apple_name" : "Jimmy" , 
   "Apple_brand" : "Awesome Brand" , 
   "seeds" : [ 
      { 
         "seed_name" : "Loopy",
         "seed_size" : "14"
      },
      {
         "seed_name" : "Quake",
         "seed_size" : "26"
      } 
  ]}
}

Maintenant, le problème ici est que le premier exemple est un JSONObject pour les graines, le deuxième exemple est un JSONArray pour les graines. Maintenant, je sais que son JSON incohérent et que le moyen le plus simple de le réparer seraient de réparer le JSON lui-même, mais malheureusement, je reçois le JSON de quelqu'un d'autre, je ne peux donc pas le réparer. Quel serait le moyen le plus simple de résoudre ce problème?

26
Jacob Nelson

Vous devez enregistrer un adaptateur de type personnalisé pour le type Apple. Dans l'adaptateur de type, vous allez ajouter une logique pour déterminer si vous avez reçu un tableau ou un seul objet. En utilisant ces informations, vous pouvez créer votre objet Apple.

Outre le code ci-dessous, modifiez votre objet modèle Apple afin que le champ seeds ne soit pas automatiquement analysé. Changez la déclaration de variable en quelque chose comme:

private List<Seed> seeds_funkyName;

Voici le code:

GsonBuilder b = new GsonBuilder();
b.registerTypeAdapter(Apple.class, new JsonDeserializer<Apple>() {
    @Override
    public Apple deserialize(JsonElement arg0, Type arg1,
        JsonDeserializationContext arg2) throws JsonParseException {
        JsonObject appleObj = arg0.getAsJsonObject();
        Gson g = new Gson();
        // Construct an Apple (this shouldn't try to parse the seeds stuff
        Apple a = g.fromJson(arg0, Apple.class);
        List<Seed> seeds = null;
        // Check to see if we were given a list or a single seed
        if (appleObj.get("seeds").isJsonArray()) {
            // if it's a list, just parse that from the JSON
            seeds = g.fromJson(appleObj.get("seeds"),
                    new TypeToken<List<Seed>>() {
                    }.getType());
        } else {
            // otherwise, parse the single seed,
            // and add it to the list
            Seed single = g.fromJson(appleObj.get("seeds"), Seed.class);
            seeds = new ArrayList<Seed>();
            seeds.add(single);
        }
        // set the correct seed list
        a.setSeeds(seeds);
        return a;
    }
});

Pour plus d’informations, voir le guide Gson .

36
jjnguy

Nous utilisons des tableaux au lieu de Listes avec GSON, et le problème n'existe pas: regardez http://app.ecwid.com/api/v1/1003/product?id=4064 la propriété "categories" est en fait un tableau Javascript avec un élément. Il a été déclaré comme ceci:

Catégorie [] catégories;

UPdate: l'utilisation de TypeToken et la sérialisation personnalisée peuvent aider, consultez la documentation suivante: https://sites.google.com/site/gson/gson-user-guide

1
Dmitry Negoda

J'ai rencontré le même problème. Je pense que ma solution est légèrement plus simple et plus générique:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(List.class, new JsonSerializer<List<?>>() {
            @Override
            public JsonElement serialize(List<?> list, Type t,
                    JsonSerializationContext jsc) {
                if (list.size() == 1) {
                    // Don't put single element lists in a json array
                    return new Gson().toJsonTree(list.get(0));
                } else {
                    return new Gson().toJsonTree(list);
                }
            }
        }).create();

Bien sûr, je suis d’accord avec l’affiche originale, la meilleure solution est de changer le JSON. Il n'y a rien de mal à avoir un tableau de taille 1 et la sérialisation et la dé-sérialisation resteront beaucoup plus simples! Malheureusement, ces changements sont parfois hors de votre contrôle.

0
matt burns

Si vous ne pouvez pas modifier le code JSON (car vous le recevez de quelqu'un d'autre), la solution la plus simple consiste à modifier le nom de votre variable Apple et Seed class dans Java Class afin qu'il corresponde au JSON analysé.

Changez-le en:  

Apple Class
-----------
String Apple_name; // The apples name
String Apple_brand; // The apples brand
List<Seed> seeds; // A list of seeds the Apple has
And the seed object looks as follows.

Seed Class
-----------
String seed_name; // The seeds name
long seed_size; // The size of the seed
0
yogendra saxena