{"id":4195,"date":"2018-07-15T21:01:01","date_gmt":"2018-07-15T19:01:01","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=4195"},"modified":"2018-07-15T21:01:01","modified_gmt":"2018-07-15T19:01:01","slug":"json-serialisierung-mit-jsr-353-374-und-jsr-367","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2018\/07\/json-serialisierung-mit-jsr-353-374-und-jsr-367\/","title":{"rendered":"JSON-Serialisierung mit JSR 353\/374 und JSR 367"},"content":{"rendered":"<p>Im Internet hat JSON das XML-Format zwecks Objekt\u00fcbertragung zwischen Server und Browser fast vollst\u00e4ndig verdr\u00e4ngt. Das liegt daran, dass ein Browser JSON-Strings direkt in JavaScript-Objekte konvertieren kann, XML-Dokumente aber erst aufw\u00e4ndiger verarbeitet werden m\u00fcssen.<\/p>\n<p>Neben dem Einsatzgebiet im Internet bietet JSON auch ein kompaktes Format, um etwa lokale Konfigurationsdateien zu kodieren.<\/p>\n<h3>JSON im Kontext von JavaScript<\/h3>\n<p>Nehmen wir folgende Zeile JavaScript-Code, die ein Person-Objekt mit zwei Properties f\u00fcr Name und Alter definiert. Eine Property wird \u00fcber ein Schl\u00fcssel-Wert-Paar beschrieben:<\/p>\n<p>var person = { &#8222;name&#8220; : &#8222;Michael Jackson&#8220;, &#8222;age&#8220; : 50 };<\/p>\n<p>Die Definition eines Objekts geschieht in der JSON (JavaScript Object Notation). Als Datentypen unterst\u00fctzt JSON Zahlen, Wahrheitswerte, Strings, Arrays, null und Objekte \u2013 wie unser Beispiel zeigt. Die Deklarationen k\u00f6nnen geschachtelt sein, um Unterobjekte aufzubauen.<\/p>\n<p>Zum Zugriff auf die JSON-Daten kommt der Punkt zum Einsatz, sodass der Name nach der Auswertung durch person.name zug\u00e4nglich ist.<\/p>\n<p>Eine Personenbeschreibung wie diese kann in einem String stehen, der von JavaScript zur Laufzeit ausgewertet wird.<\/p>\n<p>var json = &#8218;person = { &#8222;name&#8220; : &#8222;Michael Jackson&#8220;, &#8222;age&#8220; : 50 };&#8216;;<\/p>\n<p>Der Zugriff auf person.name liefert wie vorher den Namen, denn nach der Auswertung mit eval(\u2026) wird JavaScript ein neues Objekt mit person im Kontext anlegen.<\/p>\n<p>JSON ist besonders praktisch, wenn es darum geht, Daten zwischen einem Server und einem Browser mit JavaScript-Interpreter auszutauschen. Denn wenn der String json nicht von Hand mit einem String initialisiert wurde, sondern ein Server die Zeichenkette person = { &#8230; }; liefert, haben wir das, was heutzutage in modernen Ajax-Webanwendungen passiert.<\/p>\n<p>Die letzte Frage ist nun, wie elegant der Server Zeichenketten im Datenaustauschformat JSON erzeugt und so Objekte \u00fcbertr\u00e4gt. Den String per Hand aufzubauen ist eine L\u00f6sung, aber es geht besser.<\/p>\n<h3>JSON-Verarbeitung mit der Java API for JSON Processing<\/h3>\n<p>Zum Verarbeiten von JSON-Dokumenten gibt es in der Java SE keine Standardklassen, sodass sich eine Reihe von Open-Source-Bibliotheken herausgepr\u00e4gt haben; Jackson\u00a0(http:\/\/tutego.de\/go\/jackson) geh\u00f6rt zu den popul\u00e4rsten L\u00f6sungen. 2013 wurde dann die JSR 353, \u00bbJava API for JSON Processing\u00ab, verabschiedet, die Teil der Jakarta EE 7 ist, 2014 dann das JSR 374 \u00bbJava API for JSON Processing 1.1\u00ab.<\/p>\n<p>Wir k\u00f6nnen die JSON-API in unseren Java SE-Programmen nutzen, m\u00fcssen daf\u00fcr aber Java-Archive im Klassenpfad einbinden. Die Referenzimplementierung befindet sich unter https:\/\/javaee.github.io\/jsonp\/. Am einfachsten haben es Maven-Nutzer, sie binden in ihre POM die Abh\u00e4ngigkeiten auf den \u201eDefault provider for JSR 374:Java API for Processing JSON\u201c ein:<\/p>\n<p>&lt;dependency&gt;<br \/>\n&lt;groupId&gt;org.glassfish&lt;\/groupId&gt;<br \/>\n&lt;artifactId&gt;javax.json&lt;\/artifactId&gt;<br \/>\n&lt;version&gt;1.1&lt;\/version&gt;<br \/>\n&lt;\/dependency&gt;<\/p>\n<p>Die Implementierung hat eine Abh\u00e4ngigkeit zur JSON-API javax.json:javax.json-api, die wir dann nicht unbedingt selbst in die POM mit aufnehmen m\u00fcssen.<\/p>\n<h4>Aufbau von JSON-Objekten, Formatieren und Parsen<\/h4>\n<p>Der Typ JsonObject ist in der API zentral, denn er definiert ein hierarchisches Model mit den Schl\u00fcssel-Wert-Paaren eines JSON-Objekts. Um ein JsonObject aufzubauen, k\u00f6nnen wir \u00fcber den JsonObjectBuilder gehen, oder wir lassen den Parser JsonReader aus einer String-Repr\u00e4sentation ein JsonObject erzeugen. Zum formatierten Schreiben in einen Ausgabestrom k\u00f6nnen wir einen einfachen JsonWriter von der Json-Klasse holen \u2013 es geht aber noch einfacher \u00fcber toString() \u2013 oder \u00fcber die JsonWriterFactory arbeiten, falls wir eine h\u00fcbsche einger\u00fcckte Ausgabe w\u00fcnschen. Ein Beispiel:<\/p>\n<p>Point p = new Point( 10, 20 );<\/p>\n<p>JsonObjectBuilder objBuilder = Json.createObjectBuilder()<br \/>\n.add( &#8222;x&#8220;, p.x )<br \/>\n.add( &#8222;y&#8220;, p.y );<br \/>\nJsonObject jsonObj = objBuilder.build();<\/p>\n<p>System.out.println( jsonObj );\u00a0 \/\/ {&#8222;x&#8220;:10,&#8220;y&#8220;:20}<\/p>\n<p>Json.createWriter( System.out ).write( jsonObj ); \/\/ {&#8222;x&#8220;:10,&#8220;y&#8220;:20}<\/p>\n<p>Map&lt;String, Boolean&gt; config = new HashMap&lt;&gt;();<br \/>\nconfig.put( JsonGenerator.PRETTY_PRINTING, true );<br \/>\nJsonWriterFactory writerFactory = Json.createWriterFactory( config );<\/p>\n<p>StringWriter out = new StringWriter();<br \/>\nwriterFactory.createWriter( out ).write( jsonObj );<br \/>\nSystem.out.println( out );\u00a0 \/\/ {\\n\u00a0\u00a0\u00a0 &#8222;x&#8220;: 10, &#8230;<\/p>\n<p>JsonReader reader = Json.createReader( new StringReader( out.toString() ) );<br \/>\nSystem.out.println( reader.readObject().getInt( &#8222;x&#8220; ) ); \/\/ 10<\/p>\n<p>Soll der assoziierte Wert ein Array sein, so wird das Array mit Json.createArrayBuilder().add(..).add(..) aufgebaut und gef\u00fcllt.<\/p>\n<h4>JSON-Streaming API<\/h4>\n<p>So wie es f\u00fcr XML eine Pull-API gibt, existiert sie auch f\u00fcr JSON-Dokumente; das ist von Vorteil, wenn die Daten sehr umfangreich sind. Ein Beispiel zeigt das sehr gut:<\/p>\n<p>URL url = new URL( &#8222;https:\/\/data.cityofnewyork.us\/api\/views\/25th-nujf\/rows.json?accessType=DOWNLOAD&#8220; );<\/p>\n<p>try ( JsonParser parser = Json.createParser( url.openStream() ) ) {<br \/>\nwhile ( parser.hasNext() ) {<br \/>\nswitch ( parser.next() ) {<br \/>\ncase KEY_NAME:<br \/>\ncase VALUE_STRING:<br \/>\nSystem.out.println( parser.getString() );<br \/>\nbreak;<br \/>\ncase VALUE_NUMBER:<br \/>\nSystem.out.println( parser.getBigDecimal() );<br \/>\nbreak;<br \/>\ncase VALUE_TRUE:<br \/>\nSystem.out.println( true );<br \/>\nbreak;<br \/>\ncase VALUE_FALSE:<br \/>\nSystem.out.println( false );<br \/>\nbreak;<br \/>\ncase VALUE_NULL:<br \/>\ncase START_ARRAY:<br \/>\ncase END_ARRAY:<br \/>\ncase START_OBJECT:<br \/>\ncase END_OBJECT:<br \/>\n\/\/ Ignore<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>Zum Schreiben gibt es Vergleichbares, einen JsonGenerator; die API ist selbsterkl\u00e4rend:<\/p>\n<p>JsonGenerator gen = Json.createGenerator( System.out );<br \/>\ngen.writeStartArray();<br \/>\ngen.writeStartObject();<br \/>\ngen.write( &#8222;x&#8220;, &#8222;12&#8220; );<br \/>\ngen.write( &#8222;y&#8220;, &#8222;2&#8220; );<br \/>\ngen.writeEnd();<br \/>\ngen.writeStartObject()<br \/>\n.write( &#8222;x&#8220;, &#8222;99&#8220; )<br \/>\n.write( &#8222;x&#8220;, &#8222;123&#8220; )<br \/>\n.writeEnd();<br \/>\ngen.writeEnd().close();<br \/>\n\/\/ [{&#8222;x&#8220;:&#8220;12&#8243;,&#8220;y&#8220;:&#8220;2&#8243;},{&#8222;x&#8220;:&#8220;99&#8243;,&#8220;x&#8220;:&#8220;123&#8243;}]<\/p>\n<p>Der JsonGenerator ist AutoCloseable, sodass er gut in einem try-mit-Ressoucen-Block eingesetzt werden kann.<\/p>\n<h3>Objekt-JSON-Mapping<\/h3>\n<p>Das JSR 353 beschreibt kein automatisches Objekt-JSON-Mapping, wie JAXB das Objekt-XML-Mapping erm\u00f6glicht. Das wird im Standard JSR 367, \u00bbJava API for JSON Binding (JSON-B)\u00ab definiert. Die Website http:\/\/json-b.net\/ liefert Hintergrundinformationen, die Referenzimplementierung ist Eclipse Yasson.<\/p>\n<p>Um das mit einem Beispiel testen zu k\u00f6nnen, nehmen wie Yasson in unsere POM mit auf:<\/p>\n<p>&lt;dependency&gt;<\/p>\n<p>&lt;groupId&gt;org.eclipse&lt;\/groupId&gt;<\/p>\n<p>&lt;artifactId&gt;yasson&lt;\/artifactId&gt;<\/p>\n<p>&lt;version&gt;1.0.1&lt;\/version&gt;<\/p>\n<p>&lt;\/dependency&gt;<\/p>\n<p>Die Dependency selbst hat eine Maven Abh\u00e4ngigkeit auf javax.json.bind:javax.json.bind-api, also der eigentliche API.<\/p>\n<p>Zur Abbildung bauen wir uns ein Beispielobjekt und bringen es in das JSON-Format. Im zweiten Schritt \u00fcbertragen wir den JSON-String wieder auf das Objekt:<\/p>\n<p>public class JsonbDemo {<\/p>\n<p>public static class EvilLaboratory {<\/p>\n<p>public String from;<\/p>\n<p>public double volume;<\/p>\n<p>public boolean didPayElectricityBill;<\/p>\n<p>public List&lt;String&gt; items;<\/p>\n<p>}<\/p>\n<p>public static void main( String[] args ) {<\/p>\n<p>EvilLaboratory lab1 = new EvilLaboratory();<\/p>\n<p>lab1.from = &#8222;Frank&#8220;;<\/p>\n<p>lab1.didPayElectricityBill = true;<\/p>\n<p>lab1.volume = 12442.33;<\/p>\n<p>lab1.items = List.of( &#8222;corpses&#8220;, &#8222;animals&#8220; );<\/p>\n<p>&nbsp;<\/p>\n<p>Jsonb jsonbuilder = JsonbBuilder.create();<\/p>\n<p>String jsonString = jsonbuilder.toJson( lab1 );<\/p>\n<p>System.out.println( jsonString );<\/p>\n<p>&nbsp;<\/p>\n<p>EvilLaboratory lab2 = jsonbuilder.fromJson( jsonString, EvilLaboratory.class );<\/p>\n<p>System.out.printf( &#8222;from=%s, volume=%s, didPayElectricityBill=%s, items=%s&#8220;,<\/p>\n<p>lab2.from, lab2.volume, lab2.didPayElectricityBill, lab2.items );<\/p>\n<p>}<\/p>\n<p>}<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im Internet hat JSON das XML-Format zwecks Objekt\u00fcbertragung zwischen Server und Browser fast vollst\u00e4ndig verdr\u00e4ngt. Das liegt daran, dass ein Browser JSON-Strings direkt in JavaScript-Objekte konvertieren kann, XML-Dokumente aber erst aufw\u00e4ndiger verarbeitet werden m\u00fcssen. Neben dem Einsatzgebiet im Internet bietet JSON auch ein kompaktes Format, um etwa lokale Konfigurationsdateien zu kodieren. JSON im Kontext von [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[11],"tags":[],"class_list":["post-4195","post","type-post","status-publish","format-standard","hentry","category-insel"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/4195","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=4195"}],"version-history":[{"count":1,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/4195\/revisions"}],"predecessor-version":[{"id":4196,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/4195\/revisions\/4196"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=4195"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=4195"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=4195"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}