Udførelse af Java Mapping Frameworks

1. Introduktion

Oprettelse af store Java-applikationer sammensat af flere lag kræver brug af flere modeller som persistensmodel, domænemodel eller såkaldte DTO'er. Brug af flere modeller til forskellige applikationslag kræver, at vi giver en måde at kortlægge mellem bønner.

At gøre dette manuelt kan hurtigt oprette meget kedelpladekode og forbruge meget tid. Heldigvis for os er der flere objekter til kortlægning af objekter til Java.

I denne vejledning skal vi sammenligne ydeevnen for de mest populære Java-kortlægningsrammer.

2. Kortlægningsrammer

2.1. Dozer

Dozer er en kortlægningsramme, der bruger rekursion til at kopiere data fra et objekt til et andet. Rammen er ikke kun i stand til at kopiere egenskaber mellem bønnerne, men den kan også automatisk konvertere mellem forskellige typer.

For at bruge Dozer-rammen er vi nødt til at tilføje en sådan afhængighed til vores projekt:

 com.github.dozermapper dozer-core 6.5.0 

Flere oplysninger om brugen af ​​Dozer-rammen kan findes i denne artikel.

Dokumentationen af ​​rammen kan findes her.

2.2. Orika

Orika er en ramme til kortlægning af bønner til bønner, der rekursivt kopierer data fra et objekt til et andet.

Det generelle princip for Orikas arbejde ligner Dozer. Den største forskel mellem de to er, at Orika bruger bytecode-generation. Dette giver mulighed for at generere hurtigere kortlæggere med minimal overhead.

For at bruge detvi er nødt til at tilføje en sådan afhængighed til vores projekt:

 ma.glasnost.orika orika-core 1.5.4 

Mere detaljeret information om brugen af ​​Orika kan findes i denne artikel.

Den faktiske dokumentation af rammen kan findes her.

2.3. MapStruct

MapStruct er en kodegenerator, der automatisk genererer bønnekortklasser.

MapStruct har også muligheden for at konvertere mellem forskellige datatyper. Flere oplysninger om, hvordan du bruger det, kan findes i denne artikel.

For at tilføje MapStructtil vores projekt skal vi inkludere følgende afhængighed:

 org.mapstruct mapstruct 1.3.1.Final 

Dokumentationen af ​​rammen kan findes her.

2.4. ModelMapper

ModelMapper er en ramme, der har til formål at forenkle objektmapping ved at bestemme, hvordan objekter kortlægges til hinanden baseret på konventioner. Det giver typesikker og refactoring-sikker API.

Flere oplysninger om rammen kan findes i dokumentationen.

For at inkludere ModelMapper i vores projekt skal vi tilføje følgende afhængighed:

 org.modelmapper modelmapper 2.3.8 

2.5. JMapper

JMapper er kortlægningsrammen, der sigter mod at give en brugervenlig, højtydende kortlægning mellem Java Beans.

Rammen har til formål at anvende DRY-princippet ved hjælp af annotationer og relationel kortlægning.

Rammen tillader forskellige måder at konfigurere på: annotationsbaseret, XML eller API-baseret.

Flere oplysninger om rammen kan findes i dens dokumentation.

For at inkludere JMapper i vores projekt skal vi tilføje dens afhængighed:

 com.googlecode.jmapper-framework jmapper-core 1.6.1.CR2 

3. TestningModel

For at kunne teste kortlægning korrekt skal vi have kilde- og målmodeller. Vi har oprettet to testmodeller.

Den første er bare en simpel POJO med en Snor felt tillod dette os at sammenligne rammer i enklere tilfælde og kontrollere, om noget ændres, hvis vi bruger mere komplicerede bønner.

Den enkle kildemodel ser ud som nedenfor:

offentlig klasse SourceCode {Strengkode; // getter og setter}

Og dens destination er ret ens:

offentlig klasse DestinationCode {String code; // getter og setter}

Det virkelige eksempel på kilde bønner ser sådan ud:

offentlig klasse SourceOrder {private String orderFinishDate; privat PaymentType betalingType; privat rabat rabat; privat DeliveryData leveringData; privat brugerbestilling Bruger; privat liste bestilt Produkter; privat butikstilbudShop; privat int orderId; privat OrderStatus-status; privat LocalDate orderDate; // standard getters og setter}

Og målklassen ser ud som nedenfor:

public class Order {private User orderingUser; privat liste bestilt Produkter; privat OrderStatus orderStatus; privat LocalDate orderDate; privat LocalDate orderFinishDate; privat PaymentType betalingType; privat rabat rabat; privat int-shopId; privat DeliveryData leveringData; privat butikstilbudShop; // standard getters og setter}

Hele modelstrukturen kan findes her.

4. Konvertere

For at forenkle designet af testopsætningen har vi oprettet Konverter grænseflade:

public interface Converter {Bestil konvertering (SourceOrder sourceOrder); DestinationCode konvertere (SourceCode sourceCode); }

Og alle vores brugerdefinerede kortlæggere implementerer denne grænseflade.

4.1. Orika-konverter

Orika muliggør fuld API-implementering, dette forenkler oprettelsen af ​​kortlæggeren i høj grad:

offentlig klasse OrikaConverter implementerer Converter {private MapperFacade mapperFacade; offentlig OrikaConverter () {MapperFactory mapperFactory = ny DefaultMapperFactory .Builder (). build (); mapperFactory.classMap (Order.class, SourceOrder.class) .field ("orderStatus", "status"). byDefault (). register (); mapperFacade = mapperFactory.getMapperFacade (); } @ Override public Order convert (SourceOrder sourceOrder) {return mapperFacade.map (sourceOrder, Order.class); } @ Override public DestinationCode convert (SourceCode sourceCode) {return mapperFacade.map (sourceCode, DestinationCode.class); }}

4.2. DozerConverter

Dozer kræver XML-kortlægningsfil med følgende sektioner:

  com.baeldung.performancetests.model.source.SourceOrder com.baeldung.performancetests.model.destination.Order status ordre status    com.baeldung.performancetests.model.source.SourceCode com.baeldung.performancetests.model.destination.DestinationCode 

Efter at have defineret XML-kortlægningen kan vi bruge den fra kode:

offentlig klasse DozerConverter implementerer Converter {private final Mapper mapper; offentlig DozerConverter () {this.mapper = DozerBeanMapperBuilder.create () .withMappingFiles ("dozer-mapping.xml") .build (); } @Override public Order convert (SourceOrder sourceOrder) {return mapper.map (sourceOrder, Order.class); } @ Override public DestinationCode convert (SourceCode sourceCode) {return mapper.map (sourceCode, DestinationCode.class); }}

4.3. MapStructConverter

MapStruct-definition er ret enkel, da den udelukkende er baseret på kodegenerering:

@Mapper offentlig grænseflade MapStructConverter udvider Converter {MapStructConverter MAPPER = Mappers.getMapper (MapStructConverter.class); @Mapping (source = "status", target = "orderStatus") @Override Order convert (SourceOrder sourceOrder); @ Override DestinationCode konvertere (SourceCode sourceCode); }

4.4. JMapperConverter

JMapperConverter kræver mere arbejde at gøre. Efter implementering af grænsefladen:

offentlig klasse JMapperConverter implementerer Converter {JMapper realLifeMapper; JMapper simpleMapper; offentlig JMapperConverter () {JMapperAPI api = ny JMapperAPI () .add (JMapperAPI.mappedClass (Order.class)); realLifeMapper = ny JMapper (Order.class, SourceOrder.class, api); JMapperAPI simpleApi = ny JMapperAPI () .add (JMapperAPI.mappedClass (DestinationCode.class)); simpleMapper = ny JMapper (DestinationCode.class, SourceCode.class, simpleApi); } @Override public Order convert (SourceOrder sourceOrder) {return (Order) realLifeMapper.getDestination (sourceOrder); } @Override public DestinationCode convert (SourceCode sourceCode) {return (DestinationCode) simpleMapper.getDestination (sourceCode); }}

Vi skal også tilføje @JMap kommentarer til hvert felt i målklassen. JMapper kan heller ikke konvertere mellem enumtyper alene, og det kræver, at vi opretter tilpassede kortlægningsfunktioner:

@JMapConversion (fra = "betalingstype", til = "betalingstype") offentlig betalingstypekonvertering (com.baeldung.performancetests.model.source.PaymentType type) {PaymentType betalingstype = null; switch (type) {case CARD: paymentType = PaymentType.CARD; pause; sag CASH: paymentType = PaymentType.CASH; pause; sag TRANSFER: paymentType = PaymentType.TRANSFER; pause; } returner betalingstype; }

4.5. ModelMapperConverter

ModelMapperConverter kræver, at vi kun angiver de klasser, vi vil kortlægge:

offentlig klasse ModelMapperConverter implementerer Converter {privat ModelMapper modelMapper; offentlig ModelMapperConverter () {modelMapper = ny ModelMapper (); } @ Override public Order convert (SourceOrder sourceOrder) {return modelMapper.map (sourceOrder, Order.class); } @Override public DestinationCode convert (SourceCode sourceCode) {return modelMapper.map (sourceCode, DestinationCode.class); }}

5. Enkel modeltest

Til præstationstesten kan vi bruge Java Microbenchmark Harness. Flere oplysninger om, hvordan du bruger det, kan findes i denne artikel.

Vi har oprettet et separat benchmark for hver Konverter med at specificere BenchmarkMode til Mode. Alt.

5.1. Gennemsnitstid

JMH returnerede følgende resultater for gennemsnitlig kørselstid (jo mindre jo bedre):

Rammens navnGennemsnitlig driftstid (i ms pr. Operation)
MapStruct10 -5
JMapper10 -5
Orika0.001
ModelMapper0.001
Dozer0.002

Dette benchmark viser tydeligt, at både MapStruct og JMapper har de bedste gennemsnitlige arbejdstider.

5.2. Gennemstrømning

I denne tilstand returnerer benchmark antallet af operationer pr. Sekund. Vi har modtaget følgende resultater (mere er bedre) :

Rammens navnGennemstrømning (i operationer pr. Ms)
MapStruct133719
JMapper106978
Orika1800
ModelMapper978
Dozer471

I gennemløbstilstand var MapStruct den hurtigste af de testede rammer, med JMapper et tæt sekund.

5.3. SingleShotTime

Denne tilstand tillader måling af tidspunktet for en enkelt operation fra begyndelsen til slutningen. Benchmarket gav følgende resultat (mindre er bedre):

Rammens navnSingle Shot Time (i ms pr. Operation)
JMapper0.015
MapStruct0.450
Dozer2.094
Orika2.898
ModelMapper4.837

Her ser vi, at JMapper returnerer bedre resultat end MapStruct.

5.4. SampleTime

Denne tilstand tillader prøveudtagning af tidspunktet for hver operation. Resultaterne for tre forskellige percentiler ser ud som nedenfor:

Prøve tid (i millisekunder pr. Operation)
Rammens navnp0,90s0.999p1.0
JMapper10-40.0012.6
MapStruct10-40.0013
Orika0.0010.0104
ModelMapper0.0020.0153.2
Dozer0.0030.02125

Alle benchmarks har vist, at MapStruct og JMapper begge er gode valg afhængigt af scenariet.

6. Real-Life Model Testing

Til præstationstesten kan vi bruge Java Microbenchmark Harness. Flere oplysninger om, hvordan du bruger det, kan findes i denne artikel.

Vi har oprettet et separat benchmark for hver Konverter med at specificere BenchmarkMode til Mode. Alt.

6.1. Gennemsnitstid

JMH returnerede følgende resultater for gennemsnitlig kørselstid (mindre er bedre):

Rammens navnGennemsnitlig driftstid (i ms pr. Operation)
MapStruct10 -4
JMapper10 -4
Orika0.004
ModelMapper0.059
Dozer0.103

6.2. Gennemstrømning

I denne tilstand returnerer benchmark antallet af operationer pr. Sekund. For hver af kortlæggerne har vi modtaget følgende resultater (mere er bedre):

Rammens navnGennemstrømning (i operationer pr. Ms)
JMapper7691
MapStruct7120
Orika281
ModelMapper19
Dozer10

6.3. SingleShotTime

Denne tilstand gør det muligt at måle tidspunktet for en enkelt operation fra begyndelsen til slutningen. Benchmarket gav følgende resultater (mindre er bedre):

Rammens navnSingle Shot Time (i ms pr. Operation)
JMapper0.253
MapStruct0.532
Dozer9.495
ModelMapper16.288
Orika18.081

6.4. SampleTime

Denne tilstand tillader prøveudtagning af tidspunktet for hver operation. Prøveudtagningsresultater opdeles i percentiler, vi præsenterer resultater for tre forskellige percentiler p0,90, p0,999, og p1.00:

Prøve tid (i millisekunder pr. Operation)
Rammens navnp0,90s0.999p1.0
JMapper10-30.00864
MapStruct10-30.01068
Orika0.0060.27832
ModelMapper0.0832.39897
Dozer0.1464.526118

Mens de nøjagtige resultater af det enkle eksempel og det virkelige eksempel var klart forskellige, men de følger mere eller mindre den samme tendens. I begge eksempler så vi en tæt konkurrence mellem JMapper og MapStruct om toppen.

6.5. Konklusion

Baseret på den virkelige model test, vi udførte i dette afsnit, kan vi se, at den bedste ydeevne helt klart hører til JMapper, selvom MapStruct er et tæt sekund. I de samme tests ser vi, at Dozer er konsekvent i bunden af ​​vores resultattabel, bortset fra SingleShotTime.

7. Resumé

I denne artikel har vi gennemført præstationstest af fem populære Java-bønne kortlægningsrammer: ModelMapper, MapStruct, Orika, Dozer og JMapper.

Som altid kan kodeeksempler findes på GitHub.