JSON-Verarbeitung in Java EE 7

JSON-Verarbeitung in Java EE 7

1. Überblick

In diesem Artikel erfahren Sie, wie Sie JSON nur mit Java EE-Kernfunktionen verarbeiten können, ohne dass Abhängigkeiten von Drittanbietern wie Jersey oder Jackson verwendet werden. Nahezu alles, was wir verwenden, wird vom Paketjavax.jsonbereitgestellt.

2. Schreiben eines Objekts in JSONString

Das Konvertieren eines Java-Objekts in ein JSONString ist sehr einfach. Nehmen wir an, wir haben eine einfachePerson-Klasse:

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

    // getters and setters
}

Um eine Instanz dieser Klasse in eine JSONString zu konvertieren, müssen wir zuerst eine Instanz vonJsonObjectBuilder erstellen und Eigenschafts- / Wertepaare mit der Methodeadd() hinzufügen:

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

Beachten Sie, dass die Methodeadd()einige überladene Versionen aufweist. Als zweiten Parameter können die meisten primitiven Typen (sowie Boxed Objects) empfangen werden.

Sobald wir die Eigenschaften festgelegt haben, müssen wir das Objekt nur noch inString schreiben:

JsonObject jsonObject = objectBuilder.build();

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

Und das ist es! Die generiertenString sehen folgendermaßen aus:

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

2.1. Verwenden vonJsonArrayBuilder zum Erstellen von Arrays

Um unser Beispiel etwas komplexer zu gestalten, nehmen wir an, dass die KlassePersongeändert wurde, um eine neue Eigenschaft namensemails hinzuzufügen, die eine Liste von E-Mail-Adressen enthält:

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

    // getters and setters

}

Um alle Werte aus dieser Liste zuJsonObjectBuilderhinzuzufügen, benötigen wir die Hilfe vonJsonArrayBuilder:

JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();

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

objectBuilder.add("emails", arrayBuilder);

Beachten Sie, dass wir eine weitere überladene Version deradd()-Methode verwenden, die einJsonArrayBuilder-Objekt als zweiten Parameter verwendet.

Schauen wir uns also den generierten String für einPerson-Objekt mit zwei E-Mail-Adressen an:

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

2.2. Formatieren der Ausgabe mitPRETTY_PRINTING

Daher haben wir ein Java-Objekt erfolgreich in ein gültiges JSONStringkonvertiert. Bevor wir zum nächsten Abschnitt übergehen, fügen wir einige einfache Formatierungen hinzu, um die Ausgabe „JSON-ähnlicher“ und leichter lesbar zu machen.

In den vorherigen Beispielen haben wir einJsonWriter mit der einfachen statischen MethodeJson.createWriter() erstellt. Um mehr Kontrolle über die generiertenStringzu erhalten, werden wir dieJsonWriterFactory-Fähigkeit von Java 7 nutzen, um einen Writer mit einer bestimmten Konfiguration zu erstellen.

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

Der Code sieht vielleicht etwas ausführlich aus, macht aber nicht viel.

Zunächst wird eine Instanz vonJsonWriterFactoryerstellt, die eine Konfigurationszuordnung an ihren Konstruktor übergibt. Die Map enthält nur einen Eintrag, der die Eigenschaft PRETTY_PRINTING auf true setzt. Dann verwenden wir diese Factory-Instanz, um einen Writer zu erstellen, anstattJson.createWriter() zu verwenden.

Die neue Ausgabe enthält die markanten Zeilenumbrüche und Tabellen, die ein JSONStringkennzeichnen:

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

3. Erstellen eines JavaObject Aus einemString

Führen Sie nun die umgekehrte Operation aus: Konvertieren Sie ein JSONString in ein Java-Objekt.

Der Hauptteil des Konvertierungsprozesses dreht sich umJsonObject. Verwenden Sie zum Erstellen einer Instanz dieser Klasse die statische MethodeJson.createReader() gefolgt vonreadObject():

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

JsonObject jsonObject = reader.readObject();

Die MethodecreateReader() verwendetInputStream als Parameter. In diesem Beispiel verwenden wirStringReader,, da unser JSON in einemString-Objekt enthalten ist. Dieselbe Methode kann jedoch auch zum Lesen von Inhalten aus einer Datei verwendet werden, z. B. mitFileInputStream. s.

Mit einer Instanz vonJsonObject können wir die Eigenschaften mit der MethodegetString() lesen und die erhaltenen Werte einer neu erstellten Instanz unserer KlassePerson zuweisen:

Person person = new Person();

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

3.1. Verwenden vonJsonArray, umList-Werte abzurufen

Wir müssen eine spezielle Klasse namensJsonArray verwenden, um Listenwerte ausJsonObject zu extrahieren:

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

List emails = new ArrayList<>();

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

person.setEmails(emails);

Das ist es! Wir haben eine vollständige Instanz vonPerson aus einem JsonString erstellt.

4. Werte abfragen

Nehmen wir nun an, wir interessieren uns für ein ganz bestimmtes Datenelement, das in einem JSONString liegt.

Stellen Sie sich den folgenden JSON vor, der einen Kunden aus einer Zoohandlung darstellt. Nehmen wir an, Sie müssen aus irgendeinem Grund den Namen des dritten Haustieres aus der Haustierliste abrufen:

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

Das Konvertieren des gesamten Textes in ein Java-Objekt, um nur einen einzigen Wert zu erhalten, wäre nicht sehr effizient. Lassen Sie uns also einige Strategien überprüfen, um JSONStrings abzufragen, ohne die gesamte Konvertierungsprüfung durchlaufen zu müssen.

4.1. Abfragen mit der Objektmodell-API

Das Abfragen des Werts einer Eigenschaft mit einem bekannten Speicherort in der JSON-Struktur ist unkompliziert. Wir können eine Instanz vonJsonObject, derselben Klasse verwenden, die in den vorherigen Beispielen verwendet wurde:

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

JsonObject jsonObject = reader.readObject();

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

Der Haken dabei ist, durch die Eigenschaften vonjsonObjectmit der richtigen Reihenfolge der Methoden vonget*()zu navigieren.

In diesem Beispiel erhalten wir zuerst einen Verweis auf die Liste "Haustiere" mit der MethodegetJsonArray(),_ which returns a list with 3 records. Then, we use _getJsonObject(), die einen Index als Parameter verwendet und weitereJsonObject zurückgibt, die das dritte Element in der Liste darstellen Liste. Schließlich verwenden wirgetString(), um den gesuchten Zeichenfolgenwert zu erhalten.

4.2. Abfragen mit der Streaming-API

Eine andere Möglichkeit, präzise Abfragen für JSONStringdurchzuführen, ist die Verwendung der Streaming-API, deren HauptklasseJsonParser ist.

JsonParser bietet einen extrem schnellen, schreibgeschützten Vorwärtszugriff auf JS, mit dem Nachteil, dass es etwas komplizierter ist als das Objektmodell:

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

Dieses Beispiel liefert das gleiche Ergebnis wie das vorherige. Es gibt diename vom dritten Haustier in derpets-Liste zurück.

Sobald einJsonParser mitJson.createParser() erstellt wurde, müssen wir einen Iterator verwenden (daher der "Vorwärtszugriff" derJsonParser), um durch die JSON-Token zu navigieren, bis wir zur Eigenschaft gelangen (oder Eigenschaften) suchen wir.

Jedes Mal, wenn wir den Iterator durchlaufen, gelangen wir zum nächsten Token der JSON-Daten. Wir müssen also sorgfältig prüfen, ob das aktuelle Token den erwarteten Typ hat. Dies erfolgt durch Überprüfen derEvent, die vom Aufruf vonnext() zurückgegeben werden.

Es gibt viele verschiedene Arten von Token. In diesem Beispiel interessieren uns die Typen vonKEY_NAME, die den Namen einer Eigenschaft darstellen (z. "OwnerName", "pets", "name", "type"). Sobald wir zum dritten Mal einKEY_NAME-Token mit dem Wert „name“ durchlaufen haben, wissen wir, dass das nächste Token einen Zeichenfolgenwert enthält, der den Namen des dritten Haustieres aus der Liste darstellt.

Dies ist definitiv schwieriger als die Verwendung der Objektmodell-API, insbesondere für kompliziertere JSON-Strukturen. Die Wahl zwischen dem einen und dem anderen hängt wie immer von dem konkreten Szenario ab, mit dem Sie sich befassen werden.

5. Fazit

Wir haben uns mit ein paar einfachen Beispielen intensiv mit der Java EE JSON Processing API befasst. Weitere coole Informationen zur JSON-Verarbeitung finden Sie inseries of Jackson articles.

Überprüfen Sie den Quellcode der in diesem Artikel verwendeten Klassen sowie einige Komponententests in unserenGitHub repository.