java play - Désérialiser une classe abstraite dans Gson




framework scala (5)

Autant que je sache, cela ne fonctionne pas pour les types non-collection, ou plus spécifiquement, les situations où le type concret est utilisé pour sérialiser, et le type d'interface est utilisé pour désérialiser. Autrement dit, si vous avez une classe simple implémentant une interface et sérialisant la classe concrète, puis spécifiez l'interface à désérialiser, vous vous retrouverez dans une situation irrécupérable.

Dans l'exemple ci-dessus, l'adaptateur de type est enregistré sur l'interface, mais lors de la sérialisation à l'aide de la classe concrète, il ne sera pas utilisé, ce qui signifie que les données CLASS_META_KEY ne seront jamais définies.

Si vous spécifiez l'adaptateur en tant qu'adaptateur hiérarchique (indiquant ainsi à gson de l'utiliser pour tous les types dans la hiérarchie), vous vous retrouverez dans une boucle infinie car le sérialiseur continuera de s'appeler lui-même.

Quelqu'un sait comment sérialiser à partir d'une implémentation concrète d'une interface, puis désérialiser en utilisant seulement l'interface et un InstanceCreator?

Par défaut, il semble que gson créera l'instance concrète, mais ne définit pas ses champs.

Le problème est enregistré ici:

http://code.google.com/p/google-gson/issues/detail?id=411&q=interface

J'ai un objet arbre au format JSON que j'essaye de désérialiser avec Gson. Chaque nœud contient ses nœuds enfants en tant que champs de type d'objet Node. Node est une interface qui comporte plusieurs implémentations de classes concrètes. Pendant le processus de désérialisation, comment puis-je communiquer à Gson la classe concrète à implémenter lors de la désérialisation du nœud, si je ne sais pas à priori à quel type appartient le nœud? Chaque nœud a un champ membre spécifiant le type. Y a-t-il un moyen d'accéder au champ lorsque l'objet est sous forme sérialisée, et de communiquer en quelque sorte le type à Gson?

Merci!


Vous devez enregistrer JSONSerializer et JSONDeserializer. Vous pouvez également implémenter un adaptateur générique pour toutes vos interfaces de la façon suivante:

  • Pendant la sérialisation: Ajoutez une info META du type de classe impl actuel.
  • Pendant DeSerialization: récupérez cette méta-info et appelez le JSONDeserailize de cette classe

Voici la mise en œuvre que j'ai utilisée pour moi-même et fonctionne bien.

public class PropertyBasedInterfaceMarshal implements
        JsonSerializer<Object>, JsonDeserializer<Object> {

    private static final String CLASS_META_KEY = "CLASS_META_KEY";

    @Override
    public Object deserialize(JsonElement jsonElement, Type type,
            JsonDeserializationContext jsonDeserializationContext)
            throws JsonParseException {
        JsonObject jsonObj = jsonElement.getAsJsonObject();
        String className = jsonObj.get(CLASS_META_KEY).getAsString();
        try {
            Class<?> clz = Class.forName(className);
            return jsonDeserializationContext.deserialize(jsonElement, clz);
        } catch (ClassNotFoundException e) {
            throw new JsonParseException(e);
        }
    }

    @Override
    public JsonElement serialize(Object object, Type type,
            JsonSerializationContext jsonSerializationContext) {
        JsonElement jsonEle = jsonSerializationContext.serialize(object, object.getClass());
        jsonEle.getAsJsonObject().addProperty(CLASS_META_KEY,
                object.getClass().getCanonicalName());
        return jsonEle;
    }

}

Ensuite, vous pouvez enregistrer cet adaptateur pour toutes vos interfaces comme suit

Gson gson = new GsonBuilder()
        .registerTypeAdapter(IInterfaceOne.class,
                new PropertyBasedInterfaceMarshal())
        .registerTypeAdapter(IInterfaceTwo.class,
                new PropertyBasedInterfaceMarshal()).create();

Je suggère d'ajouter un JsonDeserializer personnalisé pour les Node :

Gson gson = new GsonBuilder()
    .registerTypeAdapter(Node.class, new NodeDeserializer())
    .create();

Vous pourrez accéder à JsonElement représentant le nœud dans la méthode du désérialiseur, le convertir en JsonObject et récupérer le champ qui spécifie le type. Vous pouvez ensuite créer une instance du type de Node correct en fonction de cela.


Vous devez utiliser la classe TypeToken de Google Gson. Vous aurez bien sûr besoin d'une classe générique T pour que ça marche

Type fooType = new TypeToken<Foo<Bar>>() {}.getType();

gson.toJson (foo, fooType);

gson.fromJson(json, fooType);

Dans My case @ uncaught_exceptions la réponse n'a pas fonctionné, j'ai dû utiliser List.class au lieu de java.lang.reflect.Type :

String jsonDuplicatedItems = request.getSession().getAttribute("jsonDuplicatedItems").toString();
List<Map.Entry<Product, Integer>> entries = gson.fromJson(jsonDuplicatedItems, List.class);




java json abstract-class gson