web-dev-qa-db-fra.com

Comment implémenter TypeAdapterFactory dans Gson?

Comment implémenter type TypeAdapterFactory dans Gson?

La principale méthode de création est générique. Pourquoi?

La méthode d'enregistrement registerTypeAdapterFactory () ne reçoit pas de type un argument de type. Alors, comment Gson sait-il quelles classes sont traitées par l'usine?

Dois-je implémenter une usine pour plusieurs classes, ou puis-je en implémenter une pour plusieurs classes?

Si j'implémente une usine pour plusieurs classes, que dois-je retourner en cas d'argument de type hors domaine?

24
Suzan Cioc

Lorsque vous enregistrez un adaptateur de type standard (GsonBuilder.registerTypeAdapter), il génère uniquement un adaptateur de type pour cette classe spécifique. Par exemple:

public abstract class Animal { abstract void speak(); }
public class Dog extends Animal {
   private final String speech = "woof";
   public void speak() {
       System.out.println(speech);
   }
}

// in some gson related method
gsonBuilder.registerTypeAdapter(Animal.class, myTypeAdapterObject);
Gson g = gsonBuilder.create();
Dog dog = new Dog();
System.out.println(g.toJson(dog));

Si vous avez fait cela, alors Gson utilisera pas votre myTypeAdapterObject, il utilisera l'adaptateur de type par défaut pour Object.

Alors, comment pouvez-vous créer un objet adaptateur de type capable de convertir N'IMPORTE QUELLE sous-classe Animal en Json? Créez un TypeAdapterFactory! La fabrique peut correspondre en utilisant le type générique et la classe TypeToken. Vous devez retourner null si votre TypeAdapterFactory ne sait pas comment gérer un objet de ce type.

L'autre chose TypeAdapterFactory peut être utilisée, c'est que vous ne pouvez pas CHAÎNER les adaptateurs d'une autre manière. Par défaut, Gson ne passe pas votre instance Gson dans les méthodes read ou write de TypeAdapter. Donc, si vous avez un objet comme:

public class MyOuterClass {
    private MyInnerClass inner;
}

Il n'y a aucun moyen d'écrire votre TypeAdapter<MyOuterClass> qui sait utiliser votre TypeAdapter<MyInnerClass> sans utiliser le TypeAdapterFactory. Le TypeAdapterFactory.create la méthode PASSE l'instance Gson, qui vous permet d'enseigner votre TypeAdapter<MyOuterClass> comment sérialiser le champ MyInnerClass.


Généralement, voici une bonne façon standard de commencer à écrire une implémentation d'un TypeAdapterFactory:

public enum FooAdapterFactory implements TypeAdapterFactory {
    INSTANCE; // Josh Bloch's Enum singleton pattern

    @SuppressWarnings("unchecked")
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        if (!Foo.class.isAssignableFrom(type.getRawType())) return null;

        // Note: You have access to the `gson` object here; you can access other deserializers using gson.getAdapter and pass them into your constructor
        return (TypeAdapter<T>) new FooAdapter();
    }

    private static class FooAdapter extends TypeAdapter<Foo> {
        @Override
        public void write(JsonWriter out, Foo value) {
            // your code
        }

        @Override
        public Foo read(JsonReader in) throws IOException {
            // your code
        }
    }
}
42
durron597