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.