Jackson comment transformer JsonNode en ArrayNode sans casting?

116

Je change ma bibliothèque JSON de org.json à Jackson et je souhaite migrer le code suivant:

JSONObject datasets = readJSON(new URL(DATASETS));
JSONArray datasetArray =  datasets.getJSONArray("datasets");

Maintenant, à Jackson, j'ai ce qui suit:

ObjectMapper m = new ObjectMapper();
JsonNode datasets = m.readTree(new URL(DATASETS));      
ArrayNode datasetArray = (ArrayNode)datasets.get("datasets");

Cependant je n'aime pas le casting là-bas, y a-t-il une possibilité pour un ClassCastException? Existe-t-il une méthode équivalente à getJSONArrayin org.jsonpour que je gère correctement les erreurs au cas où ce ne serait pas un tableau?

Konrad Höffner
la source
Malheureusement, je ne peux pas utiliser le mappage complet car les données ne corrigent pas les noms de champ.
Konrad Höffner
1
Si les noms de champ proviennent d'un ensemble limité, vous voudrez peut-être définir une classe les intégrant tous et utiliser la fonction de désérialiseur FAIL_ON_UNKNOWN_PROPERTIESpour simplement obtenir les valeurs nulles renvoyées dans les champs inutilisés. Mais ce n'est bien sûr une option que si le jeu de noms de champ est relativement limité.
fvu
Hm je pense que cette solution ne convient pas à mon cas mais je m'en souviendrai au cas où j'aurais un problème avec un ensemble limité qui est connu à l'avance!
Konrad Höffner

Réponses:

247

Oui, la conception de l'analyseur manuel Jackson est assez différente des autres bibliothèques. En particulier, vous remarquerez qu'il JsonNodepossède la plupart des fonctions que vous associeriez généralement aux nœuds de tableau d'autres API. En tant que tel, vous n'avez pas besoin de convertir en un ArrayNodepour l'utiliser. Voici un exemple:

JSON:

{
    "objects" : ["One", "Two", "Three"]
}

Code:

final String json = "{\"objects\" : [\"One\", \"Two\", \"Three\"]}";

final JsonNode arrNode = new ObjectMapper().readTree(json).get("objects");
if (arrNode.isArray()) {
    for (final JsonNode objNode : arrNode) {
        System.out.println(objNode);
    }
}

Production:

"Un"
"Deux"
"Trois"

Notez l'utilisation de isArraypour vérifier que le nœud est en fait un tableau avant l'itération. La vérification n'est pas nécessaire si vous êtes absolument confiant dans la structure de vos données, mais elle est disponible si vous en avez besoin (et ce n'est pas différent de la plupart des autres bibliothèques JSON).

la perception
la source
2
Vous m'avez sauvé des heures. Merci!
Igor Morais
Puis-je savoir pourquoi "final" est utilisé dans la ligne "for (final JsonNode objNode: arrNode)"?
Anthony Vinay
5

Dans Java 8, vous pouvez le faire comme ceci:

import java.util.*;
import java.util.stream.*;

List<JsonNode> datasets = StreamSupport
    .stream(datasets.get("datasets").spliterator(), false)
    .collect(Collectors.toList())
Ori Popowski
la source
1

Existe-t-il une méthode équivalente à getJSONArray dans org.json pour que je gère correctement les erreurs au cas où ce ne serait pas un tableau?

Cela dépend de votre contribution; c'est-à-dire ce que vous récupérez de l'URL Si la valeur de l'attribut "datasets" est un tableau associatif plutôt qu'un simple tableau, vous obtiendrez unClassCastException .

Mais là encore, l'exactitude de votre ancienne version dépend également de l'entrée. Dans le cas où votre nouvelle version lance un ClassCastException, l'ancienne version lancera JSONException. Référence: http://www.json.org/javadoc/org/json/JSONObject.html#getJSONArray(java.lang.String)

Stephen C
la source
Ah ok donc je pourrais juste attraper une ClassCastException, merci! À mon goût, c'est un peu moins élégant que d'avoir une JsonException spécifique mais si ce n'est pas possible sinon c'est toujours bon.
Konrad Höffner
0

Je suppose qu'à la fin de la journée, vous voulez consommer les données du ArrayNode en l'itérant. Pour ça:

Iterator<JsonNode> iterator = datasets.withArray("datasets").elements();
while (iterator.hasNext()) 
        System.out.print(iterator.next().toString() + " "); 

ou si vous aimez les flux et les fonctions lambda:

import com.google.common.collect.Streams;
Streams.stream(datasets.withArray("datasets").elements())
    .forEach( item -> System.out.print(item.toString()) )
Marteau sauvage
la source