Mapovanie zbierok pomocou MapStruct

1. Prehľad

V tomto tutoriále sa pozrieme na to, ako mapovať zbierky objektov pomocou MapStruct.

Pretože tento článok predpokladá základné znalosti o MapStruct, mali by si začiatočníci najskôr prečítať nášho rýchleho sprievodcu MapStructom.

2. Mapovanie zbierok

Všeobecne, mapovacie zbierky s MapStruct fungujú rovnako ako pri jednoduchých typoch.

V zásade musíme vytvoriť jednoduché rozhranie alebo abstraktnú triedu a deklarovať mapovacie metódy. Na základe našich vyhlásení vygeneruje MapStruct mapovací kód automaticky. Typicky vygenerovaný kód sa prekrúti cez zdrojovú kolekciu, prevedie každý prvok na cieľový typ a každý z nich zahrnie do cieľovej kolekcie.

Pozrime sa na jednoduchý príklad.

2.1. Mapovacie zoznamy

Najprv pre náš príklad zvážime jednoduchý POJO ako zdroj mapovania pre náš mapovač:

verejná trieda Zamestnanec {private String meno; private String priezvisko; // konštruktor, getri a nastavovatelia} 

Cieľom bude jednoduchý DTO:

verejná trieda EmployeeDTO {private String firstName; private String priezvisko; // zakladatelia a zakladatelia}

Ďalej definujeme náš mapovač:

@Mapper verejné rozhranie EmployeeMapper {Zoznam máp (Zoznam zamestnancov); } 

Na záver sa pozrime na kód MapStruct vygenerovaný z nášho EmployeeMapper rozhranie:

verejná trieda EmployeeMapperImpl implementuje EmployeeMapper {@Override mapa verejného zoznamu (zoznam zamestnancov) {if (zamestnanci == null) {return null; } Zoznam zoznam = nový ArrayList (zamestnanci.size ()); pre (Zamestnanec zamestnanec: zamestnanci) {list.add (employeeToEmployeeDTO (zamestnanec)); } návratový zoznam; } chránený EmployeeDTO employeeToEmployeeDTO (zamestnanec zamestnanca) {if (employee == null) {return null; } EmployeeDTO employeeDTO = nový EmployeeDTO (); employeeDTO.setFirstName (employee.getFirstName ()); employeeDTO.setLastName (employee.getLastName ()); návrat zamestnanca DTO; }} 

Je potrebné si uvedomiť dôležitú vec. Konkrétne MapStruct pre nás generoval mapovanie automaticky Zamestnanec do EmployeeDTO.

Existujú prípady, keď to nie je možné. Povedzme napríklad, že chceme zmapovať naše Zamestnanec nasledujúci model:

verejná trieda EmployeeFullNameDTO {private String fullName; // getter a setter}

V tomto prípade, ak deklarujeme iba metódu mapovania z a Zoznam z Zamestnanec do a Zoznam z EmployeeFullNameDTO dostaneme chybu alebo upozornenie pri kompilácii ako:

Varovanie: (11, 31) java: nezmapovaná cieľová vlastnosť: „fullName“. Mapovanie z prvku kolekcie „com.baeldung.mapstruct.mappingCollections.model.Employee zamestnanca“ na „com.baeldung.mapstruct.mappingCollections.dto.EmployeeFullNameDTO employeeFullNameDTO“.

V podstate to znamená MapStruct pre nás nemohol vygenerovať mapovanie automatickyv tomto prípade. Preto musíme definovať manuálne mapovanie medzi Zamestnanec a EmployeeFullNameDTO.

Vzhľadom na tieto body to definujeme manuálne:

@Mapper verejné rozhranie EmployeeFullNameMapper {Mapa zoznamu (Zoznam zamestnancov); predvolená mapa EmployeeFullNameDTO (zamestnanec zamestnanca) {EmployeeFullNameDTO employeeInfoDTO = nový EmployeeFullNameDTO (); employeeInfoDTO.setFullName (employee.getFirstName () + "" + employee.getLastName ()); vrátiť zamestnancaInfoDTO; }}

Generovaný kód použije nami definovanú metódu na mapovanie prvkov zdroja Zoznam k cieľu Zoznam.

To platí aj všeobecne. Ak sme definovali metódu, ktorá mapuje typ zdrojového prvku na typ cieľového prvku, použije ho MapStruct.

2.2. Mapovacie sady a mapy

Mapovacie súpravy s MapStruct fungujú rovnako ako so zoznamami. Povedzme napríklad, že chceme zmapovať a Nastaviť z Zamestnanec inštancie do a Nastaviť z EmployeeDTO inštancie.

Rovnako ako predtým potrebujeme mapovač:

@Mapper verejné rozhranie EmployeeMapper {Nastaviť mapu (Nastaviť zamestnancov); }

A MapStruct vygeneruje príslušný kód:

verejná trieda EmployeeMapperImpl implementuje EmployeeMapper {@Override verejná sada Mapa (sada zamestnancov) {if (zamestnanci == null) {návrat null; } Set set = new HashSet (Math.max ((int) (Zaměstnanci.size () / .75f) + 1, 16)); pre (Zamestnanec zamestnanec: zamestnanci) {set.add (employeeToEmployeeDTO (zamestnanec)); } návratová sada; } chránený EmployeeDTO employeeToEmployeeDTO (zamestnanec zamestnanca) {if (employee == null) {return null; } EmployeeDTO employeeDTO = nový EmployeeDTO (); employeeDTO.setFirstName (employee.getFirstName ()); employeeDTO.setLastName (employee.getLastName ()); návrat zamestnanca DTO; }}

To isté platí pre mapy. Uvažujme, že chceme zmapovať a Mapa do a Mapa.

Potom môžeme postupovať rovnako ako predtým:

@Mapper verejné rozhranie EmployeeMapper {Map map (Map idEmployeeMap); }

A MapStruct robí svoju prácu:

verejná trieda EmployeeMapperImpl implementuje EmployeeMapper {@Override verejná mapa mapy (mapa idEmployeeMap) {if (idEmployeeMap == null) {return null; } Mapa mapy = nový HashMap (Math.max ((int) (idEmployeeMap.size () / .75f) + 1,16)); for (java.util.Map.Entry entry: idEmployeeMap.entrySet ()) {String key = entry.getKey (); EmployeeDTO value = employeeToEmployeeDTO (entry.getValue ()); map.put (kľúč, hodnota); } spiatočná mapa; } chránený EmployeeDTO employeeToEmployeeDTO (zamestnanec zamestnanca) {if (employee == null) {return null; } EmployeeDTO employeeDTO = nový EmployeeDTO (); employeeDTO.setFirstName (employee.getFirstName ()); employeeDTO.setLastName (employee.getLastName ()); návrat zamestnanca DTO; }}

3. Stratégie mapovania zbierok

Často musíme mapovať dátové typy, ktoré majú vzťah rodič - dieťa. Spravidla máme dátový typ (rodič) majúci ako pole a Zbierka iného typu údajov (dieťa).

V takýchto prípadoch MapStruct ponúka spôsob, ako zvoliť, ako nastaviť alebo pridať deti do nadradeného typu. Najmä @Mapper anotácia má a collectionMappingStrategy atribút, ktorým môže byť ACCESSOR_ONLY, SETTER_PREFERRED, ADDER_PREFERRED alebo TARGET_IMMUTABLE.

Všetky tieto hodnoty odkazujú na spôsob, akým by mali byť deti nastavené alebo pridané k nadradenému typu. Predvolená hodnota je ACCESSOR_ONLY, čo znamená, že na nastavenie súboru možno použiť iba prístupových používateľov Zbierka detí.

Táto možnosť sa hodí, keď nastavovač pre Zbierka pole nie je k dispozícii, ale máme sčítač. Ďalším prípadom, keď je to užitočné, je keď Zbierka je nemenná na rodičovskom type. Zvyčajne sa s týmito prípadmi stretávame pri generovaných cieľových typoch.

3.1. ACCESSOR_ONLY Stratégia mapovania zbierok

Zoberme si príklad, aby sme lepšie pochopili, ako to funguje.

Pre náš príklad vytvorme a Spoločnosť trieda ako náš zdroj mapovania:

verejná trieda Spoločnosť {zamestnanci súkromného zoznamu; // getter a setter}

Cieľom pre naše mapovanie bude jednoduchý DTO:

verejná trieda CompanyDTO {zamestnanci súkromného zoznamu; public List getEmployees () {vrátiť zamestnancov; } public void setEmployees (zoznam zamestnancov) {this.employees = zamestnanci; } public void addEmployee (EmployeeDTO employeeDTO) {if (zamestnanci == null) {zamestnanci = novy ArrayList (); } zamestnanci.add (employeeDTO); }}

Všimnite si, že máme oba nastavovače, set Zamestnanci, a sčítačka, addEmployee, k dispozícii. Tiež za sčítač zodpovedáme za inicializáciu zberu.

Teraz povedzme, že chceme zmapovať a Spoločnosť do a SpoločnosťDTO. Potom, ako predtým, potrebujeme mapovač:

@Mapper (uses = EmployeeMapper.class) verejné rozhranie CompanyMapper {mapa CompanyDTO (spoločnosť spoločnosti); }

Všimnite si, že sme znovu použili EmployeeMapper a predvolené collectionMappingStrategy.

Poďme sa teraz pozrieť na vygenerovaný kód MapStruct:

verejná trieda CompanyMapperImpl implementuje CompanyMapper {private final EmployeeMapper employeeMapper = Mappers.getMapper (EmployeeMapper.class); @ Override public CompanyDTO map (Company company) {if (company == null) {return null; } CompanyDTO companyDTO = new CompanyDTO (); companyDTO.setEmployees (employeeMapper.map (company.getEmployees ())); návratová spoločnosť DTO; }}

Ako môžete vidieť, MapStruct používa nastavovač, setZamestnanci, nastaviť Zoznam z EmployeeDTO inštancie. Stáva sa to preto, lebo tu používame predvolené nastavenie collectionMappingStrategy,ACCESSOR_ONLY.

MapStruct tiež našiel metódu mapujúcu a Zoznam do a Zoznam v EmployeeMapper a znova to použil.

3.2. ADDER_PREFERRED Stratégia mapovania zbierok

Na rozdiel od toho zvážime, čo sme použili ADDER_PREFERRED ako collectionMappingStrategy:

@Mapper (collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, uses = EmployeeMapper.class) verejné rozhranie CompanyMapperAdderPreferred {mapa CompanyDTO (spoločnosť spoločnosti); }

Opäť chceme znovu použiť EmployeeMapper. Avšak musíme výslovne pridať metódu, ktorá dokáže previesť jeden Zamestnanec do an EmployeeDTO najprv:

@Mapper verejné rozhranie EmployeeMapper {mapa EmployeeDTO (zamestnanec zamestnanca); Zoznamová mapa (Zoznam zamestnancov); Nastaviť mapu (Nastaviť zamestnancov); Mapová mapa (Map idEmployeeMap); }

Je to tak preto, že MapStruct použije na pridanie sčítačku EmployeeDTO inštancie k cieľu SpoločnosťDTO napríklad jeden po druhom:

public class CompanyMapperAdderPreferredImpl implementuje CompanyMapperAdderPreferred {private final EmployeeMapper employeeMapper = Mappers.getMapper (EmployeeMapper.class); @ Override public CompanyDTO map (Company company) {if (company == null) {return null; } CompanyDTO companyDTO = new CompanyDTO (); if (company.getEmployees ()! = null) {for (Employee employee: company.getEmployees ()) {companyDTO.addEmployee (employeeMapper.map (employee))); }} vrátiť spoločnosťDTO; }}

Ak by sčítačka nebola k dispozícii, bol by použitý setter.

Kompletný popis všetkých stratégií mapovania kolekcií nájdeme v referenčnej dokumentácii MapStruct.

4. Typy implementácie pre zber cieľov

MapStruct podporuje rozhrania kolekcií ako cieľové typy metód mapovania.

V tomto prípade sa v generovanom kóde používajú niektoré predvolené implementácie. Napríklad predvolená implementácia pre Zoznam je ArrayList ako je možné poznamenať z našich príkladov vyššie.

Kompletný zoznam rozhraní, ktoré MapStruct podporuje, a predvolené implementácie, ktoré používa pre každé rozhranie, nájdeme v referenčnej dokumentácii.

5. Záver

V tomto článku sme skúmali, ako mapovať zbierky pomocou MapStruct.

Najprv sme sa pozreli na to, ako môžeme mapovať rôzne typy zbierok. Potom sme videli, ako môžeme prispôsobiť mapovače vzťahov medzi rodičmi a deťmi pomocou stratégií mapovania zbierok.

Počas toho sme zvýraznili kľúčové body a veci, na ktoré treba pamätať pri mapovaní zbierok pomocou MapStruct.

Celý kód je ako obvykle k dispozícii na serveri GitHub.


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