Kortlægning af samlinger med MapStruct

1. Oversigt

I denne vejledning ser vi på, hvordan man kortlægger objektsamlinger ved hjælp af MapStruct.

Da denne artikel allerede antager en grundlæggende forståelse af MapStruct, bør begyndere tjekke vores hurtige guide til MapStruct først.

2. Kortlægning af samlinger

Generelt, kortlægning af samlinger med MapStruct fungerer på samme måde som for enkle typer.

Dybest set skal vi oprette en simpel grænseflade eller en abstrakt klasse og erklære kortlægningsmetoderne. Baseret på vores erklæringer genererer MapStruct kortlægningskoden automatisk. Typisk, den genererede kode vil løbe over kildesamlingen, konvertere hvert element til måltypen og inkludere hver af dem i målsamlingen.

Lad os se på et simpelt eksempel.

2.1. Kortlægningslister

Lad os først, for vores eksempel, overveje en simpel POJO som kortlægningskilde for vores kortlægger:

offentlig klassemedarbejder {privat streng fornavn; privat streng efternavn; // konstruktør, getters og setters} 

Målet er en simpel DTO:

offentlig klasse EmployeeDTO {private String firstName; privat streng efternavn; // getters og setters}

Lad os derefter definere vores kortlægger:

@Mapper offentlig grænseflade EmployeeMapper {Listekort (liste medarbejdere); } 

Lad os endelig se på koden MapStruct genereret fra vores Medarbejderkort grænseflade:

offentlig klasse EmployeeMapperImpl implementerer EmployeeMapper {@Override public List map (Liste medarbejdere) {if (medarbejdere == null) {return null; } Liste liste = ny ArrayList (medarbejdere.størrelse ()); for (Medarbejdermedarbejder: medarbejdere) {list.add (medarbejderTilarbejderDTO (medarbejder)); } returliste } beskyttet EmployeeDTO-medarbejderToEmployeeDTO (Medarbejdermedarbejder) {if (medarbejder == null) {return null; } EmployeeDTO-medarbejderDTO = ny EmployeeDTO (); medarbejderDTO.setFirstnavn (medarbejder.getFirstnavn ()); medarbejderDTO.setLastnavn (medarbejder.getLastnavn ()); tilbagevendende medarbejderDTO; }} 

Der er en vigtig ting at bemærke. Specifikt MapStruct genereres automatisk for os kortlægningen fra Medarbejder til MedarbejderDTO.

Der er tilfælde, hvor dette ikke er muligt. Lad os for eksempel sige, at vi vil kortlægge vores Medarbejder model til følgende model:

offentlig klasse EmployeeFullNameDTO {private String fullName; // getter og setter}

I dette tilfælde, hvis vi bare erklærer kortlægningsmetoden fra en Liste af Medarbejder til en Liste af MedarbejderFuldt navnDTO Vi modtager en kompileringstidsfejl eller en advarsel som:

Advarsel: (11, 31) java: Ikke-kortlagt målegenskab: "fullName". Kortlægning fra indsamlingselementet "com.baeldung.mapstruct.mappingCollections.model.Employee employee" til "com.baeldung.mapstruct.mappingCollections.dto.EmployeeFullNameDTO employeeFullNameDTO".

Dybest set betyder det det MapStruct kunne ikke generere kortlægningen automatisk for osI dette tilfælde. Derfor er vi nødt til manuelt at definere kortlægningen mellem Medarbejder og MedarbejderFuldt navnDTO.

I betragtning af disse punkter, lad os manuelt definere det:

@Mapper offentlig grænseflade EmployeeFullNameMapper {Listekort (liste medarbejdere); standard EmployeeFullNameDTO-kort (Medarbejdermedarbejder) {EmployeeFullNameDTO medarbejderInfoDTO = ny EmployeeFullNameDTO (); medarbejderInfoDTO.setFullName (medarbejder.getFirstnavn () + "" + medarbejder.getLastnavn ()); returnere medarbejderInfoDTO; }}

Den genererede kode bruger den metode, vi definerede til at kortlægge kildens elementer Liste til målet Liste.

Dette gælder også generelt. Hvis vi har defineret en metode, der kortlægger kildeelementtypen til målelementtypen, vil MapStruct bruge den.

2.2. Kortlægningssæt og kort

Kortlægningssæt med MapStruct fungerer på samme måde som med lister. Lad os for eksempel sige, at vi vil kortlægge en Sæt af Medarbejder tilfælde til en Sæt af MedarbejderDTO tilfælde.

Som før har vi brug for en kortlægger:

@Mapper offentlig grænseflade EmployeeMapper {Set map (Set workers); }

Og MapStruct genererer den relevante kode:

offentlig klasse EmployeeMapperImpl implementerer EmployeeMapper {@Override public Set kort (sæt medarbejdere) {if (medarbejdere == null) {return null; } Sæt sæt = nyt HashSet (Math.max ((int) (medarbejderstørrelse () / .75f) + 1, 16)); for (Medarbejdermedarbejder: medarbejdere) {set.add (medarbejderTilmæglerDTO (medarbejder)); } returner sæt; } beskyttet EmployeeDTO-medarbejderToEmployeeDTO (Medarbejdermedarbejder) {if (medarbejder == null) {return null; } EmployeeDTO-medarbejderDTO = ny EmployeeDTO (); medarbejderDTO.setFirstnavn (medarbejder.getFirstnavn ()); medarbejderDTO.setLastnavn (medarbejder.getLastnavn ()); tilbagevendende medarbejderDTO; }}

Det samme gælder for kort. Lad os overveje, at vi vil kortlægge en Kort til en Kort.

Derefter kan vi følge de samme trin som før:

@Mapper offentlig grænseflade EmployeeMapper {Map map (Map idEmployeeMap); }

Og MapStruct gør sit job:

offentlig klasse EmployeeMapperImpl implementerer EmployeeMapper {@Override public Map map (Map idEmployeeMap) {if (idEmployeeMap == null) {return null; } Kortkort = nyt HashMap (Math.max ((int) (idEmployeeMap.size () / .75f) + 1, 16)); for (java.util.Map.Entry post: idEmployeeMap.entrySet ()) {String key = entry.getKey (); EmployeeDTO værdi = medarbejderToEmployeeDTO (entry.getValue ()); map.put (nøgle, værdi); } returner kort; } beskyttet EmployeeDTO-medarbejderToEmployeeDTO (Medarbejdermedarbejder) {if (medarbejder == null) {return null; } EmployeeDTO-medarbejderDTO = ny EmployeeDTO (); medarbejderDTO.setFirstnavn (medarbejder.getFirstnavn ()); medarbejderDTO.setLastnavn (medarbejder.getLastnavn ()); tilbagevendende medarbejderDTO; }}

3. Strategier for kortlægning af samlinger

Ofte skal vi kortlægge datatyper, der har et forhold mellem forældre og barn. Vi har typisk en datatype (forælder), der har som felt a Kollektion af en anden datatype (barn).

I sådanne tilfælde MapStruct tilbyder en måde at vælge, hvordan man indstiller eller tilføjer børnene til forældretypen. Især den @Mapper kommentar har en collectionMappingStrategy attribut, som kan være ACCESSOR_ONLY, SETTER_ FORETRUKT, ADDER_ FORETRUKT eller TARGET_IMMUTABLE.

Alle disse værdier henviser til den måde, børnene skal indstilles på eller føjes til forældretypen. Standardværdien er ACCESSOR_ONLY, hvilket betyder, at kun accessors kan bruges til at indstille Kollektion af børn.

Denne mulighed er praktisk, når setter til Kollektion felt er ikke tilgængeligt, men vi har en adder. Et andet tilfælde, hvor dette er nyttigt, er når Kollektion er uforanderlig på den overordnede type. Normalt støder vi på disse tilfælde i genererede måltyper.

3.1. ACCESSOR_ONLY Samlingskortlægningsstrategi

Lad os tage et eksempel for bedre at forstå, hvordan dette fungerer.

Lad os for vores eksempel oprette en Selskab klasse som vores kortlægningskilde:

offentlig klasse Company {private List medarbejdere; // getter og setter}

Og målet for vores kortlægning vil være en simpel DTO:

public class CompanyDTO {private List medarbejdere; offentlig liste getEmployees () {return medarbejdere; } public void setMedarbejdere (liste medarbejdere) {dette.medarbejdere = medarbejdere; } offentlig ugyldig addEmployee (EmployeeDTO medarbejderDTO) {if (medarbejdere == null) {medarbejdere = ny ArrayList (); } medarbejdere.add (medarbejderDTO); }}

Bemærk, at vi har begge setter, sætMedarbejdere, og huggeren, tilføj medarbejder, ledig. Også, for huggeren er vi ansvarlige for initialisering af indsamling.

Lad os sige, at vi vil kortlægge en Selskab til en CompanyDTO. Så som før har vi brug for en kortlægger:

@Mapper (bruger = EmployeeMapper.class) offentlig grænseflade CompanyMapper {CompanyDTO-kort (Company company); }

Bemærk, at vi genbrugte Medarbejderkort og standardindstillingen collectionMappingStrategy.

Lad os nu se på den genererede kode MapStruct:

offentlig klasse CompanyMapperImpl implementerer CompanyMapper {privat endelig EmployeeMapper medarbejderMapper = Mappers.getMapper (EmployeeMapper.class); @Override public CompanyDTO map (Company company) {if (company == null) {return null; } CompanyDTO companyDTO = ny CompanyDTO (); companyDTO.setEmployees (medarbejderMapper.map (company.getEmployees ())); returvirksomhedDTO; }}

Som kan ses, MapStruct bruger setter, sætMedarbejdere, for at indstille Liste af MedarbejderDTO tilfælde. Dette sker, fordi her bruger vi standard collectionMappingStrategy,ACCESSOR_ONLY.

MapStruct fandt også en kortlægning af en metode Liste til en Liste i Medarbejderkort og genbrugt det.

3.2. ADDER_ FORETRUKT Samlingskortlægningsstrategi

Lad os derimod overveje, at vi brugte ADDER_ FORETRUKT som collectionMappingStrategy:

@Mapper (collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, bruger = EmployeeMapper.class) offentlig grænseflade CompanyMapperAdderPreferred {CompanyDTO-kort (Company company); }

Igen vil vi genbruge Medarbejderkort. Imidlertid, Vi skal udtrykkeligt tilføje en metode, der kan konvertere en enkelt Medarbejder til en MedarbejderDTO først:

@Mapper offentlig grænseflade EmployeeMapper {EmployeeDTO-kort (medarbejdermedarbejder); Listekort (liste medarbejdere); Sæt kort (sæt medarbejdere); Kortkort (Map idEmployeeMap); }

Dette skyldes, at MapStruct bruger adderen til at tilføje MedarbejderDTO forekomster til målet CompanyDTO eksempel en efter en:

offentlig klasse CompanyMapperAdderPreferredImpl implementerer CompanyMapperAdderPreferred {private final EmployeeMapper medarbejderMapper = Mappers.getMapper (EmployeeMapper.class); @Override public CompanyDTO map (Company company) {if (company == null) {return null; } CompanyDTO companyDTO = ny CompanyDTO (); hvis (company.getEmployees ()! = null) {for (Medarbejdermedarbejder: company.getEmployees ()) {companyDTO.addEmployee (medarbejderMapper.map (ansat)) }} returner selskabDTO; }}

Hvis addereren ikke var tilgængelig, ville setteren have været brugt.

Vi kan finde en komplet beskrivelse af alle strategierne til kortlægning af samlinger i MapStruct's referencedokumentation.

4. Implementeringstyper til målindsamling

MapStruct understøtter samlingsgrænseflader som måltyper til kortlægningsmetoder.

I dette tilfælde bruges nogle standardimplementeringer i den genererede kode. For eksempel standardimplementeringen for Liste er ArrayList som det kan bemærkes fra vores eksempler ovenfor.

Vi kan finde den komplette liste over grænseflader, som MapStruct understøtter, og de standardimplementeringer, den bruger til hver grænseflade, i referencedokumentationen.

5. Konklusion

I denne artikel har vi undersøgt, hvordan man kortlægger samlinger ved hjælp af MapStruct.

Først har vi set på, hvordan vi kan kortlægge forskellige typer samlinger. Derefter så vi, hvordan vi kan tilpasse kortlægning af forældre-barn-forhold ved hjælp af strategier til kortlægning af samlinger.

Undervejs fremhævede vi de vigtigste punkter og ting, du skal huske på, når vi kortlægger samlinger ved hjælp af MapStruct.

Som sædvanlig er den komplette kode tilgængelig på GitHub.


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