2016-09-23 1 views
0

J'ai une classe MySimpleObject qui a plusieurs champs membres. Étant donné un json, il va peupler le champ en conséquence. Cependant si le json est indiqué comme "nul", j'ai l'intention de le mettre à null au lieu de la chaîne "nil".Comment écrire commun deserializer GSON personnalisé pour tous les domaines d'une classe?

L'exemple ci-dessous devrait résulter en un objet MySimpleObject avec null pour tous ses champs, et une liste de longueur 0 de subItemList. myObj1 doit être égal à myObj2.

@Test 
public void myTestFunction() { 
    String myJson1 = "{\"item1\":\"nil\",\"item2\":\"nil\",\"subItemList\":[{\"subItem1\":\"nil\",\"subItem2\":\"nil\"}]}"; 
    String myJson2 = "{\"subItemList\":[]}"; 

    GsonBuilder gsonBuilder = new GsonBuilder(); 
    gsonBuilder.registerTypeAdapter(new TypeToken<List<MySubItems>>(){ }.getType(), new MyOwnListDeserializer()); 
    gsonBuilder.registerTypeAdapter(String.class, new MyOwnStringDeserializer()); 
    Gson gson = gsonBuilder.create(); 

    MySimpleObject myObj1 = gson.fromJson(myJson1, MySimpleObject.class); 
    MySimpleObject myObj2 = gson.fromJson(myJson2, MySimpleObject.class); 

    assertThat(myObj1.equals((myObj2))).isTrue(); 
} 

class MySimpleObject implements Serializable { 
    String item1 = null; 
    String item2 = null; 
    List<MySubItems> subItemList; 

    @Override 
    public int hashCode() { 
     int hash = 17; 
     hash = 31*hash + ((item1 == null)? 0 :item1.hashCode()); 
     hash = 31*hash + ((item2 == null)? 0 :item2.hashCode()); 
     return hash; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof MySimpleObject) { 
      return this.hashCode() == obj.hashCode(); 
     } 
     return super.equals(obj); 
    } 
} 

class MySubItems implements Serializable { 
    String subItem1 = null; 
    String subItem2 = null; 

    @Override 
    public int hashCode() { 
     int hash = 17; 
     hash = 31*hash + ((subItem1 == null)? 0 :subItem1.hashCode()); 
     hash = 31*hash + ((subItem2 == null)? 0 :subItem2.hashCode()); 
     return hash; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof MySubItems) { 
      return this.hashCode() == obj.hashCode(); 
     } 
     return super.equals(obj); 
    } 
} 

Comment écrire le sérialiseur personnalisé sans avoir à boucle à travers chaque JSONObject et vérifier « néant » pour définir null?

Répondre

1

J'ai regardé la bibliothèque Gson et également le gson-fire project, mais aucun d'entre eux ne semble permettre une vraie solution générique (et performante).

Une façon de procéder est de remplacer systématiquement "nil" par "null" dans la chaîne json avant de la passer à l'objet gson. Ce n'est pas très propre, mais c'est assez performant et ça pourrait marcher.

Voici une méthode de base (doit être raffiné):

public static String convertNil(String json){ 
     return json.replaceAll(":\\s*\"nil\"", ": null"); 
} 

ensuite l'utiliser comme:

MySimpleObject myObj1 = gson.fromJson(convertNil(myJson1), MySimpleObject.class); 
MySimpleObject myObj2 = gson.fromJson(convertNil(myJson2), MySimpleObject.class); 
+0

Merci. J'aime votre réponse hors de la boîte de pensée. Ma question n'est pas très correcte auparavant. Je l'ai modifié. Pouvez-vous vérifier si vous pourriez avoir la réponse maintenant? Remercier!! – Elye

+0

J'ai essayé votre réponse, c'est aussi donner un bon résultat. Je l'ai surpassé. Merci! – Elye

0

je parviens à trouver une désérialisation personnalisée qui font le travail comme ci-dessous.

@Test 
public void myTestFunction() { 
    String myJson1 = "{\"item1\":\"nil\",\"item2\":\"nil\",\"subItemList\":[{\"subItem1\":\"nil\",\"subItem2\":\"nil\"}]}"; 
    String myJson2 = "{\"subItemList\":[]}"; 

    GsonBuilder gsonBuilder = new GsonBuilder(); 
    gsonBuilder.registerTypeAdapter(new TypeToken<List<MySubItems>>(){ }.getType(), new MyOwnListDeserializer()); 
    gsonBuilder.registerTypeAdapter(String.class, new MyOwnStringDeserializer()); 
    Gson gson = gsonBuilder.create(); 

    MySimpleObject myObj1 = gson.fromJson(myJson1, MySimpleObject.class); 
    MySimpleObject myObj2 = gson.fromJson(myJson2, MySimpleObject.class); 

    assertThat(myObj1.equals((myObj2))).isTrue(); 
} 

class MySimpleObject implements Serializable { 
    String item1 = null; 
    String item2 = null; 
    List<MySubItems> subItemList; 

    @Override 
    public int hashCode() { 
     int hash = 17; 
     hash = 31*hash + ((item1 == null)? 0 :item1.hashCode()); 
     hash = 31*hash + ((item2 == null)? 0 :item2.hashCode()); 
     return hash; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof MySimpleObject) { 
      return this.hashCode() == obj.hashCode(); 
     } 
     return super.equals(obj); 
    } 
} 

class MySubItems implements Serializable { 
    String subItem1 = null; 
    String subItem2 = null; 

    @Override 
    public int hashCode() { 
     int hash = 17; 
     hash = 31*hash + ((subItem1 == null)? 0 :subItem1.hashCode()); 
     hash = 31*hash + ((subItem2 == null)? 0 :subItem2.hashCode()); 
     return hash; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof MySubItems) { 
      return this.hashCode() == obj.hashCode(); 
     } 
     return super.equals(obj); 
    } 
} 

class MyOwnStringDeserializer implements JsonDeserializer<String> { 
    @Override 
    public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     return (json.getAsString().equals("nil"))? null : json.getAsString(); 
    } 
} 

class MyOwnListDeserializer implements JsonDeserializer<List<MySubItems>> { 
    @Override 
    public List<MySubItems> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     List<MySubItems> list = new ArrayList<>(); 

     for (JsonElement element : json.getAsJsonArray()) { 
      JsonObject subObj = element.getAsJsonObject(); 
      MySubItems subItems = new MySubItems(); 

      if (!subObj.get("subItem1").getAsString().equals("nil")) { 
       subItems.subItem1 = subObj.get("subItem1").getAsString(); 
      } 
      if (!subObj.get("subItem2").getAsString().equals("nil")) { 
       subItems.subItem2 = subObj.get("subItem1").getAsString(); 
      } 

      if (subItems.subItem1 != null || subItems.subItem2 != null) { 
       list.add(subItems); 
      } 
     } 

     return (list.size() == 0)? null : list; 
    } 
} 

Je ne suis toujours pas très heureux que MyOwnListDeserializer, doit gérer manuellement SubItem1 et subItem2, malgré qu'ils devraient avoir la même règle que celle définie par MyOwnStringDeserializer. Mais je ne sais pas comment appliquer MyOwnStringDeserializer à MyOwnListDeserializer.

Serait toujours ouvert pour d'autres meilleures réponses que le mien.

Mise à jour Une plus optimisée réponse pourrait être trouvée dans https://stackoverflow.com/a/39671580/3286489