Gson Type Adaptateur vs Personnalisé Deseralizer
L'exemple ci-dessous montre une classe (Club) qui contient une collection d'une classe abstraite (Membre). Je suis confus quant à savoir si j'ai besoin d'un TypeAdapter ou JsonDeserializer pour faire de la Désérialisation fonctionner correctement. La sérialisation fonctionne très bien sans aucune aide, mais la Désérialisation est de lever des exceptions. Pour illustrer j'ai construit à la suite, le "clone" de test. Si quelqu'un pouvait montrer un exemple de travail, je vous serais très reconnaissant.
Premier Club De La Classe
package gson.test;
import java.util.ArrayList;
import com.google.gson.Gson;
public class Club {
public static void main(String[] args) {
//Setup a Club with 2 members
Club myClub = new Club();
myClub.addMember(new Silver());
myClub.addMember(new Gold());
//Serialize to JSON
Gson gson = new Gson();
String myJsonClub = gson.toJson(myClub);
System.out.println(myJsonClub);
//De-Serialize to Club
Club myNewClub = gson.fromJson(myJsonClub, Club.class);
System.out.println(myClub.equals(myNewClub) ? "Cloned!" : "Failed");
}
private String title = "MyClub";
private ArrayList<Member> members = new ArrayList<Member>();
public boolean equals(Club that) {
if (!this.title.equals(that.title)) return false;
for (int i=0; i<this.members.size(); i++) {
if (! this.getMember(i).equals(that.getMember(i))) return false;
}
return true;
}
public void addMember(Member newMember) { members.add(newMember); }
public Member getMember(int i) { return members.get(i); }
}
Maintenant la Classe de Base Abstraite Membre
package gson.test;
public abstract class Member {
private int type;
private String name = "";
public int getType() { return type; }
public void setType(int type) { this.type = type; }
public boolean equals(Member that) {return this.name.equals(that.name);}
}
Et deux sous-catégories de Membres (Or et Argent)
package gson.test;
public class Gold extends Member {
private String goldData = "SomeGoldData";
public Gold() {
super();
this.setType(2);
}
public boolean equals(Gold that) {
return (super.equals(that) && this.goldData.equals(that.goldData));
}
}
package gson.test;
public class Silver extends Member {
private String silverData = "SomeSilverData";
public Silver() {
super();
this.setType(1);
}
public boolean equals(Silver that) {
return (super.equals(that) && this.silverData.equals(that.silverData));
}
}
Et enfin la sortie
{"title":"MyClub","members":[{"silverData":"SomeSilverData","type":1,"name":""},{"goldData":"SomeGoldData","type":2,"name":""}]}
Exception in thread "main" java.lang.RuntimeException: Failed to invoke public gson.test.Member() with no args
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:107)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:186)
...
méthode equals() doit prendre
Merci, ça m'aurait pris un peu de catch.
Il a obtenu, merci, je vais jusqu'-voter la prochaine fois.
Object
type de paramètre, pas Club
Merci, ça m'aurait pris un peu de catch.
Il a obtenu, merci, je vais jusqu'-voter la prochaine fois.
OriginalL'auteur Mike Storey | 2015-06-03
Vous devez vous connecter pour publier un commentaire.
Vous pouvez faire les deux. Celui que vous choisissez dépend vraiment sur l'impact potentiel sur les performances, et la façon dont beaucoup de code sont prêts à écrire.
Deserializers sont plus chers. C'est parce que l'entrée de deserializer est un json arbre, et GSon devrez créer un plein JsonElement de la sous-arborescence de la propriété qui correspond à votre classe, avant de le passer à votre deserializer. Si vos classes ont beaucoup de nidification, que les augmentations de coûts. Pour les objets simples, il sera négligeable.
Il semble que vous allez savoir ce qui la classe en se basant sur la valeur de
type
la propriété qui sera inclus dans l'objet cible. Votre deserializer devrezJsonElement
objet, lire latype
de la propriété, de déterminer le typecontext.deserialize()
avec la classe et le même élément qui a été transmisVotre type de carte devra être plus complexe. L'entrée pour le type d'adaptateur est stream, pas un élément ou d'un sous-arbre. Vous pouvez charger la valeur suivante entièrement à partir du flux, d'analyser et de faire exactement ce que deserializer fait, qui ne fait pas de sens et vous pouvez simplement utiliser le deserializer interface. Alternativement, vous pouvez lire le flux, voir quelles sont les propriétés il y a, de les enregistrer dans des variables locales, jusqu'à ce que vous arrivez à la
type
propriété (vous ne pouvez pas prévoir son emplacement), puis de terminer la lecture du reste de l'propriétés, et de créer votre finalGold
/Silver
des objets en fonction de leur type, et toutes les propriétés lus et enregistrés.OriginalL'auteur Pawel Veselov
Ok, véritable exemple de travail (je suis sûr que cette fois).
Le Club
Le Membre De La Classe Abstraite
Le Béton des Sous-Classes d'Argent et d'Or
Le Membre Personnalisé Serailizer
La coutume Deserializer
Et... la sortie
Je note que mon réel de cas d'utilisation est celui où la performance ne devrait pas être un problème, je suis le chargement d'un cache d'objets à partir de jSon fichiers de texte de sorte que la fréquence de ce code est exécuté rend performances beaucoup moins important que la facilité de maintenance.
OriginalL'auteur Mike Storey
Il ressemble à de la sérialisation/désérialisation des hiérarchies de classes est un problème commun.
Il y a même un "officiel" de la solution, à l'intérieur de
extras
répertoire de la source officielle des pensions de titres (il n'est malheureusement pas partie de l'Maven package).Veuillez vérifier:
OriginalL'auteur Nikola Mihajlović