Traitement JSON dans Java EE 7

Traitement JSON dans Java EE 7

1. Vue d'ensemble

Cet article explique comment traiter JSON en utilisant uniquement le noyau Java EE, sans utiliser de dépendances tierces telles que Jersey ou Jackson. Presque tout ce que nous allons utiliser est fourni par le packagejavax.json.

2. Écriture d'un objet dans JSONString

La conversion d'un objet Java en JSONString est très simple. Supposons que nous ayons une simple classePerson:

public class Person {
    private String firstName;
    private String lastName;
    private Date birthdate;

    // getters and setters
}

Pour convertir une instance de cette classe en JSONString, nous devons d'abord créer une instance deJsonObjectBuilder et ajouter des paires propriété / valeur à l'aide de la méthodeadd():

JsonObjectBuilder objectBuilder = Json.createObjectBuilder()
  .add("firstName", person.getFirstName())
  .add("lastName", person.getLastName())
  .add("birthdate", new SimpleDateFormat("DD/MM/YYYY")
  .format(person.getBirthdate()));

Notez que la méthodeadd() a quelques versions surchargées. Il peut recevoir la plupart des types primitifs (ainsi que des objets encadrés) en tant que second paramètre.

Une fois que nous avons fini de définir les propriétés, il nous suffit d'écrire l'objet dans unString:

JsonObject jsonObject = objectBuilder.build();

String jsonString;
try(Writer writer = new StringWriter()) {
    Json.createWriter(writer).write(jsonObject);
    jsonString = writer.toString();
}

Et c'est tout! LesString générés ressembleront à ceci:

{"firstName":"Michael","lastName":"Scott","birthdate":"06/15/1978"}

2.1. Utilisation deJsonArrayBuilder pour créer des tableaux

Maintenant, pour ajouter un peu plus de complexité à notre exemple, supposons que la classePerson a été modifiée pour ajouter une nouvelle propriété appeléeemails qui contiendra une liste d'adresses e-mail:

public class Person {
    private String firstName;
    private String lastName;
    private Date birthdate;
    private List emails;

    // getters and setters

}

Pour ajouter toutes les valeurs de cette liste auxJsonObjectBuilder, nous aurons besoin de l'aide deJsonArrayBuilder:

JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();

for(String email : person.getEmails()) {
    arrayBuilder.add(email);
}

objectBuilder.add("emails", arrayBuilder);

Notez que nous utilisons encore une autre version surchargée de la méthodeadd() qui prend un objetJsonArrayBuilder comme deuxième paramètre.

Examinons donc la chaîne générée pour un objetPerson avec deux adresses e-mail:

{"firstName":"Michael","lastName":"Scott","birthdate":"06/15/1978",
 "emails":["[email protected]","[email protected]"]}

2.2. Formatage de la sortie avecPRETTY_PRINTING

Nous avons donc réussi à convertir un objet Java en un JSONString valide. Maintenant, avant de passer à la section suivante, ajoutons une mise en forme simple pour rendre la sortie plus "JSON" et plus facile à lire.

Dans les exemples précédents, nous avons créé unJsonWriter en utilisant la méthode statique simple deJson.createWriter(). Afin de mieux contrôler lesString générés, nous tirerons parti de la capacité deJsonWriterFactory de Java 7 à créer un graveur avec une configuration spécifique.

Map config = new HashMap<>();

config.put(JsonGenerator.PRETTY_PRINTING, true);

JsonWriterFactory writerFactory = Json.createWriterFactory(config);

String jsonString;

try(Writer writer = new StringWriter()) {
    writerFactory.createWriter(writer).write(jsonObject);
    jsonString = writer.toString();
}

Le code peut sembler un peu verbeux, mais il ne fait vraiment pas grand-chose.

Tout d'abord, il crée une instance deJsonWriterFactory passant une carte de configuration à son constructeur. La carte contient une seule entrée qui définit la propriété sur PRETTY_PRINTING. Ensuite, nous utilisons cette instance d'usine pour créer un graveur, au lieu d'utiliserJson.createWriter().

La nouvelle sortie contiendra les sauts de ligne et la tabulation distinctifs qui caractérisent un JSONString:

{
    "firstName":"Michael",
    "lastName":"Scott",
    "birthdate":"06/15/1978",
    "emails":[
        "[email protected]",
        "[email protected]"
    ]
}

3. Construire un JavaObject à partir d'unString

Maintenant, faisons l'opération inverse: convertir un JSONString en un objet Java.

La partie principale du processus de conversion tourne autour deJsonObject. Pour créer une instance de cette classe, utilisez la méthode statiqueJson.createReader() suivie dereadObject():

JsonReader reader = Json.createReader(new StringReader(jsonString));

JsonObject jsonObject = reader.readObject();

La méthodecreateReader() prend unInputStream comme paramètre. Dans cet exemple, nous utilisons unStringReader, puisque notre JSON est contenu dans un objetString, mais cette même méthode pourrait être utilisée pour lire le contenu d'un fichier, par exemple, en utilisantFileInputStream.

Avec une instance deJsonObject à portée de main, nous pouvons lire les propriétés en utilisant la méthodegetString() et assigner les valeurs obtenues à une instance nouvellement créée de notre classePerson:

Person person = new Person();

person.setFirstName(jsonObject.getString("firstName"));
person.setLastName(jsonObject.getString("lastName"));
person.setBirthdate(dateFormat.parse(jsonObject.getString("birthdate")));

3.1. Utilisation deJsonArray pour obtenir les valeurs deList

Nous devrons utiliser une classe spéciale, appeléeJsonArray pour extraire les valeurs de liste deJsonObject:

JsonArray emailsJson = jsonObject.getJsonArray("emails");

List emails = new ArrayList<>();

for (JsonString j : emailsJson.getValuesAs(JsonString.class)) {
    emails.add(j.getString());
}

person.setEmails(emails);

C'est ça! Nous avons créé une instance complète dePerson à partir d'un JsonString.

4. Interroger des valeurs

Maintenant, supposons que nous nous intéressons à une donnée très spécifique qui se trouve à l'intérieur d'un JSONString.

Considérons le JSON ci-dessous représentant un client d'un magasin pour animaux de compagnie. Disons que, pour une raison quelconque, vous devez obtenir le nom du troisième animal de la liste des animaux:

{
    "ownerName": "Robert",
    "pets": [{
        "name": "Kitty",
        "type": "cat"
    }, {
        "name": "Rex",
        "type": "dog"
    }, {
        "name": "Jake",
        "type": "dog"
    }]
}

La conversion du texte entier en un objet Java juste pour obtenir une valeur unique ne serait pas très efficace. Voyons donc quelques stratégies pour interroger JSONStrings sans avoir à passer par toute l'épreuve de conversion.

4.1. Interrogation à l'aide de l'API de modèle d'objet

L'interrogation de la valeur d'une propriété avec un emplacement connu dans la structure JSON est simple. Nous pouvons utiliser une instance deJsonObject, de la même classe que celle utilisée dans les exemples précédents:

JsonReader reader = Json.createReader(new StringReader(jsonString));

JsonObject jsonObject = reader.readObject();

String searchResult = jsonObject
  .getJsonArray("pets")
  .getJsonObject(2)
  .getString("name");

Le problème ici est de naviguer dans les propriétés dejsonObject en utilisant la séquence correcte des méthodesget*().

Dans cet exemple, nous obtenons d'abord une référence à la liste «pets» en utilisant la méthodegetJsonArray(),_ which returns a list with 3 records. Then, we use _getJsonObject(), qui prend un index comme paramètre, retournant un autreJsonObject représentant le troisième élément de la liste. Enfin, nous utilisonsgetString() pour obtenir la valeur de chaîne que nous recherchons.

4.2. Interroger à l'aide de l'API Streaming

Une autre façon d'effectuer des requêtes précises sur un JSONString consiste à utiliser l'API Streaming, qui aJsonParser comme classe principale.

JsonParser fournit un accès direct extrêmement rapide, en lecture seule à JS, avec l'inconvénient d'être un peu plus compliqué que le modèle objet:

JsonParser jsonParser = Json.createParser(new StringReader(jsonString));

int count = 0;
String result = null;

while(jsonParser.hasNext()) {
    Event e = jsonParser.next();

    if (e == Event.KEY_NAME) {
        if(jsonParser.getString().equals("name")) {
            jsonParser.next();

            if(++count == 3) {
                result = jsonParser.getString();
                break;
            }
        }
    }
}

Cet exemple fournit le même résultat que le précédent. Il renvoie lesname du troisième animal de la listepets.

Une fois qu'unJsonParser est créé à l'aide deJson.createParser(), nous devons utiliser un itérateur (d'où la nature «accès direct» desJsonParser) pour naviguer dans les jetons JSON jusqu'à ce que nous arrivions à la propriété (ou propriétés) que nous recherchons.

Chaque fois que nous parcourons l'itérateur, nous passons au prochain jeton des données JSON. Nous devons donc veiller à vérifier si le jeton actuel a le type attendu. Ceci est fait en vérifiant lesEvent renvoyés par l'appelnext().

Il existe de nombreux types de jetons. Dans cet exemple, nous nous intéressons aux typesKEY_NAME, qui représentent le nom d'une propriété (ex. “OwnerName”, “pets”, “name”, “type”). Une fois que nous avons parcouru un jetonKEY_NAME avec une valeur de «nom» pour la troisième fois, nous savons que le jeton suivant contiendra une valeur de chaîne représentant le nom du troisième animal de la liste.

C'est certainement plus difficile que d'utiliser l'API de modèle d'objet, en particulier pour les structures JSON plus complexes. Comme toujours, le choix entre l’un ou l’autre dépend du scénario spécifique que vous allez traiter.

5. Conclusion

Nous avons couvert de nombreux aspects de l’API de traitement JSON Java EE avec quelques exemples simples. Pour en savoir plus sur le traitement JSON, consultez nosseries of Jackson articles.

Vérifiez le code source des classes utilisées dans cet article, ainsi que certains tests unitaires, dans nosGitHub repository.