Chapter 1. JSON (a Java) Table of Contents 1.1. Základní informace ............................................................................................................................ 1 1.2. Existující datové typy ......................................................................................................................... 2 1.3. Zpracování JSON v Javě .................................................................................................................. 4 1.3.1. Ukázka Data Binding ................................................................................................................... 5 ■ JavaScript Object Notation – jeden z nejpoužívanějších textových formátů pro výměnu dat na Webu ● [džej-son] ● specifikace v RFC 4627 ● použití se neomezuje jen na web, např. časté použití je pro konfigurační soubory apod. ■ zdroje a nástroje: ● www.json.org ● www.w3schools.com/js/js_json_intro.asp ● www.jsonlint.com
1.1. Základní informace ■ XML pro krátká nepříliš strukturovaná data je příliš těžkopádný (značky tvoří až 60 % přenášené informace) ● pro dlouhá a silně strukturovaná (hierarchická) data je ale XML stále nenahraditelné ■ pro úspěch JSON se setkaly dvě potřeby webových vývojářů: ● častá výměna krátkých a jednoduchých strukturovaných dat ● dobrá spolupráce s jazykem JavaScript (dále JS) ♦ zápis JSON je platným zápisem JS ■ JSON je textový, na programovacím jazyce zcela nezávislý formát ● pro všechny známé programovací jazyky již existují knihovny pracující s JSON ● ovšem nejvíce “nativní” je podpora v JS ■ JSON neumožňuje definovat znakovou sadu ● implicitně se předpokládá UTF-8 ■ charakteristika formátu: ● přípona JSON souborů je .json
JSON (a Java), © Pavel Herout, 2017 XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
1
● MIME type pro JSON text je application/json ■ validace podle schématu je možná: ● https://www.zdrojak.cz/clanky/json-schema-praxi/ ● https://spacetelescope.github.io/understanding-json-schema/basics.html
1.2. Existující datové typy ■ JSONString – textový řetězec ● vždy v uvozovkách (apostrofy nejsou povoleny) "alfa a omega" ● syntaxe jako v Javě ♦ kódování Unicode (implicitní uložení v UTF-8) – bez problémů s akcenty "alfa a omega jsou první a poslední znaky řecké abecedy" ♦ pro speciální znaky lze použít \uXXXX (vždy čtyřmístné s nevýznamovými nulami), např. "alfa \u03B1 a omega \u03A9" ♦ vnořené uvozovky pomocí \" "\"alfa\" \u03B1 a \"omega\" \u03A9" ♦ vnořené \ pomocí \\ "oblíbený adresář D:\\zzz" ♦ lze používat běžně známé “escape” znaky "nová řádka \n a tabulátor \t" ■ JSONNumber – číslo v desítkové soustavě ● celá čísla 123 -5 +18 ● reálná čísla
JSON (a Java), © Pavel Herout, 2017 XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
2
3.14 -6.3 nula před desetinnou tečkou je povinná 0.5 ● reálná čísla v exponenciálním tvaru +31.4e-1 ■ JSONBoolean – logická hodnota (pouze malými písmeny) true false ■ JSONNull – hodnota null (pouze malými písmeny) null ■ JSONArray – pole ● seřazený seznam hodnot v hranatých závorkách, oddělovače jsou čárky; hodnotami pole může být kterýkoliv datový typ JSON ["datový", "formát", "JSON"] [0, 1, 1, 2, 3, 5] [true, false, false, true] ● pole mohou mít heterogenní prvky ["JSON je", 1, true] ● hodnotami pole může být i vnořené pole ["první tři prvočísla", [2, 3, 4], [true, true, false]] ● hodnotami pole může být i objekt [{"hodnota" : 123, "měna" : "CZK"}, {"hodnota" : 35, "měna" : "EUR"}] ■ JSONObject – není to objekt v programovém slova smyslu, ale mapa (asociativní pole, hash objekty, ...) ● uzavřená do { }; obsahuje klíč (vždy JSONString) dvojtečku jako oddělovač a hodnotu (libovolný JSON datový typ) JSON (a Java), © Pavel Herout, 2017 XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
3
{"osoba": "Pavel"} {"hodnota": 123, "měna": "CZK"} {"datum_a_cas": "2017-01-02T20:35:37+01:00"} tento formát data a času je doporučen podle ISO 8601 ● prvky objektu mohou být i další objekty či vnořená pole {"cena": {"hodnota": 256, "měna": "CZK"}, "zboží": ["pivo", "rum"], "placeno ► kartou": false}
Note Hloubka vnoření u polí nebo objektů není definicí omezena. Je však omezena požadavkem na jednoduchost formátu. Při značně zanořených (hierarchických) strukturách by bylo zřejmě vhodnější použít XML formát.
Note Různé kombinace JSONArray a JSONObject představují vlastně prakticky používaný JSON formát. Není v tom žádná další složitost.
1.3. Zpracování JSON v Javě ■ existuje mnoho parserů ● srovnání na http://blog.novoj.net/2012/02/05/json-java-parsers-generators-microbenchmark/ ■ ze srovnání vybrán Jackson jako nejlepší
Note Při pokusu o stažení fastJSON v2.1.22 z fastjson.codeplex.com hlásí Firefox: “Tento soubor obsahuje vir či malvare s-msft.com.” Všechny další pokusy byly proto přerušeny. ■ základní info o použití: ● http://wiki.fasterxml.com/JacksonInFiveMinutes ● http://www.journaldev.com/2324/jackson-json-java-parser-api-example-tutorial ■ potřebujeme .jar soubory: ● jackson-core-2.8.4.jar ● jackson-databind-2.8.4.jar ● jackson-annotations-2.8.5.jar
JSON (a Java), © Pavel Herout, 2017 XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
4
■ práce s JSON soubory v Jackson se podobá práci s XML soubory v Java Core API ● k dispozici jsou tři způsoby načtení souboru ♦ Streaming API – jako StAX API ♦ Tree Model – jako XML DOM ♦ Data Binding – jako JAXB, ale jednodušší – využívá POJO (Plain Old Java Object)
1.3.1. Ukázka Data Binding 1.3.1.1. Použitý JSON formát ■ soubor data-utrata.json { "cena": { "hodnota": 256, "mena": "CZK" }, "zbozi": ["pivo", "rum", "fernet"], "placeno kartou": false }
1.3.1.2. Odpovídající POJO třída Note POJO objekty jsou jednoduché Java entitní třídy s atributy a příslušnými getry a setry. package datovyobjekt; import java.util.List; import com.fasterxml.jackson.annotation.JsonProperty; public class Utrata { public enum Mena { CZK, EUR, USD }; public static class Cena { private int hodnota; private Mena mena; public int getHodnota() { return hodnota; } public Mena getMena() { return mena; } public void setHodnota(int h) { hodnota = h; } public void setMena(Mena m) { mena = m; }
JSON (a Java), © Pavel Herout, 2017 XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
5
public String toString() { return hodnota + " " + mena; } } // atributy private Cena cena; private List<String> zbozi; @JsonProperty("placeno kartou") private boolean placenoKartou; // getry public Cena getCena() { return cena; } public List<String> getZbozi() { return zbozi; } public boolean isPlacenoKartou() { return placenoKartou; } // setry public void setCena(Cena c) { cena = c; } public void setZbozi(List<String> z) { zbozi = z; } public void setPlacenoKartou(boolean pk) { placenoKartou = pk;
}
@Override public String toString() { return "cena = " + cena + ", zbozi: " + zbozi + ", placeno kartou: " + ► placenoKartou; } }
Note Všimněte si použití anotace: @JsonProperty("placeno kartou") private boolean placenoKartou; která dovolí mít jiné jméno Java atributu a jiné jméno příslušného JSON elementu.
1.3.1.3. Čtení a zápis jednoho JSON objektu package jsontojava; import java.io.File; import java.net.URL; import java.util.Arrays; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import datovyobjekt.Utrata; import datovyobjekt.Utrata.Cena; import datovyobjekt.Utrata.Mena; public class JSONInOutObjekt {
JSON (a Java), © Pavel Herout, 2017 XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
6
public static void main(String[] args) { ObjectMapper mapper = new ObjectMapper(); System.out.println("Nacteno:"); JSONcteni(mapper); System.out.println("Vypsano:"); JSONzapis(mapper); } private static void JSONcteni(ObjectMapper mapper) { try { Utrata utrataSoubor = mapper.readValue(new File("data-utrata.json"), ► Utrata.class); System.out.println(utrataSoubor); // Utrata utrataURL = mapper.readValue( // new ► URL("http://www.kiv.zcu.cz/~herout/data/data-utrata-URL.json"), // Utrata.class); // System.out.println(utrataURL); } catch (Exception e) { e.printStackTrace(); } } private static void JSONzapis(ObjectMapper mapper) { try { Utrata utrata = new Utrata(); Cena c = new Cena(); c.setHodnota(53); c.setMena(Mena.EUR); utrata.setCena(c); utrata.setZbozi(Arrays.asList("kofola", "juice")); utrata.setPlacenoKartou(true); mapper.writeValue(new File("modifikovana-utrata.json"), utrata); mapper.configure(SerializationFeature.INDENT_OUTPUT, true); String jsonString = mapper.writeValueAsString(utrata); System.out.println(jsonString); } catch (Exception e) { e.printStackTrace(); } } } ■ program vypíše: Nacteno: cena = 256 CZK, zbozi: [pivo, rum, fernet], placeno kartou: false
JSON (a Java), © Pavel Herout, 2017 XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
7
Vypsano: { "cena" : { "hodnota" : 53, "mena" : "EUR" }, "zbozi" : [ "kofola", "juice" ], "placeno kartou" : true } ■ obsah souboru modifikovana-utrata.json: {"cena":{"hodnota":53,"mena":"EUR"},"zbozi":["kofola","juice"],"placeno ► kartou":true}
1.3.1.4. Čtení a zápis seznamu JSON objektů ■ soubor data-utrata-seznam.json [ { "cena" : { "hodnota" : 53, "mena" : "EUR" }, "zbozi" : [ "kofola", "juice" ], "placeno kartou" : true } , { "cena": { "hodnota": 256, "mena": "CZK" }, "zbozi": ["pivo", "rum", "fernet"], "placeno kartou": false } , { "cena": { "hodnota": 12, "mena": "USD" }, "zbozi": ["BigMac", "ZeroCola", "doughnut"], "placeno kartou": true } ] ■ při čtení celého seznamu využijeme generický datový typ TypeReference
>, který je typován na příslušný seznam
JSON (a Java), © Pavel Herout, 2017 XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
8
● to umožní vyhnout se nepřeložitelné konstrukci typu List.class package jsontojava; import java.io.File; import java.util.List; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import datovyobjekt.Utrata; public class JSONInOutSeznam { public static void main(String[] args) { ObjectMapper mapper = new ObjectMapper(); List seznam = JSONcteni(mapper); JSONzapis(mapper, seznam); } private static List JSONcteni(ObjectMapper mapper) { List utrataSeznam = null; try { utrataSeznam = mapper.readValue(new File("data-utrata-seznam.json"), new TypeReference>() { }); for (Utrata utrata : utrataSeznam) { System.out.println(utrata); } } catch (Exception e) { e.printStackTrace(); } return utrataSeznam; } private static void JSONzapis(ObjectMapper mapper, List seznam) { try { mapper.writeValue(new File("modifikovana-utrata-seznam.json"), seznam); } catch (Exception e) { e.printStackTrace(); } } } ■ program vypíše: cena = 53 EUR, zbozi: [kofola, juice], placeno kartou: true cena = 256 CZK, zbozi: [pivo, rum, fernet], placeno kartou: false cena = 12 USD, zbozi: [BigMac, ZeroCola, doughnut], placeno kartou: true ■ obsah souboru modifikovana-utrata-seznam.json:
JSON (a Java), © Pavel Herout, 2017 XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
9
[{"cena":{"hodnota":53,"mena":"EUR"},"zbozi":["kofola","juice"],"placeno ► kartou":true},{"cena":{"hodnota":256,"mena":"CZK"},"zbozi":["pivo","rum","fernet"],"placeno ► kartou":false},{"cena":{"hodnota":12,"mena":"USD"},"zbozi":["BigMac","ZeroCola","doughnut"],"placeno ► kartou":true}]
JSON (a Java), © Pavel Herout, 2017 XML to PDF by RenderX XEP XSL-FO Formatter, visit us at http://www.renderx.com/
10