Das JSON-Format
Aus Arrays und Objekten lassen sich die Java-Datenstrukturen nachbilden.- Ein Objekt wird durch geschweifte Klammern eingeschlossen.
- Ein Element des Objekts besteht aus einem Namen, gefolgt von einem Wert. Beide werden getrennt durch einen Doppelpunkt und sind jeweils von Anführungszeichen umgeben.
- Ein Objekt kann mehrere dieser Elemente aufnehmen, sie müssen dazu durch Kommata getrennt werden.
{ "name": "Arnold Willemer", "alter": "12", "ort": "Norgaardholz" }Ein Array nimmt mehrere gleichartige Elemente auf. Das Array erhält einen Namen, die Elemente allerdings enthalten lediglich Werte.
- Ein Array wird durch eckige Klammern eingeschlossen.
- Ein Array kann beliebig viele Werte aufnehmen. Alle Werte werden in Anführungszeichen eingeschlossen.
- Enthält das Array mehrere Werte, werden sie durch Kommata getrennt.
[ "The Beatles", "ABBA", "Beatwatt" ]Ein Objekt kann als Wert wiederum ein Objekt oder ein Array verwenden. Dadurch sind beliebige Verschachtelungen möglich.
{ "name": "Arnold Willemer", "instrumente": [ "Gitarre", "Mundharmonika", "Kazoo" ] "ort": "Norgaardholz", "sprachen": [ { "sprache": "deutsch", "kenntnis": "gut" } { "sprache": "englisch", "kenntnis": "gut" } { "sprache": "plattdeutsch", "kenntnis": "schlecht" } ] }Ein Syntaxdiagramm auf http://json.org stellt die komplette Beschreibung dar.
JSON in Java
Sie benötigen eine Bibliothek. Tatsächlich gibt es sogar mehrere Implementationen von JSON. Für die Beispiele habe ich die Org.Json verwendet. Eine passende Jar-Datei können Sie unter folgender URL herunterladen.http://mvnrepository.com/artifact/org.json/json
Um Daten in JSON zu bearbeiten, legen Sie ein Objekt der Klasse JSONObject an und fügen die Elemente mit der Methode put hinzu. Die Methode erwartet als ersten Parameter den Schlüssel. Der zweite Parameter erwartet den Wert als Referenz. Darum müssen primitive Datentypen mit einem Wrapper umgeben werden.
import org.json.*; public class JsonBau { public static void main(String[] args) { JSONObject jobj = new JSONObject(); jobj.put("name", "Arnold Willemer"); jobj.put("zahl", new Integer(100)); jobj.put("gehalt", new Double(1234.56)); jobj.put("istklug", new Boolean(true)); String jsonString = jobj.toString(); System.out.println(jsonString); } }Listing: Erzeugen eines JSON-Objekts
Das Auslesen oder Parsen eines JSON-Strings erfolgt dadurch, dass man dem Konstruktor von JSONObject als Parameter diesen String übergibt. Das Auslesen eines Wertes erfolgt mit der typangepassten get-Methode. Als erster Parameter muss der Schlüssel angegeben werden.
JSONObject jobj = new JSONObject(jsonString); String name = jobj.getString("name"); int zahl = jobj.getInt("zahl"); double gehalt = jobj.getDouble("gehalt"); boolean istklug = jobj.getBoolean("istklug");Listing: Auslesen eines JSON-Objekts
Arrays
Um ein Array zu behandeln, gibt es die Klasse JSONArray. Dennoch benötigen Sie hier zunächst ein JSONObject, um für das Array einen Schlüssel angeben zu können.Beim Erzeugen der JSON-Struktur verwenden Sie das Array als Parameter für den Konstruktor von JSONArray. Nun erzeugen Sie ein JSONObject. Ihm fügen Sie das JSONArray-Objekt über die Methode put hinzu, und geben dabei als ersten Parameter den Namen des Arrays an.
import org.json.*; public class JsonArray { public static void main(String[] args) { int[] quadrate = { 1, 4, 9, 16, 25 }; JSONArray qarr = new JSONArray(quadrate); JSONObject qobj = new JSONObject(); qobj.put("quadrate", qarr); String js = qobj.toString(); System.out.println(js); // ...Listing: Erzeugen eines JSON-Arrays
Beim Auslesen des JSON-Strings mit einem Array erzeugen Sie wie zuvor ein JSONObject, dem Sie als Parameter den JSON-String übergeben. Sie geben den Schlüssel des Arrays an, um mit der Methode getJSONArray das JSONArray zu bekommen. Darüber erzeugen Sie eine Schleife. Mit der Methode length erhalten Sie die Anzahl der Elemente. Innerhalb der Schleife können Sie die Elemente mit der typspezifischen get-Methode ermitteln. Als Parameter übergeben Sie den Index.
// ... JSONObject obj = new JSONObject(js); JSONArray jarr = obj.getJSONArray("quadrate"); int neuquad[] = new int[quadrate.length]; for (int i = 0; i < jarr.length(); i++) { neuquad[i] = jarr.getInt(i); } for (int qzahl : neuquad) { System.out.println(qzahl); } } }Listing: Auslesen eines JSON-Arrays
Klassen sorgen selbst für JSON
Die JSON-Strings haben ihr Gegenstück typischerweise in einer Java-Klasse. Darum ist der Gedanke naheliegend, dass jede Klasse eine Methode zum Erzeugen des JSON-Strings und eine Methode zum Einlesen eines JSON-Strings enthält. Das Beispiel in Listing verwendet eine eigene Methode, um ein JSONObject zu erstellen.public class Sprache { String sprache = ""; String kenntnis = ""; public JSONObject toJSONObj() { JSONObject obj = new JSONObject(); obj.put("sprache", this.sprache); obj.put("kenntnis", this.kenntnis); return obj; } }Listing: Die Klasse Sprache mit Methode toJSONObj
Das bleibt Ihnen natürlich unbenommen. Etwas eleganter ist es jedoch, wenn Sie zum Erzeugen des JSONObject ein Objekt der eigenen Klasse dem Konstruktor als Parameter übergeben. In dem Moment wird der Konstruktor automatisch aus der Klasse ein JSON-Objekt erzeugen. Dabei geht er folgendermaßen vor:
- Alle öffentlichen Methoden ohne Parameter, die mit get beginnen, werden verwendet.
- Am Rückgabetyp werden auch Arrays erkannt.
- Ist der Rückgabetyp aus einer anderen Klasse gebildet, werden auch dort die get-Methoden herangezogen.
- Als Schlüssel wird der Name der Methode ohne das get verwendet. Der erste Buchstaben wird in Kleinbuchstaben übersetzt.
public class Sprache { String sprache = ""; String kenntnis = ""; public String getSprache() { return sprache; } public String getKenntnis() { return kenntnis; } }Listing: Die Klasse benötigt keine JSON-Methode
Nun kann wird das JSONObject erzeugt, indem das Objekt der Klasse Sprache als Parameter dient.
Sprache sprache = new Sprache(); ... JSONObject personobj = new JSONObject(sprache);
Die Klassen, die in JSON überführt werden und zurück, sind häufig nicht ganz so trivial wie die oben angeführten Beispiele. Darum zeigt das Listing den Umgang mit einer Klasse Person, die eine ArrayList für Strings und eines für die Klasse Sprache verwendet.
Um ein JSONObject auszulesen wurde nicht eine Methode verwendet, sondern ein Konstruktor mit dem entsprechenden Parameter.
import java.io.BufferedReader; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import org.json.JSONArray; import org.json.JSONObject; public class JsonSpielerei { public class Sprache { String sprache = ""; String kenntnis = ""; public String getSprache() { return sprache; } public String getKenntnis() { return kenntnis; } public Sprache(String pSprache, String pKenntnis) { sprache = pSprache; kenntnis = pKenntnis; } public Sprache(JSONObject json) { this.sprache = json.getString("sprache"); this.kenntnis = json.getString("kenntnis"); } } public class Person { String name = ""; ArrayList<String> instrumente = new ArrayList<String>(); int alter = 0; ArrayList<Sprache> sprachen = new ArrayList<Sprache>(); public String getName() { return name; } public ArrayList<String> getInstrumente() { return instrumente; } public int getAlter() { return alter; } public ArrayList<Sprache> getSprachen() { return sprachen; } public Person() { } public Person(JSONObject jsonObject) { this.name = jsonObject.getString("name"); this.alter = jsonObject.getInt("alter"); JSONArray instrJson = jsonObject.getJSONArray("instrumente"); Iterator<Object> iterator = instrJson.iterator(); while (iterator.hasNext()) { this.instrumente.add((String) iterator.next()); } JSONArray sprachenJson = jsonObject.getJSONArray("sprachen"); for (int i = 0; i < sprachenJson.length(); i++) { JSONObject jsonSprache = sprachenJson.getJSONObject(i); Sprache sprache = new Sprache(jsonSprache); sprachen.add(sprache); } } } // ...Listing: Ein größeres Beispiel
Nun soll das alles getestet werden. Dazu wurde der Klasse eine main-Methode zur Seite gestellt, die den Konstruktor der Klasse ruft, um in diesem den Test durchzuführen.
Die Methode zeigt auch gleich, wie man einen JSON-String in einer Datei ablegt und ihn dort wieder ausliest, da dies schließlich eine recht häufige Anwendung von JSON ist.
// ... public JsonSpielerei() { Person person = new Person(); // wir verändern nun ein paar Elemente der Person person.name = "Arnold Willemer"; person.instrumente.add("Gitarre"); person.instrumente.add("Mundharmonika"); person.alter = 13; person.sprachen.add(new Sprache("deutsch", "toll")); person.sprachen.add(new Sprache("englisch", "naja")); JSONObject personobj = new JSONObject(person); System.out.println(personobj.toString()); // Die JSON-Struktur wird in eine Datei geschrieben try { FileWriter file = new FileWriter("/home/arnold/jsontest.txt"); file.write(personobj.toString()); file.close(); } catch (IOException e) { e.printStackTrace(); } // JSON-Struktur aus Datei lesen und Duplikat erzeugen try { BufferedReader reader = new BufferedReader( new FileReader("/home/arnold/jsontest.txt")); String zeile = ""; String jsonString = ""; while ((zeile = reader.readLine()) != null) { jsonString += zeile; } reader.close(); Person duplikat = new Person(new JSONObject(jsonString)); // Zum Test lesen wir die neue Person aus. JSONObject dupobj = new JSONObject(duplikat); System.out.println(dupobj.toString()); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new JsonSpielerei(); } }Listing: Test -JSON in Datei schreiben und wieder auslesen
Die GSON-Bibliothek
Die GSON-Bibliothek unterstützt das automatische Konvertieren von Objekten in JSON und zurück.Man kann GSON unter der Adresse repo1.maven.org/maven2/com/google/code/gson/gson herunterladen. Darunter findet man eine Liste der Versionsnummern und darunter eine Datei namens gson-x.y.z.jar. Diese wird dem Projekt hinzugefügt und in den Build-Path eingebunden.
JSON-String in Objekt überführen
import com.google.gson.Gson; // ... String jsonString = // ... Gson gson = new Gson(); Person[] liste = gson.fromJson(jsonString.toString() + "", Person[].class); for (Person p : liste) { System.out.println(p.getName()); }
Objekt in einen JSON-String überführen
import com.google.gson.Gson; // ... Person person = // ... Gson gson = new Gson(); String jsonString = gson.toJson(person);
Datum
Leider kennt JavaScript keinen Standard für einen Datumstyp und so geht es JSON auch. Die Übertragung von Date stellt ein Problem dar, dass man am einfachsten dadurch löst, dass man es nicht tut, sondern die Zahl der Millisekunden ab dem 1.1.1970 als long-Wert überträgt. Der Konstruktor von Date akzeptiert diesen Wert, um ein neues Datum zu erzeugen. Die Methode toTime() ermittelt aus einem Date-Objekt die Anzahl der Millisekunden.Falls Sie das Übertragungsformat selbst bestimmen können, wäre die Verwendung von XML eine Alternative, das mit der Übertragung eines Datums kein Problem hat. Eine vergleichbare Funktionalität wie GSON bietet JAXB.