JSON-verwerking in Java EE 7

1. Overzicht

Dit artikel laat je zien hoe je JSON kunt verwerken met alleen core Java EE, zonder het gebruik van afhankelijkheden van derden, zoals Jersey of Jackson. Vrijwel alles wat we zullen gebruiken, wordt geleverd door het pakket javax.json.

2. Een object naar JSON schrijven Draad

Een Java-object converteren naar een JSON Draad is super eenvoudig. Laten we aannemen dat we een simpele hebben Persoon klasse:

openbare klasse Persoon {privé String firstName; private String achternaam; privé geboortedatum; // getters en setters}

Om een ​​instantie van die klasse naar een JSON te converteren Draad, moeten we eerst een instantie van JsonObjectBuilder en voeg eigenschap / waarde-paren toe met behulp van de toevoegen() methode:

JsonObjectBuilder objectBuilder = Json.createObjectBuilder () .add ("voornaam", person.getFirstName ()) .add ("achternaam", person.getLastName ()) .add ("geboortedatum", nieuwe SimpleDateFormat ("DD / MM / JJJJ ") .format (person.getBirthdate ()));

Merk op dat de toevoegen() methode heeft een paar overbelaste versies. Het kan de meeste primitieve typen (evenals omkaderde objecten) ontvangen als zijn tweede parameter.

Als we klaar zijn met het instellen van de eigenschappen, hoeven we het object alleen maar in een Draad:

JsonObject jsonObject = objectBuilder.build (); Tekenreeks jsonString; probeer (Writer-schrijver = nieuwe StringWriter ()) {Json.createWriter (schrijver) .write (jsonObject); jsonString = writer.toString (); }

En dat is het! Het gegenereerde Draad ziet er als volgt uit:

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

2.1. Gebruik makend van JsonArrayBuilder om arrays te bouwen

Laten we nu, om wat meer complexiteit aan ons voorbeeld toe te voegen, aannemen dat de Persoon class is gewijzigd om een ​​nieuwe eigenschap toe te voegen met de naam e-mails die een lijst met e-mailadressen bevat:

openbare klasse Persoon {privé String firstName; private String achternaam; privé Geboortedatum; privélijst e-mails; // getters en setters}

Om alle waarden uit die lijst toe te voegen aan het JsonObjectBuilder we hebben de hulp nodig van JsonArrayBuilder:

JsonArrayBuilder arrayBuilder = Json.createArrayBuilder (); voor (String e-mail: person.getEmails ()) {arrayBuilder.add (e-mail); } objectBuilder.add ("e-mails", arrayBuilder);

Merk op dat we weer een overbelaste versie van het toevoegen() methode waarvoor een JsonArrayBuilder object als zijn tweede parameter.

Laten we dus eens kijken naar de gegenereerde String voor a Persoon object met twee e-mailadressen:

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

2.2. De uitvoer formatteren met PRETTY_PRINTING

We hebben dus met succes een Java-object geconverteerd naar een geldige JSON Draad. Laten we nu, voordat we naar de volgende sectie gaan, wat eenvoudige opmaak toevoegen om de uitvoer meer "JSON-achtig" en gemakkelijker leesbaar te maken.

In de vorige voorbeelden hebben we een JsonWriter met behulp van de ongecompliceerde Json.createWriter () statische methode. Om meer controle te krijgen over het gegenereerde Draad, zullen we gebruik maken van Java 7's JsonWriterFactory mogelijkheid om een ​​schrijver te maken met een specifieke configuratie.

Map config = nieuwe HashMap (); config.put (JsonGenerator.PRETTY_PRINTING, true); JsonWriterFactory writerFactory = Json.createWriterFactory (config); Tekenreeks jsonString; probeer (Writer-schrijver = nieuwe StringWriter ()) {writerFactory.createWriter (schrijver) .write (jsonObject); jsonString = writer.toString (); }

De code ziet er misschien een beetje uitgebreid uit, maar het doet echt niet veel.

Ten eerste maakt het een instantie van JsonWriterFactory een configuratiekaart doorgeven aan de constructor. De kaart bevat slechts één item dat waar is voor de eigenschap PRETTY_PRINTING. Vervolgens gebruiken we die fabrieksinstantie om een ​​schrijver te maken, in plaats van Json.createWriter ().

De nieuwe uitvoer bevat de onderscheidende regeleinden en tabellen die kenmerkend zijn voor een JSON Draad:

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

3. Bouwen aan een Java Voorwerp Van een Draad

Laten we nu de tegenovergestelde bewerking doen: converteer een JSON Draad in een Java-object.

Het grootste deel van het conversieproces draait om JsonObject. Gebruik de statische methode om een ​​instantie van deze klasse te maken Json.createReader () gevolgd door readObject ():

JsonReader-lezer = Json.createReader (nieuwe StringReader (jsonString)); JsonObject jsonObject = reader.readObject ();

De createReader () methode duurt een InputStream als parameter. In dit voorbeeld gebruiken we een StringReader, aangezien onze JSON is opgenomen in een Draad object, maar dezelfde methode kan worden gebruikt om inhoud uit een bestand te lezen, bijvoorbeeld met FileInputStream.

Met een exemplaar van JsonObject bij de hand kunnen we de eigenschappen lezen met behulp van de getString () methode en wijs de verkregen waarden toe aan een nieuw aangemaakt exemplaar van onze Persoon klasse:

Persoon persoon = nieuwe persoon (); person.setFirstName (jsonObject.getString ("voornaam")); person.setLastName (jsonObject.getString ("lastName")); person.setBirthdate (dateFormat.parse (jsonObject.getString ("geboortedatum")));

3.1. Gebruik makend van JsonArray krijgen Lijst Waarden

We hebben een speciale klasse nodig, genaamd JsonArray om lijstwaarden uit te halen JsonObject:

JsonArray emailsJson = jsonObject.getJsonArray ("e-mails"); Lijst e-mails = nieuwe ArrayList (); voor (JsonString j: emailsJson.getValuesAs (JsonString.class)) {emails.add (j.getString ()); } person.setEmails (e-mails);

Dat is het! We hebben een volledig exemplaar gemaakt van Persoon van een Json Draad.

4. Vragen naar waarden

Laten we nu aannemen dat we geïnteresseerd zijn in een heel specifiek stuk gegevens dat in een JSON ligt Draad.

Beschouw de onderstaande JSON die een klant van een dierenwinkel vertegenwoordigt. Laten we zeggen dat u om de een of andere reden de naam van het derde huisdier uit de huisdierenlijst moet halen:

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

Het zou niet erg efficiënt zijn om de hele tekst naar een Java-object te converteren om slechts een enkele waarde te krijgen. Laten we dus een paar strategieën bekijken om JSON te doorzoeken Snaren zonder de hele beproeving van de bekering te hoeven doorstaan.

4.1. Query's met behulp van Object Model API

Het opvragen van de waarde van een eigenschap met een bekende locatie in de JSON-structuur is eenvoudig. We kunnen een exemplaar gebruiken van JsonObject, dezelfde klasse die in eerdere voorbeelden werd gebruikt:

JsonReader-lezer = Json.createReader (nieuwe StringReader (jsonString)); JsonObject jsonObject = reader.readObject (); String searchResult = jsonObject .getJsonArray ("pets") .getJsonObject (2) .getString ("name"); 

De vangst hier is om erdoorheen te navigeren jsonObject eigenschappen met de juiste volgorde van krijgen*() methoden.

In dit voorbeeld krijgen we eerst een verwijzing naar de "pets" -lijst met getJsonArray (), wat een lijst met 3 records retourneert. Vervolgens gebruiken we getJsonObject () methode, die een index als parameter neemt en een andere retourneert JsonObject vertegenwoordigt het derde item in de lijst. Ten slotte gebruiken we getString () om de stringwaarde te krijgen waarnaar we op zoek zijn.

4.2. Query's uitvoeren met behulp van streaming-API

Een andere manier om nauwkeurige query's uit te voeren op een JSON Draad gebruikt de streaming-API, die heeft JsonParser als zijn belangrijkste klasse.

JsonParser biedt extreem snelle, alleen-lezen, voorwaartse toegang tot JS, met het nadeel dat het iets gecompliceerder is dan het objectmodel:

JsonParser jsonParser = Json.createParser (nieuwe StringReader (jsonString)); int count = 0; String resultaat = null; while (jsonParser.hasNext ()) {Event e = jsonParser.next (); if (e == Event.KEY_NAME) {if (jsonParser.getString (). equals ("naam")) {jsonParser.next (); if (++ count == 3) {result = jsonParser.getString (); breken; }}}}

Dit voorbeeld levert hetzelfde resultaat op als het vorige. Het retourneert de naam van het derde huisdier in de huisdieren lijst.

Eens een JsonParser is gemaakt met Json.createParser (), moeten we een iterator gebruiken (vandaar de "forward access" -karakteristiek van de JsonParser) om door de JSON-tokens te navigeren totdat we bij de eigenschap (of eigenschappen) komen waarnaar we op zoek zijn.

Elke keer dat we door de iterator stappen, gaan we naar het volgende token van de JSON-gegevens. We moeten dus voorzichtig zijn om te controleren of het huidige token het verwachte type heeft. Dit doet u door de Evenement geretourneerd door de De volgende() bellen.

Er zijn veel verschillende soorten tokens. In dit voorbeeld zijn we geïnteresseerd in de KEY_NAME types, die de naam van een eigenschap vertegenwoordigen (bijv. "ownerName", "pets", "name", "type"). Zodra we door een KEY_NAME token met de waarde "naam" voor de derde keer, we weten dat het volgende token een stringwaarde zal bevatten die de naam van het derde huisdier uit de lijst vertegenwoordigt.

Dit is beslist moeilijker dan het gebruik van de Object Model API, vooral voor meer gecompliceerde JSON-structuren. De keuze tussen het een of het ander hangt, zoals altijd, af van het specifieke scenario waarmee u te maken krijgt.

5. Conclusie

We hebben veel aandacht besteed aan de Java EE JSON Processing API met een paar eenvoudige voorbeelden. Bekijk onze serie Jackson-artikelen voor andere coole dingen over JSON-verwerking.

Controleer de broncode van de klassen die in dit artikel worden gebruikt, evenals enkele eenheidstests, in onze GitHub-repository.