Fa modellcsomópontokkal való munka Jacksonban

1. Áttekintés

Ez az oktatóanyag a munkára összpontosít fa modell csomópontok Jacksonban.

Majd használjuk JsonNode különféle konverziókhoz, valamint csomópontok hozzáadásához, módosításához és eltávolításához.

2. Csomópont létrehozása

A csomópont létrehozásának első lépése az ObjectMapper objektumot az alapértelmezett konstruktor használatával:

ObjectMapper mapper = új ObjectMapper ();

Létrehozása óta egy ObjectMapper Az objektum drága, ezért javasoljuk, hogy ugyanazt használja fel több művelethez.

Ezután három különböző módon lehet létrehozni egy facsomót, amint megvan ObjectMapper.

2.1. Készítsen egy csomópontot a Scratchból

A csomópont semmiből történő létrehozásának leggyakoribb módja a következő:

JsonNode csomópont = mapper.createObjectNode ();

Alternatív megoldásként létrehozhatunk egy csomópontot a JsonNodeFactory:

JsonNode csomópont = JsonNodeFactory.instance.objectNode ();

2.2. Elemzés egy JSON-forrásból

Ezt a módszert jól tárgyalja a Jackson - Marshall karakterlánc a JsonNode-hoz cikk. Kérjük, olvassa el, ha további információra van szüksége.

2.3. Konvertálás objektumból

A csomópont átalakítható Java objektumból a valueToTree (Object fromValue) módszer a ObjectMapper:

JsonNode csomópont = mapper.valueToTree (fromValue);

A convertValue Az API itt is hasznos:

JsonNode csomópont = mapper.convertValue (fromValue, JsonNode.class);

Nézzük meg, hogyan működik a gyakorlatban. Tegyük fel, hogy van egy nevű osztályunk NodeBean:

public class NodeBean {private int id; privát karakterlánc neve; public NodeBean () {} public NodeBean (int id, String name) {this.id = id; ez.név = név; } // szokásos mérőeszközök és beállítók}

Írjunk egy tesztet, amely biztosítja, hogy az átalakítás helyesen történjen:

@Test public void givenAnObject_whenConvertingIntoNode_thenCorrect () {NodeBean fromValue = new NodeBean (2016, "baeldung.com"); JsonNode csomópont = mapper.valueToTree (fromValue); assertEquals (2016, node.get ("id"). intValue ()); assertEquals ("baeldung.com", node.get ("név"). textValue ()); }

3. Csomópont átalakítása

3.1. Írja ki JSON néven

A fa csomópont JSON karakterláncsá történő átalakításának alapvető módszere a következő:

mapper.writeValue (cél, csomópont);

ahol a cél lehet a File, an OutputStream vagy a Író.

Az osztály újrafelhasználásával NodeBean a 2.3. szakaszban meghatározottak szerint egy teszt biztosítja, hogy ez a módszer a várt módon működjön:

final String pathToTestFile = "node_to_json_test.json"; @Test public void givenANode_whenModifyingIt_thenCorrect () dobja az IOException {String newString = "{\" nick \ ": \" cowtowncoder \ "}"; JsonNode newNode = mapper.readTree (newString); JsonNode rootNode = ExampleStructure.getExampleRoot (); ((ObjectNode) rootNode) .set ("név", newNode); assertFalse (rootNode.path ("név"). elérési út ("nick"). isMissingNode ()); assertEquals ("cowtowncoder", rootNode.path ("név"). elérési út ("nick"). textValue ()); }

3.2. Konvertálás objektummá

A legkényelmesebb módja a JsonNode Java objektumba az treeToValue API:

NodeBean toValue = mapper.treeToValue (csomópont, NodeBean.class);

Ami funkcionálisan egyenértékű:

NodeBean toValue = mapper.convertValue (csomópont, NodeBean.class)

Megtehetjük ezt egy token stream-en keresztül is:

JsonParser elemző = mapper.treeAsTokens (csomópont); NodeBean toValue = mapper.readValue (elemző, NodeBean.class);

Végül hajtsunk végre egy tesztet, amely igazolja az átalakítási folyamatot:

@Test public void givenANode_whenConvertingIntoAnObject_thenCorrect () dobja a JsonProcessingException {JsonNode csomópont = mapper.createObjectNode (); ([ObjectNode] csomópont) .put ("id", 2016); ((ObjectNode) csomópont) .put ("név", "baeldung.com"); NodeBean toValue = mapper.treeToValue (csomópont, NodeBean.class); assertEquals (2016, toValue.getId ()); assertEquals ("baeldung.com", toValue.getName ()); }

4. Facsomók manipulálása

A következő JSON elemek, egy megnevezett fájlban példa.json, az ebben a szakaszban tárgyalt tevékenységek alapstruktúrájaként szolgálnak:

{"name": {"first": "Tatu", "last": "Saloranta"}, "title": "Jackson alapító", "company": "FasterXML"}

Ez az osztályútvonalon található JSON-fájl egy modellfává van elemezve:

public class ExampleStructure {private static ObjectMapper mapper = new ObjectMapper (); statikus JsonNode getExampleRoot () dobja az IOException {InputStream exampleInput = ExampleStructure.class.getClassLoader () .getResourceAsStream ("example.json"); JsonNode rootNode = mapper.readTree (exampleInput); return rootNode; }}

Ne feledje, hogy a fa gyökerét a csomópontokon végzett műveletek illusztrálásához használják a következő alszakaszokban.

4.1. Csomópont keresése

Mielőtt bármilyen csomóponton dolgoznánk, az első dolog, amit meg kell tennünk, hogy megkeressük és hozzárendeljük egy változóhoz.

Ha a csomópont elérési útja előzetesen ismert, ezt elég könnyű megtenni. Tegyük fel például, hogy nevű csomópontot akarunk utolsó, amely a név csomópont:

JsonNode locatedNode = rootNode.path ("név"). Elérési út ("utolsó");

Alternatív megoldásként a kap vagy val vel Az API-k helyett is használhatók pálya.

Ha az út nem ismert, akkor a keresés természetesen összetettebbé és iteratívabbá válik.

Láthatunk egy példát az összes csomópont iterációjára az 5. Az iteráció a csomópontok felett részben

4.2. Új csomópont hozzáadása

Egy csomópont hozzáadható egy másik csomópont gyermekeként az alábbiak szerint:

ObjectNode newNode = ([(ObjectNode) locatedNode) .put (mezőnév, érték);

Számos túlterhelt változata tedd felhasználható új, különböző típusú értékű csomópontok hozzáadásához.

Sok más hasonló módszer is rendelkezésre áll, többek között putArray, putObject, PutPOJO, putRawValue és putNull.

Végül - nézzünk meg egy példát -, ahol egy teljes struktúrát adunk a fa gyökércsomópontjához:

"address": {"city": "Seattle", "state": "Washington", "country": "Egyesült Államok"}

Itt van a teljes teszt, amely az összes műveletet elvégzi és ellenőrzi az eredményeket:

@Test public void givenANode_whenAddingIntoATree_thenCorrect () dobja az IOException {JsonNode rootNode = ExampleStructure.getExampleRoot (); ObjectNode addedNode = (((ObjectNode) rootNode) .putObject ("cím"); addedNode .put ("város", "Seattle") .put ("állam", "Washington") .put ("ország", "Egyesült Államok"); assertFalse (rootNode.path ("cím"). isMissingNode ()); assertEquals ("Seattle", rootNode.path ("cím"). elérési út ("város". textValue ()); assertEquals ("Washington", rootNode.path ("cím"). elérési út ("állam". textValue ()); assertEquals ("Egyesült Államok", rootNode.path ("cím"). elérési út ("ország"). textValue ();}

4.3. Csomópont szerkesztése

An ObjectNode példány meghívással módosítható set (karakterlánc mezőnév, JsonNode érték) módszer:

JsonNode foundNode = találhatóNode.set (mezőNév, érték);

Hasonló eredményeket lehet elérni a cserélje ki vagy setAll módszerek azonos típusú objektumokon.

Annak ellenőrzésére, hogy a módszer a várt módon működik-e, megváltoztatjuk a mező értékét név objektum gyökércsomópontja alatt első és utolsó egy másikba, amely csak nick mező egy tesztben:

@Test public void givenANode_whenModifyingIt_thenCorrect () dobja az IOException {String newString = "{\" nick \ ": \" cowtowncoder \ "}"; JsonNode newNode = mapper.readTree (newString); JsonNode rootNode = ExampleStructure.getExampleRoot (); ((ObjectNode) rootNode) .set ("név", newNode); assertFalse (rootNode.path ("név"). elérési út ("nick"). isMissingNode ()); assertEquals ("cowtowncoder", rootNode.path ("név"). elérési út ("nick"). textValue ()); }

4.4. Csomópont eltávolítása

Egy csomópont eltávolítható a eltávolít (String fieldName) API a szülőcsomópontján:

JsonNode eltávolítottNode = találhatóNode.remove (fieldName);

Több csomópont egyszerre történő eltávolítása érdekében meghívhatunk egy túlterhelt metódust a Gyűjtemény típus, amely a szülőcsomópontot adja vissza az eltávolítandó helyett:

ObjectNode locatedNode = találhatóNode.remove (fieldNames);

Szélsőséges esetben, amikor egy adott csomópont összes alcsomópontját törölni akarjuk a összes eltávolítása Az API jól jön.

A következő teszt a fent említett első módszerre összpontosít - ez a leggyakoribb forgatókönyv:

@Test public void givenANode_whenRemovingFromATree_thenCorrect () dobja az IOException {JsonNode rootNode = ExampleStructure.getExampleRoot (); ((ObjectNode) rootNode) .remove ("vállalat"); assertTrue (rootNode.path ("vállalat"). isMissingNode ()); }

5. Iterálás a csomópontok felett

Ismételjük meg a JSON-dokumentum összes csomópontját, és formázzuk át őket YAML-be. A JSON-nak háromféle csomópontja van, ezek: Érték, Objektum és Tömb.

Tehát, győződjünk meg arról, hogy a mintaadataink mindhárom különböző típusba tartoznak egy Sor:

{"name": {"first": "Tatu", "last": "Saloranta"}, "title": "Jackson alapító", "company": "FasterXML", "pets": [{"type": "kutya", "szám": 1}, {"type": "hal", "szám": 50}]}

Most nézzük meg a YAML-t, amelyet elő akarunk állítani:

név: első: Tatu utolsó: Saloranta cím: Jackson alapító cég: FasterXML pets: - típus: kutyaszám: 1 - típus: halszám: 50

Tudjuk, hogy a JSON csomópontok hierarchikus faszerkezettel rendelkeznek. Tehát a teljes JSON-dokumentum ismétlésének legegyszerűbb módja az, ha felülről indul, és lefelé halad az összes gyermekcsomóponton keresztül.

A gyökércsomópontot átadjuk egy rekurzív módszernek. Ezután a módszer felhívja magát a mellékelt csomópont minden egyes gyermekével.

5.1. Az iteráció tesztelése

Először egy egyszerű teszt létrehozásával ellenőrizzük, hogy a JSON-ot sikeresen konvertálhatjuk-e YAML-be.

Tesztünk eljuttatja a JSON dokumentum gyökércsomópontját toYaml módszer, és azt állítja, hogy a visszatérített érték az, amire számítunk:

@Test public void givenANodeTree_whenIteratingSubNodes_thenWeFindExpected () dobja az IOException {JsonNode rootNode = ExampleStructure.getExampleRoot (); String yaml = onTest.toYaml (rootNode); assertEquals (várhatóYaml, yaml); } public String toYaml (JsonNode root) {StringBuilder yaml = új StringBuilder (); processNode (gyökér, yaml, 0); return yaml.toString (); }}

5.2. Különböző csomópontok kezelése

A különböző típusú csomópontokat kissé eltérően kell kezelnünk. Meg fogjuk csinálni ezt a mi processNode módszer:

private void processNode (JsonNode jsonNode, StringBuilder yaml, int mélység) {if (jsonNode.isValueNode ()) {yaml.append (jsonNode.asText ()); } else if (jsonNode.isArray ()) {for (JsonNode arrayItem: jsonNode) {appendNodeToYaml (arrayItem, yaml, mélység, igaz); }} else if (jsonNode.isObject ()) {appendNodeToYaml (jsonNode, yaml, mélység, hamis); }}

Először vegyük figyelembe az Érték csomópontot. Egyszerűen hívjuk a asText a csomópont metódusa a Húr az érték ábrázolása.

Ezután nézzünk meg egy Array csomópontot. Az Array csomópont minden eleme maga a JsonNode, tehát iterálunk a tömbön, és minden csomópontot átadunk a appendNodeToYaml módszer. Azt is tudnunk kell, hogy ezek a csomópontok egy tömb részei.

Sajnos maga a csomópont nem tartalmaz semmit, ami ezt elmondaná nekünk, ezért egy zászlót adunk át a mi csomópontunkba appendNodeToYaml módszer.

Végül meg akarjuk ismételni az egyes objektum csomópontok összes gyermekcsomópontját. Az egyik lehetőség a használat JsonNode.elements. Ugyanakkor nem tudjuk meghatározni a mező nevét egy elemtől, mivel csak a mező értékét tartalmazza:

Objektum {"first": "Tatu", "last": "Saloranta"} Érték "Jackson Founder" Érték "FasterXML" tömb [{"type": "kutya", "szám": 1}, {"type": "hal", "szám": 50}]

Ehelyett használjuk JsonNode.fields mivel ez hozzáférést biztosít mind a mező nevéhez, mind az értékéhez:

Kulcs = "név", Érték = Objektum "" első ":" Tatu "," Utolsó ":" Saloranta "} Kulcs =" cím ", Érték = Érték" Jackson alapító "Key =" vállalat ", Érték = Érték" FasterXML "Key =" pets ", Value = Array [{" type ":" kutya "," number ": 1}, {" type ":" fish "," number ": 50}]

Minden mezőhöz hozzáadjuk a mező nevét a kimenethez. Ezután dolgozza fel az értéket gyermekcsomópontként, továbbítva azt az processNode módszer:

private void appendNodeToYaml (JsonNode csomópont, StringBuilder yaml, int mélység, logikai isArrayItem) {Iterator mezők = csomópont.mezők (); logikai isFirst = igaz; while (mezők.hasNext ()) {JsonField = mezők.next () bejegyzés; addFieldNameToYaml (yaml, jsonField.getKey (), mélység, isArrayItem && isFirst); processNode (jsonField.getValue (), yaml, mélység + 1); isFirst = hamis; }}

A csomópontból nem tudjuk megmondani, hogy hány őse van. Tehát egy mélység nevű mezőt adunk át a processNode módszer ennek nyomon követésére. Ezt az értéket minden alkalommal növeljük, amikor gyermekcsomópontot kapunk, hogy helyesen tudjuk behúzni a mezőket a YAML kimenetünkben:

private void addFieldNameToYaml (StringBuilder yaml, String fieldName, int mélység, logikai isFirstInArray) {if (yaml.length ()> 0) {yaml.append ("\ n"); int requiredDepth = (isFirstInArray)? mélység-1: mélység; for (int i = 0; i <szükséges mélység; i ++) {yaml.append (""); } if (isFirstInArray) {yaml.append ("-"); }} yaml.append (mezőNév); yaml.append (":"); }

Most, hogy az összes kód megvan a csomópontok ismétléséhez és a YAML kimenet létrehozásához, futtathatjuk tesztünket, hogy megmutassuk, működik-e.

6. Következtetés

Ez az oktatóanyag egy fa modellel való munka általános API-jait és forgatókönyveit ismertette Jacksonban.

És mint mindig, ezeknek a példáknak és kódrészleteknek a megvalósítása megtalálható itt át a GitHubon - ez egy Maven-alapú projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.