Útmutató a dózerrel történő térképezéshez

1. Áttekintés

A dózer egy Java Bean - Java Bean mapper amely rekurzív módon másolja az adatokat egyik objektumból a másikba, attribútumonként.

A könyvtár nem csak a Java Beans attribútumnevek közötti leképezést támogatja, hanem az is automatikusan konvertál a típusok között - ha különböznek.

A legtöbb konverziós forgatókönyvet dobozon kívül támogatják, de a Dozer is lehetővé teszi adja meg az egyéni konverziókat XML-en keresztül.

2. Egyszerű példa

Első példaként tegyük fel, hogy a forrás és a cél adatobjektumok mindegyike ugyanazokkal a közös attribútumnevekkel rendelkezik.

Ez a legalapvetőbb feltérképezés, amelyet a Dozerrel megtehetünk:

public class Forrás {private String name; privát int kor; public Source () {} public Source (String name, int age) {this.név = név; ez.kor = életkor; } // szokásos mérőeszközök és beállítók}

Ezután a rendeltetési fájlunk, Dest.java:

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

Biztosítanunk kell tartalmazza az alapértelmezett vagy nulla argumentumkonstrukciót, mivel a Dozer a tükröt használja a motorháztető alatt.

Teljesítmény céljából tegyük globálissá a térképkészítőnket, és hozzunk létre egyetlen objektumot, amelyet a tesztjeink során használunk:

DozerBeanMapper térképező; @ Mielőtt a public void előtt () dobja a Kivételt {mapper = new DozerBeanMapper (); }

Most futtassuk le az első tesztünket annak megerősítésére, hogy amikor létrehozunk egy Forrás objektumot, közvetlenül a Rendeltetési hely tárgy:

@Test public void givenSourceObjectAndDestClass_whenMapsSameNameFieldsCorrectly_ thenCorrect () {Source source = new Source ("Baeldung", 10); Dest dest = mapper.map (forrás, Dest.class); assertEquals (dest.getName (), "Baeldung"); assertEquals (dest.getAge (), 10); }

Mint láthatjuk, a Dozer leképezés után az eredmény a. Új példánya lesz Rendeltetési hely objektum, amely értékeket tartalmaz minden olyan mezőhöz, amelynek ugyanaz a mezőneve, mint a Forrás tárgy.

Alternatívaként, ahelyett, hogy elmúlna térképező a Rendeltetési hely osztályban, csak létrehozhattuk volna a Rendeltetési hely tárgy és átment térképező hivatkozása:

@Test public void givenSourceObjectAndDestObject_whenMapsSameNameFieldsCorrectly_ thenCorrect () {Source source = new Source ("Baeldung", 10); Dest dest = új Dest (); mapper.map (forrás, cél); assertEquals (dest.getName (), "Baeldung"); assertEquals (dest.getAge (), 10); }

3. Maven Setup

Most, hogy alaposan megértettük a Dozer működését, adjuk hozzá a következő függőséget a pom.xml:

 net.sf.dózer dózer 5.5.1 

A legfrissebb verzió itt érhető el.

4. Adatkonverzió példa

Mint már tudjuk, a Dozer egy meglévő objektumot képes leképezni egy másikra, amennyiben mindkét osztályban azonos nevű attribútumokat talál.

Ez azonban nem mindig így van; és így, ha a leképezett attribútumok bármelyike ​​különböző adattípusú, akkor a Dozer leképező motor fogja automatikusan végez adattípus-átalakítást.

Lássuk működés közben ezt az új koncepciót:

public class Source2 {private String id; magán kettős pontok; public Source2 () {} public Source2 (String id, dupla pontok) {this.id = id; ez.pontok = pontok; } // szokásos mérőeszközök és beállítók}

És a rendeltetési osztály:

nyilvános osztály Dest2 {private int id; magán int pontok; public Dest2 () {} public Dest2 (int id, int pontok) {super (); ez.id = id; ez.pontok = pontok; } // szokásos mérőeszközök és beállítók}

Figyelje meg, hogy az attribútumok nevei megegyeznek, de adattípusaik eltérőek.

A forrás osztályban id egy Húr és pontokat egy kettős, míg a rendeltetési osztályban id és pontokat mindkettő egész száms.

Most nézzük meg, hogy a Dózer hogyan kezeli helyesen az átalakítást:

@Test public void givenSourceAndDestWithDifferFieldTypes_ whenMapsAndAutoConverts_thenCorrect () {Source2 source = new Source2 ("320", 15.2); Dest2 dest = mapper.map (forrás, Dest2.osztály); assertEquals (dest.getId (), 320); assertEquals (dest.getPoints (), 15); }

Átmentünk “320” és 15.2, a Húr és a kettős a forrásobjektumba és az eredménynek 320 és 15, mindkét egész száms a célobjektumban.

5. Alapvető egyéni hozzárendelések XML-en keresztül

Az összes korábbi példában, amelyet láttunk, mind a forrás, mind a cél adatobjektumoknak ugyanazok a mezőnevek vannak, ami lehetővé teszi az oldalunkon történő egyszerű leképezést.

A valós alkalmazásokban azonban számtalanszor előfordul, hogy az általunk leképezett két adatobjektumnak nem lesz közös tulajdonságnevű mezője.

Ennek megoldására a Dozer lehetőséget ad arra, hogy létrehozzunk egy egyéni leképezési konfiguráció XML-ben.

Ebben az XML fájlban meghatározhatunk osztályleképezési bejegyzéseket, amelyeket a Dozer leképező motor használni fog annak eldöntésére, hogy milyen forrásattribútumot milyen célattribútumhoz társítson.

Vessen egy pillantást egy példára, és próbálkozzon az adatobjektumok feloldásával egy francia programozó által létrehozott alkalmazásból az objektumok elnevezésének angol stílusáig.

Nekünk van Személy objektum azzal név, becenév és kor mezők:

public class Személy {private String név; privát String becenév; privát int kor; public Person () {} public Person (karakterlánc neve, String beceneve, int kor) {super (); ez.név = név; ez.név = becenév; ez.kor = életkor; } // szokásos mérőeszközök és beállítók}

Megnevezzük azt az objektumot, amelyet eltávolítunk Personne és mezõi vannak nom, surnom és kor:

nyilvános osztály Personne {privát húr nom; privát húrlánc; privát int kor; public Personne () {} public Personne (String nom, String surnom, int age) {szuper (); ez.nom = nom; this.surnom = surnom; ez.kor = életkor; } // szokásos mérőeszközök és beállítók}

Ezek a tárgyak valóban ugyanazt a célt érik el, de nyelvi akadályaink vannak. Annak érdekében, hogy segítsünk ennek az akadálynak, a Dozer segítségével feltérképezhetjük a franciákat Personne kifogásolni a mi Személy tárgy.

Csak egy egyedi leképező fájlt kell létrehoznunk, hogy a Dozer segítsen ebben. Ezt hívjuk dozer_mapping.xml:

   com.baeldung.dozer.Personne com.baeldung.dozer.Person nom név   surnom becenév

Ez a legegyszerűbb példa a rendelkezésünkre álló egyéni XML-leképezési fájlra.

Egyelőre elég észrevenni, hogy van mint gyökérelemünk, amelynek gyermeke van , annyi ilyen gyerek lehet bent mivel vannak olyan osztálypárok, amelyek egyedi leképezést igényelnek.

Figyelje meg azt is, hogyan adjuk meg a forrás és cél osztályokat a címkék. Ezt követi a minden egyes forrás- és célmezőpárhoz, amelyek egyedi leképezést igényelnek.

Végül vegye észre, hogy nem vettük fel a mezőt kor az egyedi leképezési fájlunkban. Az életkorra vonatkozó francia szó továbbra is kor, ami a Dozer egy másik fontos jellemzőjéhez vezet.

Az azonos nevű tulajdonságokat nem kell megadni a leképezés XML-fájljában. A dózer automatikusan leképezi az összes azonos tulajdonságú mezőt a forrásobjektumból a célobjektumba.

Ezután elhelyezzük egyéni XML fájlunkat az osztályútvonalon, közvetlenül a src mappába. Azonban bárhová helyezzük az osztályútvonalra, a Dozer az egész osztályterületen keresi a megadott fájlt.

Hozzunk létre egy segítő módszert, amellyel feltérképező fájlokat adhatunk hozzá térképező:

public void configureMapper (String ... mappingFileUrls) {mapper.setMappingFiles (Arrays.asList (mappingFileUrls)); }

Most teszteljük a kódot:

@Test public void givenSrcAndDestWithDifferentFieldNamesWithCustomMapper_ whenMaps_thenCorrect () {configureMapper ("dozer_mapping.xml"); Personne frenchAppPerson = new Personne ("Sylvester Stallone", "Rambo", 70); Person englishAppPerson = mapper.map (franciaAppPerson, Személy.osztály); assertEquals (magyarAppPerson.getName (), frenchAppPerson.getNom ()); assertEquals (magyarAppPerson.getNickname (), frenchAppPerson.getSurnom ()); assertEquals (angolAppPerson.getAge (), frenchAppPerson.getAge ()); }

Amint a teszt mutatja, DozerBeanMapper elfogadja az egyéni XML leképezési fájlok listáját, és eldönti, hogy mikor kell futás közben használni.

Feltéve, hogy most kezdjük el visszafejteni ezeket az adatobjektumokat az angol és a francia alkalmazás között. Nem kell új leképezést létrehoznunk az XML fájlban, A dózer elég okos ahhoz, hogy az objektumokat mindkét irányban csak egy leképezési konfigurációval tudja feltérképezni:

@Test public void givenSrcAndDestWithDifferentFieldNamesWithCustomMapper_ whenMapsBidirectionally_thenCorrect () {configureMapper ("dozer_mapping.xml"); Person englishAppPerson = new Person ("Dwayne Johnson", "The Rock", 44); Personne frenchAppPerson = mapper.map (angolAppPerson, Personne.class); assertEquals (franciaAppPerson.getNom (), angolAppPerson.getName ()); assertEquals (frenchAppPerson.getSurnom (), angolAppPerson.getNickname ()); assertEquals (franciaAppPerson.getAge (), angolAppPerson.getAge ()); }

Tehát ez a példa teszt a Dozer egy másik jellemzőjét használja - azt a tényt a dózer térképező motor kétirányú, tehát ha a célobjektumot a forrásobjektumhoz akarjuk térképezni, akkor nem kell újabb osztályleképezést adnunk az XML fájlhoz.

Betölthetünk egy egyedi leképezési fájlt az osztályútvonalon kívülről is, ha szükséges, használja a “fájl:”Előtag az erőforrás nevében.

Windows környezetben (például az alábbi teszten) természetesen a Windows specifikus fájlszintaxisát fogjuk használni.

Egy Linux dobozon a fájlt a (z) alatt tárolhatjuk /itthon és akkor:

configureMapper ("fájl: /home/dozer_mapping.xml");

És Mac OS rendszeren:

configureMapper ("fájl: /Users/me/dozer_mapping.xml");

Ha az egységteszteket a github projektből futtatja (amire szüksége van), akkor a leképezési fájlt átmásolhatja a megfelelő helyre, és módosíthatja configureMapper módszer.

A leképezési fájl a GitHub projekt teszt / források mappájában érhető el:

@Test public void givenMappingFileOutsideClasspath_whenMaps_thenCorrect () {configureMapper ("file: E: \ dozer_mapping.xml"); Person englishAppPerson = new Person ("Marshall Bruce Mathers III", "Eminem", 43); Personne frenchAppPerson = mapper.map (angolAppPerson, Personne.class); assertEquals (franciaAppPerson.getNom (), angolAppPerson.getName ()); assertEquals (frenchAppPerson.getSurnom (), angolAppPerson.getNickname ()); assertEquals (franciaAppPerson.getAge (), angolAppPerson.getAge ()); }

6. Helyettesítő karakterek és további XML-testreszabás

Hozzunk létre egy második egyedi leképezési fájlt dozer_mapping2.xml:

   com.baeldung.dozer.Personne com.baeldung.dozer.Person nom név   surnom becenév

Figyelje meg, hogy hozzáadtunk egy attribútumot helyettesítő karakter hoz elem, amely korábban nem volt ott.

Alapértelmezés szerint, helyettesítő karakter van igaz. Azt mondja a Dozer motornak, hogy azt akarjuk, hogy a forrásobjektum összes mezője a megfelelő célmezőkhöz legyen hozzárendelve.

Amikor beállítottuk hamis, azt mondjuk a Dozer-nek, hogy csak azokat a mezőket térképezze fel, amelyeket kifejezetten meghatároztunk az XML-ben.

Tehát a fenti konfigurációban csak két mezőt akarunk feltérképezni, elhagyva kor:

@Test public void givenSrcAndDest_whenMapsOnlySpecifiedFields_thenCorrect () {configureMapper ("dozer_mapping2.xml"); Person englishAppPerson = new Person ("Shawn Corey Carter", "Jay Z", 46); Personne frenchAppPerson = mapper.map (angolAppPerson, Personne.class); assertEquals (franciaAppPerson.getNom (), angolAppPerson.getName ()); assertEquals (frenchAppPerson.getSurnom (), englishAppPerson.getNickname ()); assertEquals (frenchAppPerson.getAge (), 0); }

Amint azt az utolsó állításban láthatjuk, a cél kor mező maradt 0.

7. Egyéni hozzárendelés kommentárokkal

Egyszerű feltérképezési eseteknél és olyan eseteknél, amikor írási hozzáféréssel is rendelkezünk a térképezni kívánt adatobjektumokhoz, nem biztos, hogy XML leképezést kell használnunk.

A különböző nevű mezők annotációkkal történő leképezése nagyon egyszerű, és sokkal kevesebb kódot kell írnunk, mint az XML leképezéskor, de csak egyszerű esetekben tudunk segíteni.

Replikáljuk az adatobjektumainkat Személy2.java és Personne2.java a mezők megváltoztatása nélkül.

Ennek megvalósításához csak @ kell hozzáadnunkmapper („destinationFieldName”) kommentár a getter módszerek a forrásobjektumban. Mint például:

@Mapping ("név") public String getNom () {return nom; } @Mapping ("becenév") public String getSurnom () {return surnom; }

Ezúttal kezeljük Personne2 forrásként, de ez nem számít a kétirányú természet a dózer motor.

Most, hogy az összes XML-hez kapcsolódó kódot levesszük, a tesztkódunk rövidebb:

@Test public void givenAnnotatedSrcFields_whenMapsToRightDestField_thenCorrect () {Person2 englishAppPerson = new Person2 ("Jean-Claude Van Damme", "JCVD", 55); Personne2 frenchAppPerson = mapper.map (angolAppPerson, Personne2.osztály); assertEquals (franciaAppPerson.getNom (), angolAppPerson.getName ()); assertEquals (frenchAppPerson.getSurnom (), englishAppPerson.getNickname ()); assertEquals (franciaAppPerson.getAge (), angolAppPerson.getAge ()); }

Tesztelhetjük a kétirányúságot is:

@Test public void givenAnnotatedSrcFields_whenMapsToRightDestFieldBidirectionally_ thenCorrect () {Personne2 frenchAppPerson = new Personne2 ("Jason Statham", "transzporter", 49); Person2 englishAppPerson = mapper.map (franciaAppPerson, Person2.osztály); assertEquals (magyarAppPerson.getName (), frenchAppPerson.getNom ()); assertEquals (magyarAppPerson.getNickname (), frenchAppPerson.getSurnom ()); assertEquals (angolAppPerson.getAge (), frenchAppPerson.getAge ()); }

8. Egyéni API-hozzárendelés

Korábbi példáinkban, ahol egy francia alkalmazás adatobjektumait eltávolítjuk, XML-t és annotációkat használtunk a leképezés testreszabásához.

A Dozerben elérhető másik alternatíva, hasonlóan az annotációs leképezéshez, az API hozzárendelés. Hasonlóak, mert kiküszöböljük az XML konfigurációt és szigorúan Java kódot használunk.

Ebben az esetben használjuk BeanMappingBuilder osztály, amelyet a legegyszerűbb esetben definiálunk:

BeanMappingBuilder builder = new BeanMappingBuilder () {@ Felülbírálja a védett void configure () {mapping (Person.class, Personne.class) .fields ("név", "nom") .fields ("becenév", "surnom"); }};

Mint láthatjuk, van egy elvont módszerünk, Beállítás(), amelyet felül kell írnunk a konfigurációink meghatározásához. Akkor, akárcsak a miénk címkék XML-ben, annyit definiálunk TypeMappingBuilders ahogy megköveteljük.

Ezek az építők megmondják a Dozer-nek, hogy mely forrásból a célmezőbe térképezzük fel. Ezután elhaladunk a BeanMappingBuilder nak nek DozerBeanMapper ahogy mi tennénk, az XML leképezési fájl csak más API-val:

@Test public void givenApiMapper_whenMaps_thenCorrect () {mapper.addMapping (építő); Personne frenchAppPerson = new Personne ("Sylvester Stallone", "Rambo", 70); Person englishAppPerson = mapper.map (franciaAppPerson, Személy.osztály); assertEquals (magyarAppPerson.getName (), frenchAppPerson.getNom ()); assertEquals (magyarAppPerson.getNickname (), frenchAppPerson.getSurnom ()); assertEquals (angolAppPerson.getAge (), frenchAppPerson.getAge ()); }

A leképező API kétirányú is:

@Test public void givenApiMapper_whenMapsBidirectionally_thenCorrect () {mapper.addMapping (készítő); Person englishAppPerson = new Person ("Sylvester Stallone", "Rambo", 70); Personne frenchAppPerson = mapper.map (magyarAppPerson, Personne.class); assertEquals (franciaAppPerson.getNom (), angolAppPerson.getName ()); assertEquals (frenchAppPerson.getSurnom (), englishAppPerson.getNickname ()); assertEquals (franciaAppPerson.getAge (), angolAppPerson.getAge ()); }

Vagy választhatjuk, hogy csak kifejezetten megadott mezőket jelenítünk meg ezzel az építőkonfigurációval:

BeanMappingBuilder builderMinusAge = new BeanMappingBuilder () {@Orride védett void configure () {mapping (Person.class, Personne.class) .fields ("név", "nom") .fields ("becenév", "surnom"). Kizár ("kor"); }};

és a mi életkor == 0 teszt visszatért:

@Test public void givenApiMapper_whenMapsOnlySpecifiedFields_thenCorrect () {mapper.addMapping (builderMinusAge); Person englishAppPerson = new Person ("Sylvester Stallone", "Rambo", 70); Personne frenchAppPerson = mapper.map (magyarAppPerson, Personne.class); assertEquals (franciaAppPerson.getNom (), angolAppPerson.getName ()); assertEquals (frenchAppPerson.getSurnom (), englishAppPerson.getNickname ()); assertEquals (frenchAppPerson.getAge (), 0); }

9. Egyedi átalakítók

Egy másik forgatókönyv, amellyel a térképezés során szembesülhetünk, az az, ahol szeretnénk két objektum között végezzen egyedi leképezést.

Megvizsgáltuk azokat a forgatókönyveket, ahol a forrás és a cél mezőnevek eltérnek, mint a franciáknál Personne tárgy. Ez a szakasz egy másik problémát old meg.

Mi van, ha egy olyan adatobjektum, amelyet eltávolítunk, egy dátum és idő mezőt képvisel, például a hosszú vagy Unix idő, így:

1182882159000

De a saját egyenértékű adatobjektumunk ugyanazt a dátum- és időmezőt és értéket képviseli ebben az ISO formátumban, például a Húr:

2007-06-26T21: 22: 39Z

Az alapértelmezett átalakító egyszerűen leképezi a hosszú értéket a-ra Húr így:

"1182882159000"

Ez mindenképpen hibát jelentene az alkalmazásunkban. Tehát hogyan oldjuk meg ezt? Azzal oldjuk meg konfigurációs blokk hozzáadása a leképező XML fájlban és saját átalakítónk megadása.

Először ismételjük meg a távoli alkalmazásokat Személy DTO egy név, majd a születés dátuma és ideje, dtob terület:

public class Personne3 {privát karakterlánc neve; magán hosszú dtob; public Personne3 (karakterlánc neve, hosszú dtob) {szuper (); ez.név = név; ez.dtob = dtob; } // szokásos mérőeszközök és beállítók}

és itt van a sajátunk:

public class Személy3 {privát String név; privát húr dtob; public Person3 (karakterlánc neve, String dtob) {szuper (); ez.név = név; ez.dtob = dtob; } // szokásos mérőeszközök és beállítók}

Figyelje meg a típus különbségét dtob a forrás és a cél DTO-kban.

Hozzuk létre a sajátunkat is CustomConverter átadni a dózernek a leképező XML-ben:

public class A MyCustomConvertor megvalósítja a CustomConverter {@Orride public Object convert (Object dest, Object source, class arg2, class arg3) {if (source == null) return null; if (Personne3 forrás példánya) {Personne3 személy = (Personne3) forrás; Dátum dátuma = új Dátum (person.getDtob ()); DateFormat formátum = new SimpleDateFormat ("éééé-HH-nn.'H'HH: mm: ss'Z '"); Karakterlánc isoDate = format.format (dátum); return new Person3 (person.getName (), isoDate); } else if (Person3 forrás példánya) {Person3 személy = (Személy3) forrás; DateFormat formátum = new SimpleDateFormat ("éééé-HH-nn.'H'HH: mm: ss'Z '"); Dátum dátum = format.parse (person.getDtob ()); hosszú időbélyeg = date.getTime (); return new Personne3 (person.getName (), időbélyeg); }}}

Csak felül kell írnunk alakítani() módszerrel térjen vissza, bárhová akarunk visszatérni. A forrás- és a célobjektumokkal, valamint osztálytípusaikkal élünk.

Figyeljük meg, hogyan gondoztuk a kétirányúságot azzal, hogy feltételezzük, hogy a forrás lehet a feltérképezett két osztály bármelyike.

Az egyértelműség érdekében létrehozunk egy új térképfájlt, dozer_custom_convertor.xml:

     com.baeldung.dozer.Personne3 com.baeldung.dozer.Person3 

Ez a normál leképezési fájl, amelyet az előző szakaszokban láthattunk, csak a-t adtuk hozzá blokk, amelyen belül annyi egyedi átalakítót határozhatunk meg, amennyire szükségünk van a megfelelő forrás- és céladat-osztályokkal.

Teszteljük az új CustomConverter kód:

@Test public void givenSrcAndDestWithDifferentFieldTypes_whenAbleToCustomConvert_ thenCorrect () {configureMapper ("dozer_custom_convertor.xml"); String dateTime = "2007-06-26T21: 22: 39Z"; hosszú időbélyeg = új Hosszú ("1182882159000"); Person3 person = new Person3 ("Rich", dateTime); Personne3 person0 = mapper.map (személy, Personne3 osztály); assertEquals (időbélyeg, személy0.getDtob ()); }

Azt is tesztelhetjük, hogy kétirányú-e:

@Test public void givenSrcAndDestWithDifferentFieldTypes_ whenAbleToCustomConvertBidirectionally_thenCorrect () {configureMapper ("dozer_custom_convertor.xml"); String dateTime = "2007-06-26T21: 22: 39Z"; hosszú időbélyeg = új Hosszú ("1182882159000"); Personne3 person = new Personne3 ("Rich", időbélyeg); Person3 person0 = mapper.map (személy, Személy3.osztály); assertEquals (dátumTime, személy0.getDtob ()); }

10. Következtetés

Ebben az oktatóanyagban van bemutatta a Dozer Mapping könyvtár legtöbb alapját és hogyan kell használni az alkalmazásainkban.

Ezen példák és kódrészletek teljes megvalósítása megtalálható a Dozer github projektben.


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