Práca s uzlami stromových modelov v Jackson

1. Prehľad

Tento výukový program sa zameria na prácu s programom uzly stromového modelu v Jackson.

Použijeme JsonNode na rôzne konverzie, ako aj na pridávanie, úpravu a odstraňovanie uzlov.

2. Vytvorenie uzla

Prvým krokom pri vytváraní uzla je vytvorenie inštancie ObjectMapper objekt pomocou predvoleného konštruktora:

ObjectMapper mapovač = nový ObjectMapper ();

Od vytvorenia ObjectMapper objekt je drahý, odporúča sa, aby bol ten istý opakovane používaný pre viac operácií.

Ďalej máme tri rôzne spôsoby, ako vytvoriť uzol stromu, keď už máme ObjectMapper.

2.1. Vytvorte uzol od začiatku

Najbežnejší spôsob, ako vytvoriť uzol z ničoho, je nasledujúci:

Uzol JsonNode = mapper.createObjectNode ();

Prípadne môžeme vytvoriť uzol aj pomocou JsonNodeFactory:

Uzol JsonNode = JsonNodeFactory.instance.objectNode ();

2.2. Analýza zo zdroja JSON

Tejto metóde sa dobre venuje článok Jackson - Marshall String to JsonNode. Ak potrebujete ďalšie informácie, pozrite si ho.

2.3. Prevod z objektu

Uzol je možné previesť z objektu Java volaním súboru valueToTree (objekt z hodnoty) metóda na ObjectMapper:

JsonNode node = mapper.valueToTree (fromValue);

The convertValue API je tu tiež užitočné:

JsonNode node = mapper.convertValue (fromValue, JsonNode.class);

Pozrime sa, ako to funguje v praxi. Predpokladajme, že máme pomenovanú triedu NodeBean:

verejná trieda NodeBean {private int id; súkromné ​​meno reťazca; public NodeBean () {} public NodeBean (int id, názov reťazca) {this.id = id; this.name = meno; } // štandardní zakladatelia a zakladatelia}

Poďme napísať test, ktorý zabezpečí, že ku konverzii dôjde správne:

@Test public void givenAnObject_whenConvertingIntoNode_thenCorrect () {NodeBean fromValue = nový NodeBean (2016, "baeldung.com"); JsonNode node = mapper.valueToTree (fromValue); assertEquals (2016, node.get ("id"). intValue ()); assertEquals ("baeldung.com", node.get ("meno"). textValue ()); }

3. Transformácia uzla

3.1. Vypisujte ako JSON

Základná metóda na transformáciu uzla stromu na reťazec JSON je nasledovná:

mapper.writeValue (cieľ, uzol);

kde môže byť cieľ a Súbor, an OutputStream alebo a Spisovateľ.

Opätovným použitím triedy NodeBean deklarované v časti 2.3, test zaručuje, že táto metóda funguje podľa očakávania:

final String pathToTestFile = "node_to_json_test.json"; @ Test public void givenANode_whenModifyingIt_thenCorrect () vyvolá IOException {String newString = "{\" nick \ ": \" cowtowncoder \ "}"; JsonNode newNode = mapper.readTree (newString); JsonNode rootNode = ExampleStructure.getExampleRoot (); ((ObjectNode) rootNode) .set ("name", newNode); assertFalse (rootNode.path ("name"). path ("nick"). isMissingNode ()); assertEquals ("cowtowncoder", rootNode.path ("meno"). cesta ("nick"). textValue ()); }

3.2. Konvertovať na objekt

Najpohodlnejší spôsob prevodu a JsonNode do objektu Java je treeToValue API:

NodeBean toValue = mapovač.treeToValue (uzol, NodeBean.class);

Čo je funkčne ekvivalentné s:

NodeBean toValue = mapper.convertValue (uzol, NodeBean.class)

Môžeme to urobiť aj prostredníctvom toku tokenov:

Analyzátor JsonParser = mapovač.treeAsTokens (uzol); NodeBean toValue = mapovač.readValue (analyzátor, NodeBean.class);

Na záver poďme implementovať test, ktorý overí proces konverzie:

@ Test public void givenANode_whenConvertingIntoAnObject_thenCorrect () hodí JsonProcessingException {JsonNode node = mapper.createObjectNode (); ((ObjectNode) node) .put ("id", 2016); ((ObjectNode) node) .put ("name", "baeldung.com"); NodeBean toValue = mapovač.treeToValue (uzol, NodeBean.class); assertEquals (2016, toValue.getId ()); assertEquals ("baeldung.com", toValue.getName ()); }

4. Manipulácia s uzlami stromov

Nasledujúce prvky JSON obsiahnuté v súbore s názvom priklad.json, sa používajú ako základná štruktúra pre činnosti diskutované v tejto časti, ktoré sa majú vykonať:

{"name": {"first": "Tatu", "last": "Saloranta"}, "title": "zakladateľ spoločnosti Jackson", "spoločnosť": "FasterXML"}

Tento súbor JSON, ktorý sa nachádza na ceste triedy, je analyzovaný do modelového stromu:

verejná trieda ExampleStructure {private static ObjectMapper mapper = new ObjectMapper (); static JsonNode getExampleRoot () vyvolá IOException {InputStream exampleInput = ExampleStructure.class.getClassLoader () .getResourceAsStream ("example.json"); JsonNode rootNode = mapovač.readTree (príkladInput); návrat rootNode; }}

Upozorňujeme, že koreň stromu sa použije na ilustráciu operácií na uzloch v nasledujúcich podkapitolách.

4.1. Vyhľadanie uzla

Pred prácou na ľubovoľnom uzle je potrebné najskôr vyhľadať a priradiť ho k premennej.

Ak je cesta k uzlu známa vopred, je to celkom ľahké. Povedzme napríklad, že chceme mať uzol s názvom posledný, ktorý je pod názov uzol:

JsonNode locatedNode = rootNode.path ("name"). Path ("last");

Prípadne dostať alebo s Namiesto nich je možné použiť aj API cesta.

Ak cesta nie je známa, bude vyhľadávanie samozrejme zložitejšie a iteratívnejšie.

Príklad iterácie cez všetky uzly môžeme vidieť na 5. Iterácii cez uzly

4.2. Pridanie nového uzla

Uzol je možné pridať ako potomok iného uzla nasledovne:

ObjectNode newNode = ((ObjectNode) locatedNode) .put (fieldName, value);

Mnoho preťažených variantov dať sa môžu použiť na pridanie nových uzlov rôznych typov hodnôt.

K dispozícii je tiež mnoho ďalších podobných metód, vrátane putArray, putObject, PutPOJO, putRawValue a putNull.

Na záver - pozrime sa na príklad - keď do koreňového uzla stromu pridáme celú štruktúru:

"address": {"city": "Seattle", "state": "Washington", "country": "United States"}

Tu je úplný test, ktorý prechádza všetkými týmito operáciami a overuje výsledky:

@ Test public void givenANode_whenAddingIntoATree_thenCorrect () vyvolá IOException {JsonNode rootNode = ExampleStructure.getExampleRoot (); ObjectNode addedNode = ((ObjectNode) rootNode) .putObject ("adresa"); addedNode .put ("mesto", "Seattle") .put ("štát", "Washington") .put ("krajina", "USA"); assertFalse (rootNode.path ("adresa"). isMissingNode ()); assertEquals ("Seattle", rootNode.path ("adresa"). cesta ("mesto"). textValue ()); assertEquals ("Washington", rootNode.path ("adresa"). cesta ("štát"). textValue ()); assertEquals ("USA", rootNode.path ("adresa"). cesta ("krajina"). textValue ();}

4.3. Úprava uzla

An ObjectNode inštanciu je možné upraviť vyvolaním sada (reťazec fieldName, hodnota JsonNode) metóda:

JsonNode locatedNode = locatedNode.set (fieldName, value);

Podobné výsledky možno dosiahnuť použitím vymeniť alebo setAll metódy na objektoch rovnakého typu.

Aby sme overili, že metóda funguje podľa očakávania, zmeníme hodnotu poľa názov pod koreňovým uzlom z objektu najprv a posledný do iného pozostávajúceho iba z prezývka pole v teste:

@ Test public void givenANode_whenModifyingIt_thenCorrect () vyvolá IOException {String newString = "{\" nick \ ": \" cowtowncoder \ "}"; JsonNode newNode = mapper.readTree (newString); JsonNode rootNode = ExampleStructure.getExampleRoot (); ((ObjectNode) rootNode) .set ("name", newNode); assertFalse (rootNode.path ("name"). path ("nick"). isMissingNode ()); assertEquals ("cowtowncoder", rootNode.path ("meno"). cesta ("nick"). textValue ()); }

4.4. Odstránenie uzla

Uzol je možné odstrániť zavolaním na remove (String fieldName) API na svojom nadradenom uzle:

JsonNode removeNode = locatedNode.remove (fieldName);

Aby sme mohli odstrániť viac uzlov naraz, môžeme vyvolať preťaženú metódu s parametrom Zbierka typ, ktorý vráti nadradený uzol namiesto toho, ktorý sa má odstrániť:

ObjectNode locatedNode = locatedNode.remove (fieldNames);

V krajnom prípade, keď chceme vymazať všetky poduzly daného uzla the odobrať všetky API sa hodí.

Nasledujúci test sa zameria na prvú metódu uvedenú vyššie - čo je najbežnejší scenár:

@ Test public void givenANode_whenRemovingFromATree_thenCorrect () vyvolá IOException {JsonNode rootNode = ExampleStructure.getExampleRoot (); ((ObjectNode) rootNode) .remove ("spoločnosť"); assertTrue (rootNode.path ("spoločnosť"). isMissingNode ()); }

5. Iterácia cez uzly

Poďme iterovať všetky uzly v dokumente JSON a preformátujme ich na YAML. JSON má tri typy uzlov, ktorými sú Value, Object a Array.

Zabezpečme teda, aby naše vzorové údaje mali všetky tri rôzne typy pridaním znaku Pole:

{"name": {"first": "Tatu", "last": "Saloranta"}, "title": "zakladateľ spoločnosti Jackson", "spoločnosť": "FasterXML", "pets": [{"type": "dog", "number": 1}, {"type": "fish", "number": 50}]}

Teraz sa pozrime na YAML, ktorý chceme vyrobiť:

meno: prvé: Tatu posledné: Saloranta titul: zakladateľská spoločnosť Jackson: FasterXML domáce zvieratá: - typ: číslo psa: 1 - typ: číslo ryby: 50

Vieme, že uzly JSON majú hierarchickú stromovú štruktúru. Najjednoduchší spôsob, ako iterovať v celom dokumente JSON, je začať zhora a postupovať dole cez všetky podradené uzly.

Koreňový uzol odovzdáme rekurzívnej metóde. Metóda sa potom bude volať s každým potomkom dodávaného uzla.

5.1. Testovanie iterácie

Začneme tým, že vytvoríme jednoduchý test, ktorý skontroluje, či môžeme úspešne konvertovať JSON na YAML.

Náš test dodáva nášmu koreňovému uzlu dokumentu JSON toYaml metóda a tvrdí, že vrátená hodnota je to, čo očakávame:

@ Test public void givenANodeTree_whenIteratingSubNodes_thenWeFindExected () vyvolá IOException {JsonNode rootNode = ExampleStructure.getExampleRoot (); Reťazec yaml = onTest.toYaml (rootNode); assertEquals (expectYaml, yaml); } public String toYaml (koreň JsonNode) {StringBuilder yaml = nový StringBuilder (); processNode (root, yaml, 0); vrátiť yaml.toString (); }}

5.2. Zaobchádzanie s rôznymi typmi uzlov

S rôznymi typmi uzlov musíme narábať trochu odlišne. Urobíme to v našom processNode metóda:

private void processNode (JsonNode jsonNode, StringBuilder yaml, int depth) {if (jsonNode.isValueNode ()) {yaml.append (jsonNode.asText ()); } else if (jsonNode.isArray ()) {for (JsonNode arrayItem: jsonNode) {appendNodeToYaml (arrayItem, yaml, depth, true); }} else if (jsonNode.isObject ()) {appendNodeToYaml (jsonNode, yaml, depth, false); }}

Najskôr zvážme uzol Hodnota. Jednoducho hovoríme asText metóda uzla na získanie a String vyjadrenie hodnoty.

Ďalej sa pozrime na uzol Array. Každá položka v uzle Array je sama o sebe a JsonNode, takže iterujeme nad poľom a odovzdávame každý uzol do appendNodeToYaml metóda. Musíme tiež vedieť, že tieto uzly sú súčasťou poľa.

Samotný uzol, bohužiaľ, neobsahuje nič, čo by nám to hovorilo, takže do nás pošleme príznak appendNodeToYaml metóda.

Nakoniec chceme iterovať cez všetky podradené uzly každého uzla Object. Jednou z možností je použitie JsonNode.elements. Nemôžeme však určiť názov poľa z prvku, pretože obsahuje iba hodnotu poľa:

Objekt {"first": "Tatu", "last": "Saloranta"} Hodnota "Jackson Founder" Hodnota "FasterXML" Array [{"type": "dog", "number": 1}, {"type": "fish", "number": 50}]

Namiesto toho použijeme Polia JsonNode pretože nám to umožňuje prístup k názvu aj hodnote poľa:

Key = "name", Value = Object {"first": "Tatu", "last": "Saloranta"} Key = "title", Value = Value "Jackson Founder" Key = "company", Value = Value "FasterXML "Key =" pets ", Value = Array [{" type ":" dog "," number ": 1}, {" type ":" fish "," number ": 50}]

Pre každé pole pridáme do výstupu názov poľa. Potom spracujte hodnotu ako podradený uzol odovzdaním do processNode metóda:

private void appendNodeToYaml (JsonNode node, StringBuilder yaml, int depth, boolean isArrayItem) {Iterator polia = node.fields (); boolean isFirst = true; while (fields.hasNext ()) {Záznam jsonField = fields.next (); addFieldNameToYaml (yaml, jsonField.getKey (), depth, isArrayItem && isFirst); processNode (jsonField.getValue (), yaml, depth + 1); isFirst = false; }}

Z uzla nemôžeme povedať, koľko má predkov. Takže míňame pole zvané hĺbka do processNode spôsob, ako to sledovať. Túto hodnotu zvyšujeme zakaždým, keď dostaneme podradený uzol, aby sme mohli správne odsadiť polia v našom výstupe YAML:

private void addFieldNameToYaml (StringBuilder yaml, String fieldName, int depth, boolean isFirstInArray) {if (yaml.length ()> 0) {yaml.append ("\ n"); int requiredDepth = (isFirstInArray)? hĺbka-1: hĺbka; for (int i = 0; i <requiredDepth; i ++) {yaml.append (""); } if (isFirstInArray) {yaml.append ("-"); }} yaml.append (menoPole); yaml.append (":"); }

Teraz, keď máme všetok kód na mieste na iteráciu cez uzly a vytváranie výstupu YAML, môžeme spustiť náš test a ukázať, že funguje.

6. Záver

Tento kurz sa venoval bežným API a scenárom práce s stromovým modelom v Jackson.

Implementáciu všetkých týchto príkladov a útržkov kódu nájdete ako vždy v cez GitHub - toto je projekt založený na Maven, takže by malo byť ľahké ho importovať a spustiť tak, ako je.


$config[zx-auto] not found$config[zx-overlay] not found