Jackson, wie man JsonNode in ArrayNode umwandelt, ohne zu gießen?

116

Ich ändere meine JSON-Bibliothek von org.json auf Jackson und möchte den folgenden Code migrieren:

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

Jetzt in Jackson habe ich folgendes:

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

Allerdings mag ich die Besetzung dort nicht, gibt es die Möglichkeit für eine ClassCastException? Gibt es eine Methode entspricht getJSONArrayin org.jsonso , dass ich die richtige Fehlerbehandlung im Fall , dass es kein Array?

Konrad Höffner
quelle
Leider kann ich keine vollständige Zuordnung verwenden, da die Daten keine festen Feldnamen enthalten.
Konrad Höffner
1
Wenn die Feldnamen aus einer begrenzten Menge stammen, möchten Sie möglicherweise eine Klasse mit allen definieren und die Funktion des Deserializers verwenden, FAIL_ON_UNKNOWN_PROPERTIESum nur Nullen in den nicht verwendeten Feldern zurückzugeben. Dies ist natürlich nur dann eine Option, wenn der festgelegte Feldname relativ begrenzt ist.
fvu
Hm, ich denke, diese Lösung passt nicht am besten in meinen Fall, aber ich werde mich daran erinnern, falls ich ein Problem mit einem begrenzten Satz habe, das im Voraus bekannt ist!
Konrad Höffner

Antworten:

247

Ja, das manuelle Parser-Design von Jackson unterscheidet sich erheblich von anderen Bibliotheken. Insbesondere werden Sie feststellen, dass JsonNodedie meisten Funktionen vorhanden sind, die Sie normalerweise mit Array-Knoten anderer APIs verknüpfen würden. Als solches müssen Sie nicht in ein Casting umwandeln, um es ArrayNodezu verwenden. Hier ist ein Beispiel:

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);
    }
}

Ausgabe:

"Eins"
"Zwei"
"Drei"

Beachten Sie die Verwendung von isArray, um zu überprüfen, ob der Knoten tatsächlich ein Array ist, bevor Sie iterieren. Die Überprüfung ist nicht erforderlich, wenn Sie absolut sicher sind, dass Ihre Datenstruktur vorhanden ist. Sie ist jedoch verfügbar, falls Sie sie benötigen (und dies unterscheidet sich nicht von den meisten anderen JSON-Bibliotheken).

Wahrnehmung
quelle
2
Du hast mir Stunden gespart. Vielen Dank!
Igor Morais
Darf ich wissen, warum "final" in der Zeile "for (final JsonNode objNode: arrNode)" verwendet wird?
Anthony Vinay
5

In Java 8 können Sie dies folgendermaßen tun:

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

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

Gibt es eine Methode, die getJSONArray in org.json entspricht, damit ich die richtige Fehlerbehandlung habe, falls es sich nicht um ein Array handelt?

Es hängt von Ihrer Eingabe ab; dh das Zeug, das Sie von der URL abrufen. Wenn der Wert des Attributs "Datasets" eher ein assoziatives Array als ein einfaches Array ist, erhalten Sie ein ClassCastException.

Andererseits hängt die Richtigkeit Ihrer alten Version auch von der Eingabe ab. In der Situation, in der Ihre neue Version a wirft ClassCastException, wird die alte Version werfen JSONException. Referenz: http://www.json.org/javadoc/org/json/JSONObject.html#getJSONArray(java.lang.String)

Stephen C.
quelle
Ah ok, ich könnte einfach eine ClassCastException abfangen, danke! Für meinen Geschmack ist es etwas weniger elegant als eine bestimmte JsonException, aber wenn es sonst nicht möglich ist, ist das immer noch gut.
Konrad Höffner
0

Ich würde am Ende des Tages davon ausgehen, dass Sie die Daten im ArrayNode durch Iteration verbrauchen möchten. Dafür:

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

oder wenn Sie sich für Streams und Lambda-Funktionen interessieren:

import com.google.common.collect.Streams;
Streams.stream(datasets.withArray("datasets").elements())
    .forEach( item -> System.out.print(item.toString()) )
Wildhammer
quelle