Recherche…


Introduction

Gson est une bibliothèque Java pouvant être utilisée pour convertir des objets Java en leur représentation JSON. Gson considère ces deux objectifs comme des objectifs de conception très importants.

Caractéristiques de Gson:

Fournit des toJson() simples de toJson() et fromJson() pour convertir des objets Java en JSON et vice-versa

Autoriser les objets non modifiables préexistants à être convertis vers et depuis JSON

Prise en charge étendue de Java Generics

Prise en charge d'objets arbitrairement complexes (avec des hiérarchies d'héritage profondes et une utilisation extensive des types génériques)

Syntaxe

  • Excluder excluder ()
  • Champ FieldNamingStrategyNamingStrategy ()
  • <T> T fromJson (JsonElement json, Class <T> classOfT)
  • <T> T fromJson (JsonElement json, type typeOfT)
  • <T> T fromJson (lecteur JsonReader, type typeOfT)
  • <T> T fromJson (Reader json, Class <T> classOfT)
  • <T> T fromJson (Reader json, type typeOfT)
  • <T> T fromJson (String json, Class <T> classOfT)
  • <T> T fromJson (String json, type typeOfT)
  • <T> TypeAdapter <T> getAdapter (type Class <T>)
  • <T> TypeAdapter <T> getAdapter (type TypeToken <T>)
  • <T> TypeAdapter <T> getDelegateAdapter (typeAdapterFactory skipPast, type TypeToken <T>)
  • JsonReader newJsonReader (lecteur de lecteur)
  • JsonWriter newJsonWriter (Writer writer)
  • JsonElement toJsonTree (objet src)
  • JsonElement toJsonTree (objet src, type typeOfSrc)
  • boolean serializeNulls ()
  • boolean htmlSafe ()
  • String toJson (JsonElement jsonElement)
  • String toJson (Object src)
  • String toJson (Object src, Type typeOfSrc)
  • String toString ()
  • void toJson (objet src, type typeOfSrc, écrivain appendable)
  • void toJson (Object src, Type typeOfSrc, JsonWriter writer)
  • void toJson (JsonElement jsonElement, écrivain appendable)
  • void toJson (JsonElement jsonElement, JsonWriter writer)
  • annuler toJson (objet src, écrivain appendable)

Analyse JSON avec Gson

L'exemple montre l'analyse d'un objet JSON à l'aide de la bibliothèque Gson de Google .

Objets d'analyse:

class Robot {
    //OPTIONAL - this annotation allows for the key to be different from the field name, and can be omitted if key and field name are same . Also this is good coding practice as it decouple your variable names with server keys name 
    @SerializedName("version") 
    private String version;

    @SerializedName("age")
    private int age;
    
    @SerializedName("robotName")
    private String name;
    
    // optional : Benefit it allows to set default values and retain them, even if key is missing from Json response. Not required for primitive data types. 

    public Robot{
       version = "";
       name = "";
    }


}

Ensuite, lorsque l'analyse doit avoir lieu, utilisez les éléments suivants:

String robotJson = "{
                        \"version\": \"JellyBean\",
                        \"age\": 3,
                        \"robotName\": \"Droid\"
                   }";

Gson gson = new Gson();
Robot robot = gson.fromJson(robotJson, Robot.class);

Analyse d'une liste:

Lors de la récupération d'une liste d'objets JSON, vous souhaiterez souvent les analyser et les convertir en objets Java.

La chaîne JSON que nous allons essayer de convertir est la suivante:

{
  "owned_dogs": [
    {
      "name": "Ron",
      "age": 12,
      "breed": "terrier"
    },
    {
      "name": "Bob",
      "age": 4,
      "breed": "bulldog"
    },
    {
      "name": "Johny",
      "age": 3,
      "breed": "golden retriever"
    }
  ]
}

Ce tableau JSON particulier contient trois objets. Dans notre code Java, nous souhaitons mapper ces objets aux objets Dog . Un objet Chien ressemblerait à ceci:

private class Dog {
    public String name;
    public int age;

    @SerializedName("breed")
    public String breedName;
}

Pour convertir le tableau JSON en un Dog[] :

Dog[] arrayOfDogs = gson.fromJson(jsonArrayString, Dog[].class);

Conversion d'un Dog[] en chaîne JSON:

String jsonArray = gson.toJson(arrayOfDogs, Dog[].class);

Pour convertir le tableau JSON en ArrayList<Dog> nous pouvons procéder comme suit:

Type typeListOfDogs = new TypeToken<List<Dog>>(){}.getType();
List<Dog> listOfDogs = gson.fromJson(jsonArrayString, typeListOfDogs);

L'objet Type typeListOfDogs définit à quoi ressemblerait une liste d'objets Dog . GSON peut utiliser cet objet de type pour mapper le tableau JSON sur les bonnes valeurs.

Vous pouvez également convertir un List<Dog> en un tableau JSON de la même manière.

String jsonArray = gson.toJson(listOfDogs, typeListOfDogs);

Analyse de la propriété JSON pour énumérer avec Gson

Si vous voulez analyser une chaîne enum avec Gson:

{"status": "open"}

public enum Status {
    @SerializedName("open")
    OPEN,
    @SerializedName("waiting")
    WAITING,
    @SerializedName("confirm")
    CONFIRM,
    @SerializedName("ready")
    READY
}

Analyse d'une liste avec Gson

Méthode 1

Gson gson = new Gson();
String json = "[ \"Adam\", \"John\", \"Mary\" ]";

Type type = new TypeToken<List<String>>(){}.getType();
List<String> members = gson.fromJson(json, type);
Log.v("Members", members.toString());

Ceci est utile pour la plupart des classes de conteneurs génériques, car vous ne pouvez pas obtenir la classe d'un type paramétré (c'est-à-dire que vous ne pouvez pas appeler List<String>.class ).

Méthode 2

public class StringList extends ArrayList<String> { }

...

List<String> members = gson.fromJson(json, StringList.class);

Alternativement, vous pouvez toujours sous-classer le type que vous voulez, puis passer dans cette classe. Cependant, ce n'est pas toujours la meilleure pratique, car cela vous renverra un objet de type StringList ;

Sérialisation / désérialisation JSON avec AutoValue et Gson

Importer dans votre fichier racine gradle

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

Importer dans votre fichier d'application Gradle

apt 'com.google.auto.value:auto-value:1.2'  
apt 'com.ryanharter.auto.value:auto-value-gson:0.3.1'  
provided 'com.jakewharton.auto.value:auto-value-annotations:1.2-update1'  
provided 'org.glassfish:javax.annotation:10.0-b28'

Créer un objet avec autovalue:

@AutoValue public abstract class SignIn {    
    @SerializedName("signin_token") public abstract String signinToken();
    public abstract String username();

    public static TypeAdapter<SignIn> typeAdapter(Gson gson) {
        return new AutoValue_SignIn.GsonTypeAdapter(gson);
    }

    public static SignIn create(String signin, String username) {
        return new AutoValue_SignIn(signin, username);
    }
}

Créez votre convertisseur Gson avec votre GsonBuilder

Gson gson = new GsonBuilder()
                .registerTypeAdapterFactory(
                    new AutoValueGsonTypeAdapterFactory())
                .create());

Désérialiser

String myJsonData = "{
    \"signin_token\": \"mySigninToken\",
    \"username\": \"myUsername\" }";
SignIn signInData = gson.fromJson(myJsonData, Signin.class);

Sérialiser

Signin myData = SignIn.create("myTokenData", "myUsername");
String myJsonData = gson.toJson(myData);

L'utilisation de Gson est un excellent moyen de simplifier le code de sérialisation et de désérialisation à l'aide d'objets POJO. L'effet secondaire est que la réflexion est coûteuse en termes de performances. C'est pourquoi l'utilisation d'AutoValue-Gson pour générer CustomTypeAdapter permet d'éviter ce coût de réflexion tout en restant très simple à mettre à jour en cas de changement d'API.

Analyse JSON en objet de classe générique avec Gson

Supposons que nous ayons une chaîne JSON:

["first","second","third"]

Nous pouvons analyser cette chaîne JSON dans un tableau String :

Gson gson = new Gson();
String jsonArray = "[\"first\",\"second\",\"third\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);

Mais si nous voulons l'analyser dans un objet List<String> , nous devons utiliser TypeToken .

Voici l'échantillon:

Gson gson = new Gson();
String jsonArray = "[\"first\",\"second\",\"third\"]";
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());

Supposons que nous avons deux classes ci-dessous:

public class Outer<T> {
    public int index;
    public T data;
}

public class Person {
    public String firstName;
    public String lastName;
}

et nous avons une chaîne JSON qui doit être analysée dans un objet Outer<Person> .

Cet exemple montre comment analyser cette chaîne JSON avec l'objet de classe générique associé:

String json = "......";
Type userType = new TypeToken<Outer<Person>>(){}.getType();
Result<User> userResult = gson.fromJson(json,userType);

Si la chaîne JSON doit être analysée dans un objet Outer<List<Person>> :

Type userListType = new TypeToken<Outer<List<Person>>>(){}.getType();
Result<List<User>> userListResult = gson.fromJson(json,userListType); 

Ajouter Gson à votre projet

dependencies {
    compile 'com.google.code.gson:gson:2.8.1'
}

Utiliser la dernière version de Gson

La ligne ci-dessous compilera la dernière version de la bibliothèque gson chaque fois que vous compilerez, vous n'avez pas à changer de version.

Avantages: Vous pouvez utiliser les dernières fonctionnalités, la vitesse et moins de bugs.
Inconvénients: Cela pourrait rompre la compatibilité avec votre code.

compile 'com.google.code.gson:gson:+'

Utiliser Gson pour charger un fichier JSON à partir du disque.

Cela va charger un fichier JSON à partir du disque et le convertir au type donné.

public static <T> T getFile(String fileName, Class<T> type) throws FileNotFoundException {
    Gson gson = new GsonBuilder()
            .create();
    FileReader json = new FileReader(fileName);
    return gson.fromJson(json, type);
}

Ajout d'un convertisseur personnalisé à Gson

Parfois, vous devez sérialiser ou désérialiser certains champs dans un format souhaité, par exemple votre backend peut utiliser le format "AAAA-MM-jj HH: mm" pour les dates et vous voulez que votre POJOS utilise la classe DateTime dans Joda Time.

Pour convertir automatiquement ces chaînes en objet DateTimes, vous pouvez utiliser un convertisseur personnalisé.

/**
 * Gson serialiser/deserialiser for converting Joda {@link DateTime} objects.
 */
public class DateTimeConverter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> {

    private final DateTimeFormatter dateTimeFormatter;

    @Inject
    public DateTimeConverter() {
        this.dateTimeFormatter = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm");
    }

    @Override
    public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(dateTimeFormatter.print(src));
    }

    @Override
    public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
        
        if (json.getAsString() == null || json.getAsString().isEmpty()) {
            return null;
        }

        return dateTimeFormatter.parseDateTime(json.getAsString());
    }
}

Pour que Gson utilise le convertisseur nouvellement créé, vous devez l'assigner lors de la création de l'objet Gson:

    DateTimeConverter dateTimeConverter = new DateTimeConverter();
    Gson gson = new GsonBuilder().registerTypeAdapter(DateTime.class, dateTimeConverter)
            .create();

    String s = gson.toJson(DateTime.now());
    // this will show the date in the desired format

Pour désérialiser la date dans ce format, il suffit de définir un champ au format DateTime:

public class SomePojo {
    private DateTime someDate;    
} 

Lorsque Gson rencontre un champ de type DateTime, il appelle votre convertisseur afin de désérialiser le champ.

Utiliser Gson comme sérialiseur avec Retrofit

Tout d'abord, vous devez ajouter GsonConverterFactory à votre fichier build.gradle

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

Ensuite, vous devez ajouter la fabrique de convertisseurs lors de la création du service Retrofit:

Gson gson = new GsonBuilder().create();
new Retrofit.Builder()
        .baseUrl(someUrl)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()
        .create(RetrofitService.class);

Vous pouvez ajouter des convertisseurs personnalisés lors de la création de l'objet Gson que vous transmettez à la fabrique. Vous permettant de créer des conversions de types personnalisées.

Analyse du tableau json en classe générique à l'aide de Gson

Supposons que nous ayons un json:

{
  "total_count": 132,
  "page_size": 2,
  "page_index": 1,
  "twitter_posts": [
    {
      "created_on": 1465935152,
      "tweet_id": 210462857140252672,
      "tweet": "Along with our new #Twitterbird, we've also updated our Display Guidelines",
      "url": "https://twitter.com/twitterapi/status/210462857140252672"
    },
    {
      "created_on": 1465995741,
      "tweet_id": 735128881808691200,
      "tweet": "Information on the upcoming changes to Tweets is now on the developer site",
      "url": "https://twitter.com/twitterapi/status/735128881808691200"
    }
  ]
}

Nous pouvons analyser ce tableau dans un objet Custom Tweets (conteneur de liste de tweets) manuellement, mais il est plus facile de le faire avec la méthode fromJson :

Gson gson = new Gson();
String jsonArray = "....";
Tweets tweets = gson.fromJson(jsonArray, Tweets.class);

Supposons que nous avons deux classes ci-dessous:

class Tweets {
    @SerializedName("total_count")
    int totalCount;
    @SerializedName("page_size")
    int pageSize;
    @SerializedName("page_index")
    int pageIndex;
    // all you need to do it is just define List variable with correct name 
    @SerializedName("twitter_posts")
    List<Tweet> tweets;
}

class Tweet {
    @SerializedName("created_on")
    long createdOn;
    @SerializedName("tweet_id")
    String tweetId;
    @SerializedName("tweet")
    String tweetBody;
    @SerializedName("url")
    String url;
}

et si vous avez juste besoin d'analyser un tableau json, vous pouvez utiliser ce code dans votre analyse:

String tweetsJsonArray = "[{.....},{.....}]"
List<Tweet> tweets = gson.fromJson(tweetsJsonArray, new TypeToken<List<Tweet>>() {}.getType());

Deserializer JSON personnalisé avec Gson

Imaginez que vous avez toutes les dates dans toutes les réponses dans un format personnalisé, par exemple /Date(1465935152)/ et que vous souhaitez appliquer une règle générale pour désérialiser toutes les dates Json en instances de Date Java. Dans ce cas, vous devez implémenter Json Deserializer personnalisé.

Exemple de json:

{
  "id": 1,
  "created_on": "Date(1465935152)",
  "updated_on": "Date(1465968945)",
  "name": "Oleksandr"
}

Supposons que nous ayons cette classe ci-dessous:

class User {
    @SerializedName("id")
    long id;
    @SerializedName("created_on")
    Date createdOn;
    @SerializedName("updated_on")
    Date updatedOn;
    @SerializedName("name")
    String name;
}

Désérialiseur personnalisé:

class DateDeSerializer implements JsonDeserializer<Date> {
    private static final String DATE_PREFIX = "/Date(";
    private static final String DATE_SUFFIX = ")/";

    @Override
    public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        String dateString = json.getAsString();
        if (dateString.startsWith(DATE_PREFIX) && dateString.endsWith(DATE_SUFFIX)) {
            dateString = dateString.substring(DATE_PREFIX.length(), dateString.length() - DATE_SUFFIX.length());
        } else {
            throw new JsonParseException("Wrong date format: " + dateString);
        }
        return new Date(Long.parseLong(dateString) - TimeZone.getDefault().getRawOffset());
    }
}

Et l'utilisation:

Gson gson = new GsonBuilder()
                .registerTypeAdapter(Date.class, new DateDeSerializer())
                .create();
String json = "....";
User user = gson.fromJson(json, User.class);

Sérialiser et désérialiser les chaînes Jackson JSON avec les types de date

Cela s'applique également au cas où vous souhaitez rendre la conversion de date de Gson compatible avec Jackson, par exemple.

Jackson a l'habitude de sérialiser Date à "millisecondes depuis l'époque" alors que Gson utilise un format lisible comme Aug 31, 2016 10:26:17 pour représenter Date. Cela conduit à JsonSyntaxExceptions dans Gson lorsque vous essayez de désérialiser une date au format Jackson.

Pour contourner ce problème, vous pouvez ajouter un sérialiseur personnalisé et un désérialiseur personnalisé:

JsonSerializer<Date> ser = new JsonSerializer<Date>() {
    @Override
    public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext
                context) {
        return src == null ? null : new JsonPrimitive(src.getTime());
    }
};

JsonDeserializer<Date> deser = new JsonDeserializer<Date>() {
    @Override
    public Date deserialize(JsonElement json, Type typeOfT,
                JsonDeserializationContext context) throws JsonParseException {
        return json == null ? null : new Date(json.getAsLong());
    }
};

Gson gson = new GsonBuilder()
                .registerTypeAdapter(Date.class, ser)
                .registerTypeAdapter(Date.class, deser)
                .create();

Utiliser Gson avec héritage

Gson ne supporte pas l'héritage par défaut.

Disons que nous avons la hiérarchie de classes suivante:

public class BaseClass {
    int a;
 
    public int getInt() {
        return a;
   }
}
 
public class DerivedClass1 extends BaseClass {
     int b;
 
     @Override
     public int getInt() {
         return b;
     }
 }
 
public class DerivedClass2 extends BaseClass {
    int c;
 
    @Override
    public int getInt() {
        return c;
    }
}

Et maintenant, nous voulons sérialiser une instance de DerivedClass1 en une chaîne JSON

DerivedClass1 derivedClass1 = new DerivedClass1();
derivedClass1.b = 5;
derivedClass1.a = 10;
 
Gson gson = new Gson();
String derivedClass1Json = gson.toJson(derivedClass1);

Maintenant, à un autre endroit, nous recevons cette chaîne json et souhaitons la désérialiser - mais au moment de la compilation, nous savons seulement qu’elle est supposée être une instance de BaseClass :

BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);
System.out.println(maybeDerivedClass1.getInt());

Mais GSON ne sait pas que: derivedClass1Json était à l'origine une instance de DerivedClass1 , donc cela imprimera 10.

Comment résoudre ce problème?

Vous devez créer votre propre JsonDeserializer , qui gère de tels cas. La solution n'est pas parfaitement propre, mais je n'ai pas pu en trouver une meilleure.

Tout d'abord, ajoutez le champ suivant à votre classe de base

@SerializedName("type")
private String typeName;

Et l'initialiser dans le constructeur de la classe de base

public BaseClass() {
    typeName = getClass().getName();
}

Ajoutez maintenant la classe suivante:

public class JsonDeserializerWithInheritance<T> implements JsonDeserializer<T> {
 
 @Override
 public T deserialize(
     JsonElement json, Type typeOfT, JsonDeserializationContext context)
     throws JsonParseException {
     JsonObject jsonObject = json.getAsJsonObject();
     JsonPrimitive classNamePrimitive = (JsonPrimitive) jsonObject.get("type");
 
     String className = classNamePrimitive.getAsString();
 
     Class<?> clazz;
     try {
     clazz = Class.forName(className);
     } catch (ClassNotFoundException e) {
     throw new JsonParseException(e.getMessage());
     }
     return context.deserialize(jsonObject, clazz);
 }
}

Tout ce qui reste à faire est de tout brancher -

GsonBuilder builder = new GsonBuilder();
 builder
 .registerTypeAdapter(BaseClass.class, new JsonDeserializerWithInheritance<BaseClass>());
 Gson gson = builder.create();

Et maintenant, en exécutant le code suivant

 DerivedClass1 derivedClass1 = new DerivedClass1();
 derivedClass1.b = 5;
 derivedClass1.a = 10;
 String derivedClass1Json = gson.toJson(derivedClass1);
 
 BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);
 System.out.println(maybeDerivedClass1.getInt());

Imprimera 5.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow