Table of Contents - GitHub Pages · Getting Started Downloading the Distribution If you are using...

Post on 30-May-2020

26 views 0 download

Transcript of Table of Contents - GitHub Pages · Getting Started Downloading the Distribution If you are using...

1.1

1.2

1.3

1.3.1

1.4

1.4.1

1.4.2

1.5

1.5.1

1.5.2

2.1

2.2

2.3

2.4

2.5

2.6

2.7

2.8

2.9

2.10

2.11

3.1

3.2

3.3

3.4

3.5

4.1

4.2

4.3

TableofContentsIntroduction

WhyMap?

GettingStarted

Usage

MappingsviaXML

viaAnnotations

viaAPI

Configuration

ConfigurationviaXML

ConfigurationviaAPI

DozermappingconceptsMappingClasses

BasicPropertyMapping

InheritanceMapping

ContextBasedMapping

One-WayMapping

CopyingByObjectReference

DeepPropertyMapping

IndexedPropertyMapping

ExcludingFields

AssemblerPattern

Mappingimmutabletypes

Howdoimapatypeof…?Enums

StringtoDate

CollectionsandArrays

MapBackedPropertyMapping

ProxyObjects

Whatifineedtocustomisethemapping?CustomConverters

CustomBeanFactories

CustomCreateMethods

1

4.4

4.5

5.1

5.2

5.3

6.1

6.2

6.3

7.1

7.2

8.1

8.2

8.3

8.4

9.1

9.2

9.3

10.1

10.2

10.2.1

10.2.2

Customget()set()Methods

ExpressionLanguage

ExtraLogging

EventListening

MetadataQueryInterface

3rdPartySpringIntegration

SpringBootIntegration

JAXB

OtherFAQ

Examples

Migrationv5tov6

v6.0.0tov6.1.0

v6.1.0tov6.2.0

v6.2.0tov6.3.0

SchemaMappingXSD

Spring4XSD

User’sGuidePDF

EclipsePluginInstallation

Usage

viaXML

viaEditor

2

3

Dozer

WhatisDozer?DozerisaJavaBeantoJavaBeanmapperthatrecursivelycopiesdatafromoneobjecttoanother.Typically,theseJavaBeanswillbeofdifferentcomplextypes.

Dozersupportssimplepropertymapping,complextypemapping,bi-directionalmapping,implicit-explicitmapping,aswellasrecursivemapping.Thisincludesmappingcollectionattributesthatalsoneedmmappingattheelementlevel.

PleasereadtheaboutpagefordetailedinformationonDozer.

Introduction

4

WhyMap?Amappingframeworkisusefulinalayeredarchitecturewhereyouarecreatinglayersofabstractionbyencapsulatingchangestoparticulardataobjectsvs.propagatingtheseobjectstootherlayers(i.e.externalservicedataobjects,domainobjects,datatransferobjects,internalservicedataobjects).AmappingframeworkisidealforusingwithinMappertypeclassesthatareresponsibleformappingdatafromonedataobjecttoanother.

Fordistributedsystems,asideeffectisthepassingofdomainobjectsbetweendifferentsystems.Typically,youwon’twantinternaldomainobjectsexposedexternallyandwon’tallowforexternaldomainobjectstobleedintoyoursystem.

Mappingbetweendataobjectshasbeentraditionallyaddressedbyhandcodingvalueobjectassemblers(orconverters)thatcopydatabetweentheobjects.Mostprogrammerswilldevelopsomesortofcustommappingframeworkandspendcountlesshoursandthousandsoflinesofcodemappingtoandfromtheirdifferentdataobject.

Agenericmappingframeworksolvestheseproblems.Dozerisanopensourcemappingframeworkthatisrobust,generic,flexible,reusable,andconfigurable.

Dataobjectmappingisanimportantpartoflayeredserviceorientedarchitectures.Pickandchoosethelayersyouusemappingcarefully.Donotgooverboardasthereismaintenanceandperformancecostsassociatedwithmappingdataobjectsbetweenlayers.

ParallelObjectHierarchies

Therecouldbedifferentreasonsofwhyapplicationshouldsupportparallelobjecthierarhchies.Tonameafew:

IntegrationwithExternalCode

SerializationRequirements

FrameworkIntegration

SeparationofArchitecturalLayers

Insomecasesitisefficienttoguardyourcodebasefromfrequentlychangingobjecthierarchy,whichyoudonotcontroldirectly.InthiscaseDozerservesasabridgebetweenapplicationandexternalobjects.AsmappingisperformedinreflectivemannernotallchangesbreakyourAPI.ForexampleifobjectchangesfromNumbertoStringthecodewillkeepworkingasthisisresolvedautomatically.

SomeframeworksimposeSerializationconstraints,whichdoesnotallowsendinganyJavaobjectsthroughthewire.OneofthepopularexamplesisGoogleWebToolkit(GWT)framework,whichrestrictsdevelopertosendingonlyobjectscompiledtoJavaScriptandmarkedasSerializable.DozerhelpstoconvertRichDomainModeltoPresentationModel,whichsatisfiesGWTserializationrequirements.

DozerintegratesnicelywithframeworksuseJAXBimplementations.Withhelpofprovidedfactoryclasses,conversionbetweendomainmodelandXmlobjectsisdefinedinthesamewayasplainobjecttoobjectmappings.

Incomplexenterpriseapplicationitisoftenvaluabletoseparatedesigntoseveralarchitecturallayers.Eachofthemwouldresideonitsownabstractionlevel.Atypicalsimplifiedexamplewouldbepresentation,domainandpersistencelayers.EachofthislayerscouldhaveownsetofJavaBeansrepresentingdatarelevantforthislayer.Itisnotnecessarythatalldatawilltraveltotheupperlevelsofarchitecture.Forexamplethesamedomainobjectcouldhavedifferentmappingsdependantofthepresentationlayerrequirements.

WhyMap?

5

WhyMap?

6

GettingStarted

DownloadingtheDistribution

IfyouareusingApacheMaven,simplycopy-pastethisdependencytoyourproject.

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>6.4.0</version></dependency>

1stMapping

Foryourfirstmapping,letsassumethatthetwodataobjectsshareallcommonattributenames.

Mappermapper=DozerBeanMapperBuilder.buildDefault();DestinationObjectdestObject=mapper.map(sourceObject,DestinationObject.class);

AfterperformingtheDozermapping,theresultwillbeanewinstanceofthedestinationobjectthatcontainsvaluesforallfieldsthathavethesamefieldnameasthesourceobject.Ifanyofthemappedattributesareofdifferentdatatypes,theDozermappingenginewillautomaticallyperformdatatypeconversion.AtthispointyouhavecompletedyourfirstDozermapping.Latersectionswillgooverhowtospecifycustommappingsviacustomxmlfiles.

IMPORTANT:Forreal-worldapplicationsitisNOTrecommendedtocreateanewinstanceoftheMappereachtimeyoumapobjectsbutreusecreatedinstanceinstead.

SpecifyingCustomMappingsviaXML

Ifthetwodifferenttypesofdataobjectsthatyouaremappingcontainanyfieldsthatdon’tshareacommonpropertyname,youwillneedtoaddaclassmappingentrytoyourcustommappingxmlfile.ThesemappingsxmlfilesareusedatruntimebytheDozermappingengine.

Dozerautomaticallyperformsanytypeconversionwhencopyingthesourcefielddatatothedestinationfield.TheDozermappingengineisbi-directional,soifyouwantedtomapthedestinationobjecttothesourceobject,youdonotneedtoaddanotherclassmappingtothexmlfile.

IMPORTANT:Fieldsthatareofthesamenamedonotneedtobespecifiedinthemappingxmlfile.Dozerautomaticallymapsallfieldswiththesamepropertynamefromthesourceobjectintothedestinationobject.

i.e.:

<mapping><class-a>yourpackage.yourSourceClassName</class-a><class-b>yourpackage.yourDestinationClassName</class-b><field><a>yourSourceFieldName</a><b>yourDestinationFieldName</b></field></mapping>

ThecompleteDozermappingxmlfilewouldlooklikethefollowing.TheCustomMappingssectioncontainsmoreinformationonmappingoptionsthatareavailabletoyouformorecomplexusecases.

GettingStarted

7

<?xmlversion="1.0"encoding="UTF-8"?><mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttp://dozermapper.github.io/schema/bean-mapping.xsd"><configuration><stop-on-errors>true</stop-on-errors><date-format>MM/dd/yyyyHH:mm</date-format><wildcard>true</wildcard></configuration><mapping><class-a>yourpackage.yourSourceClassName</class-a><class-b>yourpackage.yourDestinationClassName</class-b><field><A>yourSourceFieldName</A><B>yourDestinationFieldName</B></field></mapping></mappings>

DozerandDependencyInjectionFrameworks

DozerisnotdependantofanyexistingDependencyInjectionframework(DI).Howeverthegeneralaimistosupportthemosttypicalusecaseswithready-to-usewrappers.CheckSpringIntegrationmanualforoptionofinitializingDozerincontextofSpringDIframework.

GettingStarted

8

Usage

DozerBeanMapper

Beforewegooversettingupcustomxmlbeanmappings,letuslookatasimpleexampleofusingDozer.TheDozermappingimplementationhasamethodcalledmapwhichtakesasourceobjectandeitheradestinationobjectordestinationobjectclasstype.Aftermappingthetwoobjectsitthenreturnsthedestinationobjectwithallofitsmappedfields.

Mappermapper=DozerBeanMapperBuilder.buildDefault();DestinationObjectdestObject=mapper.map(sourceObject,DestinationObject.class);

Or…

DestinationObjectdestObject=newDestinationObject();mapper.map(sourceObject,destObject);

Dozeroperatesintwogeneralmodes:implicitandexplicit.

Implicitmodeisactivatedbydefaultandtriestoresolvemappingsforyou.Itusessimpleassumptionsthatiftwoobjectsarepassedformappingthenbeanpropertieswiththesamenamesshouldbemapped.Ifthereareadditionalmappingsneeded,whichcannotbederivedbythenamingyoushouldaddthoseeitherviaXML,annotationsorAPI.

Explicitmodeassumesthatnomappingsshouldbeperformedor"guessed"untilyouhavespecifiedthosespecifically.Theamountofcodingishigherinexplicitmode,butsometimesyouwouldliketohavefullcontrolonwhatisgoingonduringthemappingsprocessandthisapproachisalsousedinmanyoftheproductiveapplications.Implicit/Explicitmappingswitchiscalled"wildcard"inDozer.

InjectingCustomMappingFiles

TheDozermappingxmlfile(s)defineanycustommappingsthatcan’tbeautomaticallyperformedbytheDozermappingengine.AnycustomDozermappingfilesneedtobeinjectedintotheMapperimplementationviaDozerBeanMapperBuilder#withMappingFiles(..)method.

Preferably,youwillbeusinganIOCframeworksuchasSpringfortheseDozerinjectionrequirements.Alternatively,theinjectionofmappingfilescanbedoneprogrammatically.Belowisaprogrammaticapproachtocreatingabeanmapper.NotethatthisisNOTtherecommendedwaytoretrievethebeanmapper.Eachnewinstanceneedstobeinitializedandthisconsumestimeaswellasresources.Ifyouareusingthemapperthiswayjustwrapitusingthesingletonpattern.

Mappermapper=DozerBeanMapperBuilder.create().withMappingFiles("dozerBeanMapping.xml","someOtherDozerBeanMappings.xml").build();

DestinationObjectdestObject=mapper.map(sourceObject,DestinationObject.class);

SpringIntegration

ThefollowingisanexamplehowtheMapperbeanwouldbeconfiguredviaSpring.

<beanid="mapper"class="com.github.dozermapper.core.DozerBeanMapper"><propertyname="mappingFiles"><list>

Usage

9

<value>dozer-global-configuration.xml</value><value>dozer-bean-mappings.xml</value><value>more-dozer-bean-mappings.xml</value></list></property></bean>

Usage

10

CustomMappingsViaDozerXMLFilesThissectionwillcoversettingupcustommappingsinxmlfile(s).Ifthetwodifferenttypesofdataobjectsthatyouaremappingcontainanyfieldsthatdon’tshareacommonpropertyname,youwillneedtoaddaclassmappingentrytoyourcustommappingxmlfile.ThesemappingsxmlfilesareusedatruntimebytheDozermappingengine.

Dozerautomaticallyperformsanytypeconversionwhencopyingthesourcefielddatatothedestinationfield.TheDozermappingengineisbi-directional,soifyouwantedtomapthedestinationobjecttothesourceobject,youdonotneedtoaddanotherclassmappingtothexmlfile.

Anexampleofamappingfile….

<?xmlversion="1.0"encoding="UTF-8"?><mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttp://dozermapper.github.io/schema/bean-mapping.xsd"><mapping><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><field><a>one</a><b>onePrime</b></field></mapping><mappingwildcard="false"><class-a>com.github.dozermapper.core.vo.TestObjectFoo</class-a><class-b>com.github.dozermapper.core.vo.TestObjectFooPrime</class-b><field><a>oneFoo</a><b>oneFooPrime</b></field></mapping></mappings>

Amappingselementhasmultiplemappingelements,eachwithclassmappingdeclarationsandfieldlevelmappings.Thewildcardattributeissettotruebydefault.Thismeansthatitwillautomaticallytrytomapeverypropertyinthetwoobjects.Whentheattributeissettofalseitwillonlymapexplicitlydefinedfields.

IMPORTANT:Propertiesthatareofthesamenamedonotneedtobespecifiedinthemappingxmlfile.Dozerautomaticallymapsallfieldswiththesamepropertynamefromthesourceobjectintothedestinationobject.

HowCustomMappingFilesAreLoaded

Dozerwillsearchtheentireclasspathlookingforthespecifiedfile.Thegenerallyacceptablewayofdistributingyourmappingsistobundletheminsideyourapplicationarchive.

Alternatively,youcanloadfilesfromoutsidetheclasspathbyprepending"file:"totheresourcename.Ex)"file:c:\somedozermapping.xml"

LoadingFilesfromInputStream

Sinceversion5.4.0itispossibletoloadXMLmappingfilesfromprovidedInputStreamobject.CheckDozerMapperclassforthecorrespondingAPIcalls.

MappingsviaXML

11

MappingsviaXML

12

AnnotationMappings

WhyAnnotations?

OneofthedownsidesofusingDozerforthelongtimewasXml.SinceDozerstartedduringXml-hypeyearsmorethanfiveyearsagothatwasprettyobviouschoicebackthen.AfterthatJava5broughtusannotationsandnewindustryacceptedstyleofconfiguringbehaviourareDomain-SpecificLanguages.DSL-likesupportisprovidedinformofmappingAPI,butsinceversion5.3.2Dozerstartsprovidingannotationssupportaswell.

Theobviousreasonstouseannotationsistoavoidduplicatingfieldandmethodnamesinyourmappingcode.Theannotationcanbeputontothemappedpropertyitselfthusreducingtheamountofcode.Howevertherearecaseswhenannotationsshouldbeavoidedorevenimpossibletouse.Someofthemarethefollowing:

Youaremappingclasses,whicharenotunderyourcontrol,butprovidedinlibraries;

Themappingsarequitecomplexandrequiremanyconfigurations;

InthefirstcaseyoucouldbemappingJAXBgeneratedentitiesorthird-partyDTOsandhavenopossibilitytoputannotations.Inthesecondcasethereisachoiceofputtinglotsofmulti-lineannotationsorisolatingthemappingcodewithcertainduplicationofentitynames.Overannotatedbeanscouldbeproblematictoreadandunderstand.

Usage

WARNING:AnnotationsupportinDozerisexperimentalanddoesnotcovercomplexusecasesyet.HoweveritmaybeusefultoimplementthatsimplestmappingsyouhavehadtodoinXmlorAPIbefore.

Theideaisverysimple.Youput@Mappingannotationeitherongetteroffielddirectly.IfDozerfindsthatitaddsabi-directionalmapping.Itmeansthatputtingannotationoncewillcreatemappingsforbothconversiontypes.Typeconversions(e.g.String-Long)willbechosenautomatically.Globalcustomconvertersareresolvedaswell.Annotationsworkonlyifaconversionissubjecttowildcardrule(activebydefault).Thefollowingexampledemonstratesannotationsinaction.

publicclassSourceBean{

privateLongid;

privateStringname;

@Mapping("binaryData")privateStringdata;

@Mapping("pk")publicLonggetId(){returnthis.id;}

publicStringgetName(){returnthis.name;}}

publicclassTargetBean{

privateStringpk;

privateStringname;

viaAnnotations

13

privateStringbinaryData;

publicvoidsetPk(Stringpk){this.pk=pk;}

publicvoidsetName(Stringname){this.name=name;}}

MappingthegivenbeanswithDozerwillresultinallthreefieldsbeingmapped.Property"name"willbemappedbynamingconvention.Property"id"willbetransformedto"pk".Field"data"willbemovedto"binaryData".Donotworryaboutprivatemodifier;itwillbehandledautomatically.

CurrentlyDozeroffersonlyoneannotation,butthenextoneswillbeaddedinfollowingreleases.Asfornowyoucanmixandmatchallflavoursofmappingtypestoachievethedesiredeffect:Xml,APIandAnnotations.

viaAnnotations

14

APIMappings

XMLMappingFlaws

XML-basedapproachisstableandisusedinmanyproductionprojects.However,itimposesseverallimitations.

First,andmostimportant,isthatitcannotbedynamicallygenerated.AllXMLmappingsshouldbepresentonDozerstart-upandcannotbemodifiedafterwards.Therearetrickyways,whenyoucangenerateandputmappingstothefilesystembyyourowntemplatingengine,butthisapproachisnotsupportedbyDozeritself.Bygeneratingcustommappingsyouareabletoautomaterepetitivechunksoflow-levelDozerlanguage.

SecondproblemisthatyouareforcedtoduplicateallofyourBeanclassnamesinXmlmappings.Thisleadstolotsoftypingandcopy-pasteprogramming.ThiscanbepartlycompensatedbyuseofExpressionLanguageinsideXml,butitisnotsolvingalloftheproblems.

RefactoringsupportislimitedasIDEshouldkeeptrackofclassnamesinXmlfilesandchangethemwhenyourenameormovethereferencedclass.Auto-completionsupportisalsonotavailableinallIDEs.

APIMappings

APImappingsareintendedtosolveallofthementionedproblems.TopreservebackwardscompatibilityAPImappingscanbecombinedwithexistingXmlmappings.Infactsomepartsoftheconfiguration(e.g.globalconfigurationblock)areonlypossibletoexpressinXmlformat.

Togetafeelingofwhatarethesemappingstakealookatthefollowingcodeexample.

importcom.github.dozermapper.core.classmap.RelationshipType;importcom.github.dozermapper.core.loader.api.BeanMappingBuilder;importcom.github.dozermapper.core.loader.api.FieldsMappingOptions;importcom.github.dozermapper.core.loader.api.TypeMappingOptions;

importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.collectionStrategy;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.copyByReference;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.customConverter;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.customConverterId;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.hintA;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.hintB;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.useMapId;importstaticcom.github.dozermapper.core.loader.api.TypeMappingOptions.mapId;importstaticcom.github.dozermapper.core.loader.api.TypeMappingOptions.mapNull;

publicclassMyClass{

publicvoidcreate(){BeanMappingBuilderbuilder=newBeanMappingBuilder(){protectedvoidconfigure(){mapping(Bean.class,Bean.class,TypeMappingOptions.oneWay(),mapId("A"),mapNull(true)).exclude("excluded").fields("src","dest",copyByReference(),collectionStrategy(true,RelationshipType.NON_CUMULATIVE),hintA(String.class),hintB(Integer.class),FieldsMappingOptions.oneWay(),useMapId("A"),customConverterId("id")

viaAPI

15

).fields("src","dest",customConverter("com.github.dozermapper.core.CustomConverter"));}};}}

ConstructedbuilderobjectshouldbethenpassedtoDozerBeanMapperBuilder.ItispossibletoaddmultipleBuilderclasses.

Mappermapper=DozerBeanMapperBuilder.create().withMappingBuilder(builder).build();

viaAPI

16

ConfigurationDozerconfigurationpropertiescanbecustomizedviaanoptionalDozerpropertiesfile.Bydefault,Dozerwilllookforafilenameddozer.propertiestoloadconfigurationproperties.Ifapropertiesfileisnotfoundorspecified,defaultvalueswillbeused.

Dozerisdistributedwithanexampledozer.propertiesfilein/configthatshowsthevariousoptions.Justputtheexamplefileinyourclasspathandcustomizeit.

AnalternativeDozerpropertiesfilecanbespecifiedviathedozer.configurationsystemproperty.ex)-Ddozer.configuration=someDozerConfigurationFile.properties

Table1.DozerConfigurationProperties

PropertyName Description ValidValues Default

dozer.el.enabled

SpecifieswhetherduringXmlmappingsparsingDozerwillrecognizeELexpressions.

true false false

dozer.cache.converter-by-dest-type-maxsize

SpecifiesthemaxsizeforoneofDozersinternalcaches.

0-Long.MAX_VALUE 10000

dozer.cache.super-type-maxsize

SpecifiesthemaxsizeforoneofDozersinternalcaches

0-Long.MAX_VALUE 10000

dozer.beans.proxy-resolver-bean

SpecifiesimplementationofDozerProxyResolvertobeused

Validclassname Defaultimplementation

dozer.beans.class-loader-bean

SpecifiesimplementationofDozerClassLoadertobeused

Validclassname Defaultimplementation

Configuration

17

ConfigurationviaXMLThemajorityofDozer’sbehaviourcanbeconfiguredfromwithinXMLmappingfiles.Settingscanappearinsidefivedifferentscopeswhichaffecttheelementstheyareappliedto:Global,perclassmapping,atindividualclasslevel,perfieldmapping,andatindividualfieldlevel.

ConfigurationScopes

GlobalScope

Theconfigurationblockisusedtosettheglobaldefaultsettings.Also,anyCustomConvertersaredefinedinthissection.Theconfigurationblockisentirely"optional".

Dozersupportstheabilitytohavemultiplemappingfiles.Eachofthesemappingfilescanhavetheirownconfigurationblock.Amappingwillinherititsconfigurationfromthemappingfilethatitisstoredin.Implicitmappingswillinheritthedefaultvaluesforconfiguration.

Thefollowingisthesampleconfigurationblockfromtheexamplemappingsfile:

<configuration><date-format>MM/dd/yyyyHH:mm</date-format><stop-on-errors>true</stop-on-errors><wildcard>true</wildcard><custom-converters><!--thesearealwaysbi-directional--><convertertype="com.github.dozermapper.core.converters.TestCustomConverter"><class-a>com.github.dozermapper.core.vo.TestCustomConverterObject</class-a><class-b>another.type.to.Associate</class-b></converter></custom-converters></configuration>

AllglobalsettingsappearasseparateXMLtagscontainingtheirvalue.

PerClassMapping

Globalsettings(ortheirdefaults)canbeoverriddenattheindividualmappinglevel.Here,configurationvaluesaresetusingname="value"attributes.Theywillaffectallmappingoperationsbetweenthetwoclasses.

<mappingwildcard="false"date-format="MM/dd/yyyyHH:mm"><class-a>com.github.dozermapper.core.vo.SpringBean</class-a><class-b>com.github.dozermapper.core.vo.SpringBeanPrime</class-b><field><a>anAttributeToMap</a><b>anAttributeToMapPrime</b></field></mapping>

AtIndividualClassLevel

Sometimes,youmaywanttoapplyasettingonlytooneofthetwoclasses.Thiscanbeachievedbyplacingtheattributeinsidetheclass-aorclass-btag:

<mapping><class-ais-accessible="true">com.github.dozermapper.core.vo.SpringBean</class-a>

ConfigurationviaXML

18

<class-b>com.github.dozermapper.core.vo.SpringBeanPrime</class-b><field><a>anAttributeToMap</a><b>anAttributeToMapPrime</b></field></mapping>

PerFieldMapping

Likewise,youcanchangethemappingbehaviourforspecificfieldpairs:

<mapping><class-a>com.github.dozermapper.core.vo.SpringBean</class-a><class-b>com.github.dozermapper.core.vo.SpringBeanPrime</class-b><fieldremove-orphans="false"><a>anAttributeToMap</a><b>anAttributeToMapPrime</b></field></mapping>

AtIndividualFieldLevel

Finally,somesettingscanbeappliedtoasinglefield:

<mapping><class-a>com.github.dozermapper.core.vo.SpringBean</class-a><class-b>com.github.dozermapper.core.vo.SpringBeanPrime</class-b><field><aget-method="getTheAttribute">anAttributeToMap</a><b>anAttributeToMapPrime</b></field></mapping>

AvailableConfigurationSettings

Thefollowingtableliststheavailableconfigurationoptionsandmappingdirectives,inwhichscopestheycanappear,andthesectionofthemanualcontainingmoreinformation:

Name Global ClassMapping

SingleClass

FieldMapping

SingleField

ManualSection

allowed-exceptions X seebelow

custom-converter X Custom

Converters

custom-converter-id X Custom

Converters

custom-converter-param

X CustomConverters

copy-by-reference X CopyBy

Reference

copy-by-references X CopyBy

Reference

ConfigurationviaXML

19

create-method X X

CustomCreateMethod

bean-factory X X X

CustomBeanFactories

date-format X X XStringtoDateMapping

factory-bean-id X

CustomBeanFactories

get-method X CustomMethods

is-accessible X X

Mappingimmutabletypes

key X MapMapping

map-empty-string X X X Excluding

Fields

map-id XContextBasedMapping

map-null X X X ExcludingFields

map-set-method X X Map

Mapping

map-get-method X X Map

Mapping

relationship-type X X X Collection

Mapping

remove-orphans X Collection

Mapping

set-method X CustomMethods

skip-constructor X

Mappingimmutabletypes

stop-on-errors X seebelow

ConfigurationviaXML

20

trim-strings X X seebelow

type X X One-WayMapping

variables X ExpressionLanguage

wildcard X X seebelow

wildcard-case-insensitive

X X seebelow

Errorhandling(stop-on-errors,allowed-exceptions)

Bydefault,ifDozerencountersanerrorwhileperformingafieldmapping,anexceptionisthrownandthemappingaborted.Whilethisistherecommendedbehaviour,Dozercanbeinstructedtoignoretheerrorandsimplycontinuewiththenextfield,viathestop-on-errorspolicy.

YoucanalsospecifyexceptionsthatshouldcauseDozertostopandrethrowthem,evenifstop-on-errorsissettofalse,usingtheallowed-exceptionselement:

<configuration><stop-on-errors>false</stop-on-errors><allowed-exceptions><exception>org.example.UnrecoverableError</exception><exception>org.example.BadException</exception></allowed-exceptions></configuration>

TrimmingStrings(trim-strings)

Asthenamesuggests,trim-stringsappliesJava’sString.trim()tothesourcevaluebeforecallingthetargetbeans’ssetter.

Wildcardmapping(wildcard,wildcard-case-insensitive)

Perdefault,Dozermapsallfieldsbetweensourceandtargetbeanthatsharethesamename("wildcardmapping").Listingfieldsinmappingdefinitionsdoesnotoverridethisbehaviour,exceptforthegivenfields.Forexample,giventhefollowingclasses

classPerson{privateStringfirstName;privateStringlastName;}

classContact{privateStringfirstName;privateStringsurname;}

andthemappingdefinition

<mapping>

ConfigurationviaXML

21

<class-a>com.github.dozermapper.core.vo.Person</class-a><class-b>com.github.dozermapper.core.vo.Contact</class-b><field><a>lastName</a><b>surname</b></field></mapping>

amappingfromaPersonobjectontoaContactwillmaplastNametosurnameandfirstNametofirstName,eventhoughthelatterpairisnotmentionedinthemappingdefinition.

Youcandisablewildcardmappinggloballyorattheclassmappinglevelbysettingwildcardtofalse.Ifyoudo,youhavetoexplicitlyspecifyeachpairoffieldsthatshouldbemapped:

<mappingwildcard="false"><class-a>com.github.dozermapper.core.vo.Person</class-a><class-b>com.github.dozermapper.core.vo.Contact</class-b><field><a>lastName</a><b>surname</b></field><field><a>firstName</a><b>firstName</b></field></mapping>

UptoDozerversion5.4.0,wildcardmappingswerecaseinsensitive.CurrentversionsofDozeronlyautomaticallymapfieldswiththeexactsamename.Youcanenabletheoldcaseinsensitivebehaviourbysettingthewildcard-case-insensitivepolicytotrue.Then,forexampleasourcefieldnamedcamelCasewillbemappedtotargetfieldcamelcase(andviceversa).

ConfigurationviaXML

22

ConfigurationviaAPIIfyouareusingtheMapperBuildertodefineyourmappings,youcandeclaremapping,class,andfieldconfigurationsettingsprogrammatically:

Mappermapper=DozerBeanMapperBuilder.create().withMappingBuilder(newBeanMappingBuilder(){@Overrideprotectedvoidconfigure(){mapping(type(A.class).mapEmptyString(true),type(B.class),TypeMappingOptions.wildcardCaseInsensitive(true)).fields(field("fieldOfA").getMethod("getTheField"),field("fieldOfB"),FieldsMappingOptions.oneWay());}}).build();

GlobalconfigurationiscurrentlynotsupportedbytheAPI.

PleaseseeConfigurationviaXMLforalistoftheavailableconfigurationsettings.

ConfigurationviaAPI

23

MappingClassesAnexampleofmappingtwoclassesisdefinedbelow.Note:Explicitxmlmappingfor2classesisnotrequiredifallthefieldmappingbetweensrcanddestobjectcanbeperformedbymatchingonattributename.Customxmlclassmappingisonlyrequiredwhenyouneedtospecifyanycustomfieldmappings.

<mappings><mapping><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><!--Anycustomfieldmappingxmlwouldgohere--></mapping></mappings>

Thesemappingsarebi-directionalsoyouwouldneverneedtodefineanXMLmapforTestObjectPrimetoTestObject.Ifthesetwoclasseshadreferencestocomplextypesthatneededtypetransformation,youwouldalsodefinethemasmappings.Dozerrecursivelygoesthroughanobjectandmapseverythinginit.Datatypeconversionisperformedautomatically.Dozeralsosupportsnoattributemappingsatall.Ifsuppliedtwoclassesthatarenotmapped,itsimplytriestomappropertiesthatarethesamename.

MappingClasses

24

BasicPropertyMapping

ImplicitPropertyMapping(bi-directional)

MatchingfieldnamesareautomaticallyhandledbyDozer.

Propertiesthatareofthesamenamedonotneedtobespecifiedinthemappingxmlfile.

SimpleMappings(bi-directional)

Wewillstartoffsimple.Ifyouhavetwopropertieswithdifferentnamestheycanbemappedassuch:

<field><a>one</a><b>onePrime</b></field>

Datatypeconversion

DatatypecoversionisperformedautomaticallybytheDozermappingengine.Currently,Dozersupportsthefollowingtypesofconversions:(theseareallbi-directional)

PrimitivetoPrimitiveWrapper

PrimitivetoCustomWrapper

PrimitiveWrappertoPrimitiveWrapper

PrimitivetoPrimitive

ComplexTypetoComplexType

StringtoPrimitive

StringtoPrimitiveWrapper

StringtoComplexTypeiftheComplexTypecontainsaStringconstructor

StringtoMap

CollectiontoCollection

CollectiontoArray

MaptoComplexType

MaptoCustomMapType

EnumtoEnum

Eachofthesecanbemappedtooneanother:java.util.Date,java.sql.Date,java.sql.Time,java.sql.Timestamp,java.util.Calendar,java.util.GregorianCalendar

StringtoanyofthesupportedDate/CalendarObjects.

ObjectscontainingatoString()methodthatproducesalongrepresentingtimein(ms)toanysupportedDate/Calendarobject.

RecursiveMapping(bi-directional)

BasicPropertyMapping

25

DozersupportsfullClasslevelmappingrecursion.Ifyouhaveanycomplextypesdefinedasfieldlevelmappingsinyourobject,DozerwillsearchthemappingsfileforaClasslevelmappingbetweenthetwoClassesthatyouhavemapped.Ifyoudonothaveanymappings,itwillonlymapfieldsthatareofthesamenamebetweenthecomplextypes.

BasicPropertyMapping

26

InheritanceMapping

ReducingMappingXMLwhenusingbaseclassattributes

Propertiesthatareofthesamenamedonotneedtobespecifiedinthemappingxmlfileunlesshintsareneeded.

IfyouaremappingsubclassesthatalsohavehavebaseclassattributesrequiringmappingXML,youmightbeinclinedtoreproducebaseclassfieldmapsineachsubclassmappingelement,likethefollowingexample:

<mapping><class-a>com.github.dozermapper.core.vo.SubClass</class-a><class-b>com.github.dozermapper.core.vo.SubClassPrime</class-b><field><!--thisisthesameforallsubclasses--><a>superAttribute</a><b>superAttr</b></field><field><a>attribute2</a><b>attributePrime2</b></field></mapping><mapping><class-a>com.github.dozermapper.core.vo.SubClass2</class-a><class-b>com.github.dozermapper.core.vo.SubClassPrime2</class-b><field><!--thisisthesameforallsubclasses--><a>superAttribute</a><b>superAttr</b></field><field><a>attribute2</a><b>attributePrime2</b></field></mapping>

Inthepreviousmapping,someofthefieldswerefromacommonbaseclass,butyouhadtoreproducethemintoeachmappingofthesubclasses.

However,abetterwaytodoitwouldbetomapthebaseclassindividually.Thiscanbedoneforeachbaseclass(inthecaseofalargerheirarchy).Assumingthebaseclassname,belowistherefactoredmappingxml:

<mapping><class-a>com.github.dozermapper.core.vo.SuperClass</class-a><class-b>com.github.dozermapper.core.vo.SuperClassPrime</class-b><field><a>superAttribute</a><b>superAttr</b></field></mapping><mapping><class-a>com.github.dozermapper.core.vo.SubClass</class-a><class-b>com.github.dozermapper.core.vo.SubClassPrime</class-b><field><a>attribute</a><b>attributePrime</b></field></mapping><mapping><class-a>com.github.dozermapper.core.vo.SubClass2</class-a>

InheritanceMapping

27

<class-b>com.github.dozermapper.core.vo.SubClassPrime2</class-b><field><a>attribute2</a><b>attributePrime2</b></field></mapping>

Thefollowingimagesexplainsomeofthedifferentscenariosdozerhandles.Eachdiagramshowstwomappedclasshierarchiesandexistingrelations,whichDozerrecognizesandmaps.

Scenario1showsthatifyoumapSubClasstoClassPrimeallattributesfromSuperClass→ClassPrimewillbemappedaswell.

Scenario2showsthatDozerhasnolimitationsontheinheritancedepthitanalyzestofindparentmappings.

InheritanceMapping

28

Scenario3showsthatitispossibletomaptwocollectionswithdifferentsubctypesofthesameparenttype.Thisisdonebyprovidinghintstothecollectionmapping,describingallpotentialsubclasses.

<field><a>aList</a><b>bList</b><a-hint>B1,B2</a-hint><b-hint>BPrime1,BPrime2</b-hint></field>

InheritanceMapping

29

ContextBasedMappingContextbasedmappingcanbespecifiedbyusingthemap-idattribute.Notethatwealsosupportnestedcontextmappingbyspecifyingamap-idatthefieldlevel.

<mappingmap-id="caseA"><class-a>com.github.dozermapper.core.vo.context.ContextMapping</class-a><class-b>com.github.dozermapper.core.vo.context.ContextMappingPrime</class-b><field-exclude><a>loanNo</a><b>loanNo</b></field-exclude><fieldmap-id="caseC"><a>contextList</a><b>contextList</b><b-hint>com.github.dozermapper.core.vo.context.ContextMappingNestedPrime</b-hint></field></mapping><mappingmap-id="caseB"><class-a>com.github.dozermapper.core.vo.context.ContextMapping</class-a><class-b>com.github.dozermapper.core.vo.context.ContextMappingPrime</class-b></mapping><mappingmap-id="caseC"><class-a>com.github.dozermapper.core.vo.context.ContextMappingNested</class-a><class-b>com.github.dozermapper.core.vo.context.ContextMappingNestedPrime</class-b><field-exclude><a>loanNo</a><b>loanNo</b></field-exclude></mapping><mappingmap-id="caseD"><class-a>com.github.dozermapper.core.vo.context.ContextMappingNested</class-a><class-b>com.github.dozermapper.core.vo.context.ContextMappingNestedPrime</class-b></mapping>

TouseaparticularcontextwheninvokingtheMapper,yousimplyspecifythemap-idinyourmappingcall.

ContextMappingPrimecmpA=mapper.map(cm,ContextMappingPrime.class,"caseA");

ContextBasedMapping

30

One-WayMappingYoucansethowamappingdefinitionbehavesasfarasdirectiongoes.Ifyouonlywanttomaptwoclassestogoone-wayyoucansetthisatthemappinglevel.Thedefaultisbi-directional.ThiscanbesetatthemappinglevelORthefieldlevel.Whenone-wayisspecified,"a"isalwaysthesrcobjectand"b"isalwaysthedestinationobject.

<mappingtype="one-way"><class-a>com.github.dozermapper.core.vo.TestObjectFoo</class-a><class-b>com.github.dozermapper.core.vo.TestObjectFooPrime</class-b><field><a>oneFoo</a><b>oneFooPrime</b></field></mapping>

Inthefollowingexampletheone-wayfieldsareonlymappedwhen"a"objectismappedto"b"object.If"b"ismappedto"a",thenthefieldisnotmapped.

<mapping><class-a>com.github.dozermapper.core.vo.TestObjectFoo2</class-a><class-b>com.github.dozermapper.core.vo.TestObjectFooPrime2</class-b><fieldtype="one-way"><a>oneFoo2</a><b>oneFooPrime2</b></field><fieldtype="one-way"><a>oneFoo3.prime</a><b>oneFooPrime3</b></field></mapping>

ExcludingFieldsOne-Way

Dozersupportsfieldexcludesgoingone-wayasshownintheexample.Intheexamplethefieldisonlyexcludedwhen"a"ismappedto"b".If"b"ismappedto"a",thenthefieldisnotexcluded.

<field-excludetype="one-way"><a>fieldToExclude</a><b>fieldToExclude</b></field-exclude>

One-WayMapping

31

CopyingByObjectReferenceDozersupportscopyinganobjectbyreference.Noconversion/transformationisdoneforsuchobjects.Thisapproachallowstodecreaseanumberofobjectallocations,butisapplicableonlywhenJavaBeansaretobethrownaway(GarbageCollected)aftertransformation.Thisapproachisgenerallyrecommendedforperformancetuningofthemappingprocesswhenpossible.Makesurethatbothobjecttypesarethesameoryouwillrunintocastingproblems.Thedefaultvalueis'false'.

<fieldcopy-by-reference="true"><a>copyByReference</a><b>copyByReferencePrime</b></field>

Thisisalsosupportedattheclasslevel.Justdefinetheclassesyouwanttobecopiedbyreferenceintheconfigurationblock.

<configuration><copy-by-references><copy-by-reference>com.github.dozermapper.core.vo.NoExtendBaseObjectGlobalCopyByReference</copy-by-reference></copy-by-references></configuration>

Ontheclasslevelwildcardexpressionsareallowed.Copybyreferenceisappliedviamask,whichcaninlcudemultiplewildcard(*)characters.

<configuration><copy-by-references><copy-by-reference>com.github.dozermapper.core.vo.*</copy-by-reference><copy-by-reference>com.github.dozermapper.core.*.vo.*DTO</copy-by-reference></copy-by-references></configuration>

Referencingself(this)inafieldmapping

UsingafieldmappingitispossibletomapwhereN==0(self,orthis).InthefollowingexampleSimpleAccountismappedtoAddress.ItisalsomappedtoAccount.SupposeAddresswasanattributeonAccount.HowcouldwemapthevaluesonSimpleAccounttothatproperty?Theansweristousethekeyword(this)todenoteusingtheclassbeingmappedasthesourceobject.

<mapping><classa>com.github.dozermapper.core.vo.self.SimpleAccount</classa><classb>com.github.dozermapper.core.vo.self.Account</classb><field><a>this</a><b>address</b></field></mapping><mapping><classa>com.github.dozermapper.core.vo.self.SimpleAccount</classa><classb>com.github.dozermapper.core.vo.self.Address</classb>

CopyingByObjectReference

32

<field><a>streetName</a><b>street</b></field></mapping>

CopyingByObjectReference

33

DeepPropertyMappingItispossibletomapdeepproperties.AnexamplewouldbewhenyouhaveanobjectwithaStringproperty.YourotherobjecthasaStringpropertybutitisseverallevelsdeepwithintheobjectgraph.IntheexamplebelowtheDestDeepObjhasnestedattributeswithintheobjectgraphthatneedtobemapped.Typehintsaresupportedfordeepfieldmappings.Theattributescopy-by-reference,type=one-way,andrelationship-typecanalsobeused.

<mapping><class-a>com.github.dozermapper.core.vo.deep.SrcDeepObj</class-a><class-b>com.github.dozermapper.core.vo.deep.DestDeepObj</class-b><field><a>srcNestedObj.src1</a><b>dest1</b></field><field><a>srcNestedObj.src2</a><b>dest2</b></field><field><a>srcNestedObj.srcNestedObj2.src5</a><b>dest5</b></field><field><!--java.util.Listtojava.util.List--><a>srcNestedObj.hintList</a><b>hintList</b><a-hint>java.lang.String</a-hint><b-hint>java.lang.Integer</b-hint></field><field><a>srcNestedObj.hintList2</a><b>hintList2</b><a-hint>com.github.dozermapper.core.vo.TheFirstSubClass</a-hint><b-hint>com.github.dozermapper.core.vo.TheFirstSubClassPrime</b-hint></field><fieldcopy-by-reference="true"><a>srcNestedObj.hintList3</a><b>hintList3</b></field></mapping>

DeepIndexedMapping

Indexedmappingwithindeepmappingissupported.

<field><a>offSpringName</a><b>pets[1].offSpring[2].petName</b></field>

DestinationHintsareNOTrequirediftheindexedcollectionisanArrayorifyouareusingjdk1.5Generics.Dozerisabletoautomaticallydeterminethepropertytypefortheseusecases.ButyouwillneedtoprovidehintsifthedatatypesarenotArraysorifyouarenotusingGenerics.ThisisrequiredsothatDozerknowswhattypesofdestobjectstocreatewhileittraversesthedeepfieldmapping.

Thefollowingisanexampleofusinghints…..

<field><a>someField</a>

DeepPropertyMapping

34

<b>someList[1].someOtherList[0].someOtherField</b><b-deep-index-hint>com.github.dozermapper.core.vo.TestObject,com.github.dozermapper.core.vo.AnotherTestObject</b-deep-index-hint></field>

DeepPropertyMapping

35

IndexedPropertyMappingFieldsthatneedtobelookeduporwrittentobyindexedpropertyaresupported.

<mapping><class-a>com.github.dozermapper.core.vo.Individuals</class-a><class-b>com.github.dozermapper.core.vo.FlatIndividual</class-b><field><a>usernames[0]</a><b>username1</b></field><field><a>usernames[1]</a><b>username2</b></field><field><a>individual.username</a><b>username2</b></field><field><a>secondNames[1]</a><b>secondName1</b></field><field><a>secondNames[2]</a><b>secondName2</b></field><field><a>aliases.otherAliases[0]</a><b>primaryAlias</b></field></mapping>

IndexedPropertyMapping

36

ExcludingFieldsDozersupportsexcludingfieldsfromamappingusingthefield-excludetag.Wealsosupportfieldexcludesgoingone-wayasshownintheexample.

<field-exclude><a>fieldToExclude</a><b>fieldToExclude</b></field-exclude>

<field-excludetype="one-way"><a>fieldToExclude</a><b>fieldToExclude</b></field-exclude>

Wildcard-excludingdefaultfieldmappings

There’salsoaflag(wildcard)setonclassmappingwhichcontrolswhetherthedefaultmapping(whichappliestopairofpropertiesofthesamename)shouldbedone.Thedefaultvalueistrue.Forexample:

<mappingwildcard="false"><class-a>com.github.dozermapper.core.vo.AnotherTestObject</class-a><class-b>com.github.dozermapper.core.vo.AnotherTestObjectPrime</class-b><field><a>field1</a><b>field1</b></field></mapping>

Thisconfigurationwouldcauseonlythefieldsfield1inbothclassestobemapped,evenifbothclassesshareapropertywiththesamenamecalled`field2`.

ExcludeMappingNullValues

Youcanbypassthemappingofnullvalues.Ifthisisspecified,thedestfieldmappingisbypassedatruntimeandthedestinationvaluesettermethodwillnotbecalledifthesrcvalueisnull.Thiscanbespecifiedatthemappingorclasslevel.Forexample:

<mappingmap-null="false"><class-a>com.github.dozermapper.core.vo.AnotherTestObject</class-a><class-b>com.github.dozermapper.core.vo.AnotherTestObjectPrime</class-b><field><a>field4</a><b>to.one</b></field></mapping>

OR…

<mapping><class-a>com.github.dozermapper.core.vo.AnotherTestObject</class-a><class-bmap-null="false">com.github.dozermapper.core.vo.AnotherTestObjectPrime</class-b><field><a>field4</a><b>to.one</b></field>

ExcludingFields

37

</mapping>

ExcludeMappingEmptyStrings

YoucanbypassthemappingofemptyStringvalues.Ifthisisspecified,thedestfieldmappingisbypassedatruntimeandthedestinationvaluesettermethodwillnotbecalledifthesrcvalueisanemptyString.Thiscanbespecifiedatthemappingorclasslevel.Forexample:

<mappingmap-empty-string="false"><class-a>com.github.dozermapper.core.vo.AnotherTestObject</class-a><class-b>com.github.dozermapper.core.vo.AnotherTestObjectPrime</class-b><field><a>field4</a><b>to.one</b></field></mapping>

OR…

<mapping><class-a>com.github.dozermapper.core.vo.AnotherTestObject</class-a><class-bmap-empty-string="false">com.github.dozermapper.core.vo.AnotherTestObjectPrime</class-b><field><a>field4</a><b>to.one</b></field></mapping>

ExcludingFields

38

MappingConcepts

AssemblerPattern

DozercanbeusedasanAssembler.MartinFowlerhasagreatexplanationofwhyandwhenyouwoulduseanAssembler.Basically,itisawaytotakemultiplefinegrainobjectsandcreateonecoarsegrainobjectusedfordatatransfer.Aslongasyouhavemappingsdefinedforeachofyourfinegrainedobjectstoyourcoarsegrainobjectyoucancallthemappermultipletimestoachievethedesiredassemblerpattern.

mapper.map(sourceA,ClassB.class);

Let’ssaythatClassA,ClassB,andClassCallmaptoClassD.Firstcreatetheseindividualmappingsinthemappingfile.Next,callthemapperonceforeachmapping.Notethatthiswouldalsoworkinabi-directinonalmanner.

ClassDd=newClassD();mapper.map(sourceA,d);mapper.map(sourceB,d);mapper.map(sourceC,d);

AssemblerPattern

39

MappingimmutabletypesYoucancreateobjectswhenconstructorisnotavailable,orwhenthereisnono-argsconstructorintheclass.Featureisdesignedformappingimmutabletypes.Touseit,atthemappingleveladdanoptiontoskiptheconstructor,thenatthefieldlevelchoosetoinjectthevaluedirectlytothefield,skippingthesetter.

<mapping><class-a>com.github.dozermapper.core.vo.AnyExternalModelClass</class-a><class-bskip-constructor="true">com.github.dozermapper.core.vo.ImmutableModelClass</class-b><field><a>externalModelField</a><bis-accessible="true">ourFinalField</b></field></mapping>

Mappingimmutabletypes

40

EnumMappingTomapanenumsvaluetoanotherenumisshownbelow.

<field><a>status</a><b>statusPrime</b></field>

Basedonthefollowingcode:

enumStatus{PROCESSING,SUCCESS,ERROR}

publicclassUserGroup{

privateStatusstatus;

publicStatusgetStatus(){returnstatus;}

publicvoidsetStatus(Statusstatus){this.status=status;}

}

enumStatusPrime{PROCESSING,SUCCESS,ERROR}

publicclassUserGroupPrime{

privateStatusPrimestatusPrime;

publicStatusPrimegetStatusPrime(){returnstatusPrime;}

publicvoidsetStatusPrime(StatusPrimestatusPrime){this.statusPrime=statusPrime;}

}

Enums

41

StringtoDateMappingAdateformatfortheStringcanbespecifiedatthefieldlevelsothatthenecessarydatatypeconversioncanbeperformed.

<field><adate-format="MM/dd/yyyyHH:mm:ss:SS">dateString</a><b>dateObject</b></field>

Adefaultdateformatcanalsobespecifiedattheclassmappinglevel.Thisdefaultdateformatwillbeappliedtoallfieldmappingsunlessitisoverriddenatthefieldlevel.

<mappingdate-format="MM-dd-yyyyHH:mm:ss"><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><field><a>dateString</a><b>dateObject</b></field></mapping>

Adefaultdateformatcanalsobespecifiedattheverytopmappingslevel.Thisdefaultdateformatwillbeappliedtoallfieldmapppingsunlessitisoverriddenatalowerlevel

<mappings><configuration><date-format>MM/dd/yyyyHH:mm</date-format></configuration><mappingwildcard="true"><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><field><a>dateString</a><b>dateObject</b></field></mapping><mapping><class-a>com.github.dozermapper.core.vo.SomeObject</class-a><class-b>com.github.dozermapper.core.vo.SomeOtherObject</class-b><field><a>srcField</a><b>destField</b></field></mapping></mappings>

StringtoDate

42

CollectionandArrayMappingDozerautomaticallymapsbetweencollectiontypesandautomaticallyperformsanytypeconversion.Eachelementinthesourcecollectionismappedtoanelementinthedestobject.Hintsareusedtospecifywhattypeofobjectsarecreatedinthedestinationcollection.ThefollowingcollectionmappingisautomaticallyhandledbyDozer:(Theseareallbi-directional)

ListtoList

ListtoArray

ArraytoArray

SettoSet

SettoArray

SettoList

UsingHintsforCollectionMapping

HintsarenotrequiredifyouareusingJDK1.5GenericsorArraysbecausethetypescanbeautodetectedbyDozer.ButifyouarenotusinggenericsorArrays,toconvertaCollection/ArraytoaCollection/ArraywithdifferenttypeobjectsyoucanspecifyaHinttoletDozerknowwhattypeofobjectsyouwantcreatedinthedestinationlist.IfaHintisnotspecifiedforthedestinationfield,thenthedestinationCollectionwillbepopulatedwithobjectsthatarethesametypeastheelementsinthesrcCollection.

<!--convertingTheFirstSubClassListtoTheFirstSubClassPrimeList--><field><a>hintList</a><b>hintList</b><b-hint>com.github.dozermapper.core.vo.TheFirstSubClassPrime</b-hint></field>

BelowisasummaryofthemappinglogicusedwhenmappingArrays,Sets,andLists.Thisgivesabreakdownofwhathappenswhenhintsareorarenotused.

ListtoList

**DestHintreq’d:NO

DestHintallowed:YES

Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource

Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type

ArraytoList

**DestHintreq’d:NO

DestHintallowed:YES

Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource

Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type

ListtoArray

CollectionsandArrays

43

**DestHintreq’d:NO

DestHintallowed:YES

Ifnodesthintspecified:Destarraywillcontaindatatypesdefinedbythearray

Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type(onlyifObjectArray)

ArraytoArray

**DestHintreq’d:NO

DestHintallowed:YES

Ifnodesthintspecified:Destarraywillcontaindatatypesdefinedbythearray

Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type(onlyifObjectArray)

SettoSet

**DestHintreq’d:NO

DestHintallowed:YES

Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource

Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type

ArraytoSet

**DestHintreq’d:NO

DestHintallowed:YES

Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource

Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type

SettoArray

**DestHintreq’d:NO

DestHintallowed:YES

Ifnodesthintspecified:Destarraywillcontaindatatypesdefinedbythearray

Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type(onlyifObjectArray)

ListtoSet

**DestHintreq’d:NO

DestHintallowed:YES

Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource

Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type

SettoList

**DestHintreq’d:NO

DestHintallowed:YES

Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource

Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type

CollectionsandArrays

44

UsingJDK1.5GenericsforCollectionMappingHintsarenotrequiredwhenJDK1.5Genericsareused.ToconvertaCollection/ArraytoaCollection/Arraywithdifferenttypeobjectsdozercandetermineparameterizedtypesatruntime.

publicclassUserGroup{

privateSet<User>users;

publicSet<User>getUsers(){returnusers;}

publicvoidsetUsers(Set<User>aUsers){users=aUsers;}

}publicclassUserGroupPrime{

privateList<UserPrime>users;

publicList<UserPrime>getUsers(){returnusers;}

publicvoidsetUsers(List<UserPrime>aUsers){users=aUsers;}

}

ObjectArraytoList(bi-directional)

WhenconvertinganObjectarraytoaList,bydefaultthedestinationListwillcontainthesamedatatypeasthesourceArray.

<!--changinganInteger[]toListandbackagain--><field><a>arrayForLists</a><b>listForArray</b></field>

Useahintfordatatypeconversion.Becauseahintisspecified,thedestinationListwillcontainStringelementsinsteadofIntegers.

<!--changinganInteger[]toListandbackagain--><field><a>arrayForLists</a><b>listForArray</b><b-hint>java.lang.String</b-hint></field>

PrimitiveArraytoPrimitiveArray(bi-directional)

WhenconvertinganObjectarraytoanArray,bydefaultthedestinationArraywillcontainthesamedatatypeasthesourceArray.

<!--convertingint[]toint[]bynameonly-->

CollectionsandArrays

45

<field><a>anArray</a><b>theMappedArray</b></field>

Cumulativevs.Non-CumulativeListMapping(bi-directional)

IfyouaremappingtoaClasswhichhasalreadybeeninitialized,dozerwilleither'add'or'update'objectstoyourList.IfyourListorSetalreadyhasobjectsinitdozerchecksthemappedList,Set,orArrayandcallsthecontains()methodtodetermineifitneedsto'add'or'update'.Thisisdeterminedusingtherelationship-typeattributeonthefieldtag.Thedefaultis'cumulative'.relationship-typecanbespecifedatthefieldmapping,classmapping,orglobalconfigurationlevel.

globalconfigurationlevel….

<mappings><configuration><relationship-type>non-cumulative</relationship-type></configuration></mappings>

classmappinglevel….

<mappings><mappingrelationship-type="non-cumulative"><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><field><a>someList</a><b>someList</b></field></mapping></mappings>

fieldmappinglevel….

<!--objectswillalwaysbeaddedtoanexistingList--><fieldrelationship-type="cumulative"><a>hintList</a><b>hintList</b><a-hint>com.github.dozermapper.core.vo.TheFirstSubClass</a-hint><b-hint>com.github.dozermapper.core.vo.TheFirstSubClassPrime</b-hint></field>

<!--objectswillupdatedifalreadyexistinList,addediftheyarenotpresent--><fieldrelationship-type="non-cumulative"><a>unequalNamedList</a><b>theMappedUnequallyNamedList</b></field>

Note:ifyoudonotdefinecustomequals()andhashCode()methodsnon-cumulativeoptionwillnotfunctionproperly,asDozerwillfailtodetermineobjectequalityandwillrelyonJDKgeneratedobjectIds.Indefaultcasetwoinstancesofaclassarealwaystreatedasdifferentandupdatewillnotoccure.

RemovingOrphans

CollectionsandArrays

46

Orphansareelementswhichexistinadestinationcollectionthatdidnotexistwithinthesourcecollection.Dozerwillremoveorphansbycallingthe'remove'methodonactualorphansoftheunderlyingdestinationcollection;itwillnotclearall.Todetermineelementswhichareorphansdozerusesthecontains()methodtocheckiftheresultscontainsorphans.Thedefaultsettingvalueisfalse.

<!--orphanobjectswillalwaysberemovedfromanexistingdestinationList--><fieldremove-orphans="true"><a>srcList</a><b>destList</b></field>

CollectionsandArrays

47

MapBackedPropertyMapping

MaptoMap

Dozerwillmapajava.util.Maptoajava.util.Map.Iftherearecomplextypeswithhintsitwilldodeeprecursionmappingaswell.Ifthedestinationmapexistsitwilladdelementstotheexistingmap.

<mapping><class-a>com.github.dozermapper.core.vo.map.MapToMap</class-a><class-b>com.github.dozermapper.core.vo.map.MapToMapPrime</class-b><field><a>standardMapWithHint</a><b>standardMapWithHint</b><a-hint>com.github.dozermapper.core.vo.TestObject</a-hint><b-hint>com.github.dozermapper.core.vo.TestObjectPrime</b-hint></field></mapping>

MappingFieldLevelPropertiestoajava.util.MaporaCustomMapwithuniqueGet/Setmethods

Dozersupportsmappingmapbackedpropertiesatthefieldlevel.Themapcaneitherimplementthejava.util.MapInterfaceorbeacustommapwithasetofuniqueGet/Setmethods.

InthisexampleFieldAisabasicStringanditismappedtoFieldBwhichisaHashMap.ThekeyintheHashMapwillbe"stringProperty"(theattributename)andthevaluewillbewhatevervalueisstoredinthatattribute.

<mapping><class-a>com.github.dozermapper.core.vo.map.PropertyToMap</class-a><class-b>com.github.dozermapper.core.vo.map.MapToProperty</class-b><field><a>stringProperty</a><b>hashMap</b></field></mapping>

ThisexampleshowsFieldAisabasicStringanditismappedtoFieldBwhichisaHashMap.ThekeyintheHashMapwillbe"myStringProperty"andthevaluewillbewhatevervalueisstoredinthatattribute.AlsonoticethatFieldAhasauniquesetter()methodname.

<mapping><class-a>com.github.dozermapper.core.vo.map.PropertyToMap</class-a><class-b>com.github.dozermapper.core.vo.map.MapToProperty</class-b><field><aset-method="addStringProperty2">stringProperty2</a><bkey="myStringProperty">hashMap</b></field></mapping>

ThisexampleshowsFieldAisabasicStringanditismappedtoFieldBwhichisacustommap.Thekeyinthecustommapwillbe"myCustomProperty"andthevaluewillbewhatevervalueisstoredinthatattribute.NoticethatFieldBhasuniquemapgetter()andmapsetter()methodnames.IfyouareusingacustommapyoumustexplicitlysetthemapGet/Setmethodnames.AdestinationhintcanalsobeprovidedifyourcustommapimplementsanInterfaceorisanAbstractclass.

MapBackedPropertyMapping

48

<mapping><class-a>com.github.dozermapper.core.vo.map.PropertyToMap</class-a><class-b>com.github.dozermapper.core.vo.map.MapToProperty</class-b><field><a>stringProperty3</a><bmap-get-method="getValue"map-set-method="putValue"key="myCustomProperty">customMap</b></field><field><a>stringProperty4</a><bmap-get-method="getValue"map-set-method="putValue"key="myCustomNullProperty">nullCustomMap</b><b-hint>com.github.dozermapper.core.vo.map.CustomMap</b-hint></field><field><a>stringProperty5</a><bmap-get-method="getValue"map-set-method="putValue">customMap</b></field></mapping>

MappingClassLevelPropertiestoajava.util.MaporaCustomMapwithuniqueGet/Setmethods

Dozercanalsomapentirecomplexobjectsdirectlytoajava.util.Maporacustommapobject.Thisexampleshowsthedeclarationofamappingbetweenacomplexobject(PropertyToMap)andajava.util.Map.Whendoingthisyouneedtoexplicitlydefineauniquemap-idforthemapping.Thisisusedwhendeterminingwhichmaptouseatrun-time.EveryattributeonthePropertyToMapclasswillbemappedtothejava.util.Map.YouDONOTneedtoexplicitlydefinethesemappings.Fieldexcludemappingscanbeusedtoexcludefieldsatrun-time.Iftheattributenameisnotthesameasthemapkeyjustsetthekeyattributeforacustomfieldmapping.ThemappingtostringProperty2showsanexampleofthis.

Thesecondexampleshowshowtosetupacustommapobject.Theonlydifferencehereisthatyouneedtoexplicitlydefinemap-set-methodandmap-get-methodvalues.Thesecorrespondtothejava.util.Mapget()andput()methods.

<mappingmap-id="myTestMapping"><class-a>com.github.dozermapper.core.vo.map.PropertyToMap</class-a><class-b>java.util.Map</class-b><field><aset-method="addStringProperty2">stringProperty2</a><bkey="myStringProperty">this</b></field><field-exclude><a>excludeMe</a><b>this</b></field-exclude></mapping><mappingmap-id="myCustomTestMapping"><class-a>com.github.dozermapper.core.vo.map.PropertyToMap</class-a><class-bmap-set-method="putValue"map-get-method="getValue">com.github.dozermapper.core.vo.map.CustomMap</class-b><field><aset-method="addStringProperty2">stringProperty2</a><bkey="myStringProperty">this</b></field><field-exclude><a>excludeMe</a><b>this</b></field-exclude></mapping>

MapBackedPropertyMapping

49

Theexamplebelowshowshowtousethesemappings.Noticethatthefieldmappingsreferenceamap-id.ThefirstfieldmappingwillusethemyTestMappingdefinedmappingandmapaccordingly.Samegoeswiththecustommapping.

<mapping><class-a>com.github.dozermapper.core.vo.map.MapTestObject</class-a><class-b>com.github.dozermapper.core.vo.map.MapTestObjectPrime</class-b><fieldmap-id="myTestMapping"><a>propertyToMap</a><b>propertyToMapMap</b></field><fieldmap-id="myTestMapping"><a>propertyToMapToNullMap</a><b>nullPropertyToMapMap</b><b-hint>java.util.HashMap</b-hint></field><fieldmap-id="myCustomTestMapping"><a>propertyToCustomMap</a><b>propertyToCustomMapMap</b></field></mapping>

TheClassLevelmapbackedmappingscanalsobeusedasastandardmapping.ForthisdozerhasanewAPI.InadditiontothesourceanddestinationclassesyoucannowpassinthemapreferenceId.

//Example1PropertyToMapptm=newPropertyToMap();ptm.setStringProperty("stringPropertyValue");ptm.addStringProperty2("stringProperty2Value");Mapmap=Mapper.map(ptm,HashMap.class,"myTestMapping");

//Example2CustomMapcustomMap=mapper.map(ptm,CustomMap.class,"myCustomTestMapping");

//Example3CustomMapcustom=newCustomMap();custom.putValue("myKey","myValue");Mapper.map(ptm,custom,"myCustomTestMapping");

//Example4-MapBackMapmap=newHashMap();map.put("stringProperty","stringPropertyValue");PropertyToMapproperty=mapper.map(map,PropertyToMap.class,"myTestMapping");assertEquals("stringPropertyValue",property.getStringProperty());

MapBackedPropertyMapping

50

ProxyObjects

Overview

Dozersupportsmappingsdoneonproxyobjects.Thisistypicallythecasewhenusingpersistenceframework,whichsupportssophisticatedfeatureslikelazy-loading.Inthiscaseapplicationisworkingwithfakeobjects,containingtherealobjectsencapsulated.Implementationofproxiesisdependantonthetechnologyyouuse.Generallyspeaking,therearetwopopularlibrariesforcreatingJavaproxies(CglibandJavassist).However,howparticularframeworkmakesusesofthemcouldalsovary.Dozeroffersbydefaultagenericwaytohandlesimpleproxyscenarios,bothJavassistandCglib.Howeveritisstronglyrecommendedtotuneproxyhandlingbehaviorforyourparticularscenario.

Configuration

Proxyimplementationisset-upbymodifyingconfigurationfile.Currently,besidesofdefaultbehavior,HibernateandNo-Proxymodesaresupported.Forthefulllistoftheimplementations,seethelistofcom.github.dozermapper.core.util.DozerProxyResolverinterfaceimplementations.ThelistcouldberetrievedfromJavaDocs.

Incaseyoudonotmapproxiedobjects-useNoProxyresolver,whichimposesminimumperformanceoverhead.

CustomScenarios

Forcustomscenariositispossibletoprovideyourownimplementationofcom.github.dozermapper.core.util.DozerProxyResolverinterface.Itisconfiguredinthesamewayasthestandardclasses.

ProxyObjects

51

CustomConvertersCustomconvertersareusedtoperformcustommappingbetweentwoobjects.IntheConfigurationblock,youcanaddsomeXMLtotellDozertouseacustomconverterforcertainclassAandclassBtypes.WhenacustomconverterisspecifiedforaclassAandclassBcombination,Dozerwillinvokethecustomconvertertoperformthedatamappinginsteadofthestandardmappinglogic.

Yourcustomconvertermustimplementthecom.github.dozermapper.core.CustomConverterinterfaceinorderforDozertoacceptit.Otherwiseanexceptionwillbethrown.

Customconvertersaresharedacrossmappingfiles.ThismeansthatyoucandefinethemonceinamappingfileanditwillbeappliedtoallclassmappingsinothermappingfilesthatmatchtheClassA-ClassBpattern.Intheexamplebelow,wheneverDozercomesacrossamappingwherethesrc/destclassmatchthecustomconverterdefinition,itwillinvokethecustomconverterclassinsteadofperformingthetypicalmapping.

<?xmlversion="1.0"encoding="UTF-8"?><mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttp://dozermapper.github.io/schema/bean-mapping.xsd"><configuration><custom-converters><!--thesearealwaysbi-directional--><convertertype="com.github.dozermapper.core.converters.TestCustomConverter"><class-a>com.github.dozermapper.core.vo.CustomDoubleObject</class-a><class-b>java.lang.Double</class-b></converter><!--YouareresponsibleformappingeverythingbetweenClassAandClassB--><convertertype="com.github.dozermapper.core.converters.TestCustomHashMapConverter"><class-a>com.github.dozermapper.core.vo.TestCustomConverterHashMapObject</class-a><class-b>com.github.dozermapper.core.vo.TestCustomConverterHashMapPrimeObject</class-b></converter></custom-converters></configuration></mappings>

Customconverterscanalsobespecifiedattheindividualfieldlevel.Intheexamplebelow,Dozerwillinvokethecustomconvertertoperformthefieldmapping.

<mapping><class-a>com.github.dozermapper.core.vo.SimpleObj</class-a><class-b>com.github.dozermapper.core.vo.SimpleObjPrime2</class-b><fieldcustom-converter="com.github.dozermapper.core.converters.StringAppendCustomConverter"><a>field1</a><b>field1Prime</b></field></mapping>

Customconverter'instances'canbereusedattheindividualfieldlevel.Intheexamplebelow,Dozerwillinvokethecustomconvertertoperformthefieldmapping.

<mapping><class-a>com.github.dozermapper.core.vo.SimpleObj</class-a><class-b>com.github.dozermapper.core.vo.SimpleObjPrime2</class-b>

CustomConverters

52

<fieldcustom-converter-id="CustomConverterWithId"><a>field1</a><b>field1Prime</b></field></mapping>

CustomConverterinstancescanbeprovidedduringconfigurationofMapperviaDozerBeanMapperBuilder#withCustomConverter(..)method.

<?xmlversion="1.0"encoding="UTF-8"?><beansdefault-lazy-init="false"><beanid="com.github.dozermapper.core.Mapper"class="com.github.dozermapper.core.DozerBeanMapper"><propertyname="mappingFiles"><list><value>dozerBeanMapping.xml</value><value>injectedCustomConverter.xml</value></list></property><propertyname="customConvertersWithId"><map><entrykey="CustomConverterWithId"ref="configurableConverterBeanInstance1"/><entrykey="CustomConverterWithId2"ref="configurableConverterBeanInstance2"/></map></property></bean></beans>

Samplecustomconverterimplementation:

Note:CustomConvertersgetinvokedwhenthesourcevalueisnull,soyouneedtoexplicitlyhandlenullvaluesinyourcustomconverterimplementation.

importcom.github.dozermapper.core.CustomConverter;importcom.github.dozermapper.core.MappingException;

publicclassTestCustomConverterimplementsCustomConverter{

@OverridepublicObjectconvert(ObjectexistingDestinationFieldValue,ObjectsourceFieldValue,Class<?>destinationClass,Class<?>sourceClass){if(sourceFieldValue==null){returnnull;}

CustomDoubleObjectdest;if(sourceinstanceofDouble){//checktoseeiftheobjectalreadyexistsif(destination==null){dest=newCustomDoubleObject();}else{dest=(CustomDoubleObject)destination;}

dest.setTheDouble(((Double)source).doubleValue());

returndest;}elseif(sourceinstanceofCustomDoubleObject){doublesourceObj=((CustomDoubleObject)source).getTheDouble();returnnewDouble(sourceObj);}else{thrownewMappingException("ConverterTestCustomConverter"+"usedincorrectly.Argumentspassedinwere:"+destination+"and"+source);

CustomConverters

53

}}}

CustomConverterscanalsobeinjectedintotheMapperifyouneedtodosomemanipulationwiththembeforetheyareusedindozer.

<?xmlversion="1.0"encoding="UTF-8"?><beansdefault-lazy-init="false"><beanid="com.github.dozermapper.core.Mapper"class="com.github.dozermapper.core.DozerBeanMapper"><propertyname="mappingFiles"><list><value>dozerBeanMapping.xml</value><value>injectedCustomConverter.xml</value></list></property><propertyname="customConverters"><list><refbean="customConverterTest"/></list></property></bean><!--customconverter--><beanid="customConverterTest"class="com.github.dozermapper.core.converters.InjectedCustomConverter"><propertyname="injectedName"><value>injectedName</value></property></bean></beans>

SupportforArrayTypes

YoucanspecifyacustomconverterforArraytypes.Forexample,ifyouwanttouseacustomconverterformappingbetweenanarrayofobjectsandaStringyouwouldusethefollowingmappingnotation.DozergenericallyusesClassLoader.loadClass()whenparsingthemappingfiles.Forarrays,javaexpectstheclassnameinthefollowingformat:[Lcom.github.dozermapper.core.vo.SimpleObj;

<convertertype="com.github.dozermapper.core.converters.StringAppendCustomConverter"><class-a>[Lcom.github.dozermapper.core.vo.SimpleObj;</class-a><class-b>java.lang.String</class-b></converter>

Supportforprimitives

Youcanspecifyacustomconverterforprimitivetypes.Justusetheprimitivewrapperclasswhendefiningthecustomconvertermapping.Inthefollowingexample,DozerwillusethespecifiedcustomconverterwhenmappingbetweenSomeObjectandtheintprimitivetype.NotethatDozerwillalsousethecustomconverterwhenmappingbetweenSomeObjectandtheIntegerwrappertype.

<convertertype="somePackage.SomeCustomConverter"><class-a>somePackage.SomeObject</class-a><class-b>java.lang.Integer</class-b></converter>

ConfigurableCustomConverters

CustomConverters

54

Youcandefineacustomconverter,whichcanbeconfiguredfrommappingsviaconfigurationparameter.InthiscaseyoushouldimplementConfigurableCustomConverterinterfaceinsteadofusualCustomConverter.Configurableconverterhasadditionalattributeprovidedinruntime-param.Parameterisprovidedusingcustom-converter-paramattribute.

<mapping><class-a>com.github.dozermapper.core.vo.BeanA</class-a><class-b>com.github.dozermapper.core.vo.BeanB</class-b><fieldcustom-converter="com.github.dozermapper.core.converters.MathOperationConverter"custom-converter-param="+"><a>amount</a><b>amount</b></field></mapping>

Configurablecustomconvertershouldbeusedwhenyouhavesimilarbehaviourinmanycases,whichcanbeparametrized,butthenumberofcombinationsistoohightodosimpleCustomConvertersubclassing.

importcom.github.dozermapper.core.ConfigurableCustomConverter;importcom.github.dozermapper.core.MappingException;

publicclassMathOperationConverterimplementsConfigurableCustomConverter{

privateStringparameter;

@OverridepublicvoidsetParameter(Stringparameter){this.parameter=parameter;}

@OverridepublicObjectconvert(ObjectexistingDestinationFieldValue,ObjectsourceFieldValue,Class<?>destinationClass,Class<?>sourceClass){Integersource=(Integer)sourceFieldValue;Integerdestination=(Integer)existingDestinationFieldValue;

if("+".equals(parameter)){returndestination.intValue+source.intValue();}

if("-".equals(parameter)){returndestination.intValue-source.intValue();}

thrownewMappingException("ConverterMathOperationConverter"+"usedincorrectly.Argumentspassedinwere:"+destination+","+source+"and"+parameter);}}

NewCustomConverterAPI

WhileprovidinggreatdealofflexibilityCustomConverterAPIdescribedaboveiswrittenonfairlylowlevelofabstraction.Thisresultsinconverter,whichcodeisdifficulttounderstandandtoreuseinotherwaysthanpluggingintoDozermapping.Howeveritisnotuncommonsituationwhenthesameconversionlogicshouldbecalledfromaplaceotherthanbeanmappingframework.versionofDozergetsshippedwithnew-cleanerAPIfordefiningcustomconverter,whichgivesyoumoreobviousAPIwhiletakingawaycertainpartofcontroloftheexecutionsflow.Thefollowingexampledemonstratessimple,yetworkingconverterusingnewAPI.

CustomConverters

55

importcom.github.dozermapper.core.DozerConverter;

publicclassNewDozerConverterextendsDozerConverter<String,Boolean>{

publicNewDozerConverter(){super(String.class,Boolean.class);}

@OverridepublicBooleanconvertTo(Stringsource,Booleandestination){if("yes".equals(source)){returnBoolean.TRUE;}elseif("no".equals(source)){returnBoolean.FALSE;}thrownewIllegalStateException("Unknownvalue!");}

@OverridepublicStringconvertFrom(Booleansource,Stringdestination){if(Boolean.TRUE.equals(source)){return"yes";}elseif(Boolean.FALSE.equals(source)){return"no";}thrownewIllegalStateException("Unknownvalue!");}}

NotethatJava5Genericsaresupportedandyoudonotneedtocastsourceobjecttodesiredtypeaspreviously.

DataStructureConversions

Therearecaseswhereitisrequiredtoperformprogrammaticdatastructureconversion,saycopyeachoddelementinalistasmapkey,buteachevenasmapvalue.InthiscaseitisneededtodefinetransformationofthestructurewhilerelyingonusualDozermappingsupportforindividualvalues.ForthispurposesitispossibletouseMapperAwareinterface,whichinjectscurrentmapperinstanceinsidecustomconverter.

importjava.util.HashMap;importjava.util.List;importjava.util.Map;

importcom.github.dozermapper.core.DozerConverter;importcom.github.dozermapper.core.Mapper;importcom.github.dozermapper.core.MapperAware;

publicclassConverterextendsDozerConverter<List,Map>implementsMapperAware{

privateMappermapper;

publicConverter(){super(List.class,Map.class);}

@OverridepublicvoidsetMapper(Mappermapper){this.mapper=mapper;}

@OverridepublicMapconvertTo(Listsource,Mapdestination){MaporiginalToMapped=newHashMap();for(Sourceitem:source){TargetmappedItem=mapper.map(item,Target.class);

CustomConverters

56

originalToMapped.put(item,mappedItem);}returnoriginalToMapped;}

@OverridepublicListconvertFrom(Mapsource,Listdestination){thrownewIllegalStateException("Notimplemented");}}

CustomConverters

57

CustomBeanFactoriesYoucanconfigureDozertousecustombeanfactoriestocreatenewinstancesofdestinationdataobjectsduringthemappingprocess.BydefaultDozerjustcreatesanewinstanceofanydestinationobjectsusingadefaultconstructor.Thisissufficientformostusecases,butifyouneedmoreflexibilityyoucanspecifyyourownbeanfactoriestoinstantiatethedataobjects.

Yourcustombeanfactorymustimplementthecom.github.dozermapper.core.BeanFactoryinterface.BydefaulttheDozermappingenginewillusethedestinationobjectclassnameforthebeanidwhencallingthefactory.

publicinterfaceBeanFactory{publicObjectcreateBean(Objectsource,ClasssourceClass,StringtargetBeanId,BeanContainerbeanContainer);}

Next,inyourDozermappingfile(s)youjustneedtospecifyabean-factoryxmlattributeforanymappingsthatyouwanttouseacustomfactory.

Inthefollowingexample,theSampleCustomBeanFactorywillbeusedtocreateanynewinstancesoftheInsideTestObjectPrimejavabeandataobject.

<mapping><class-a>com.example.vo.InsideTestObject</class-a><class-bbean-factory="com.example.factories.SomeCustomBeanFactory">com.example.vo.InsideTestObjectPrime</class-b></mapping>

Ifyourfactorylooksupbeansbasedonadifferentidthanclassname,youcanspecifyafactory-bean-idxmlattribute.Atruntimethespecifiedfactory-bean-idwillbepassedtothefactoryinsteadofclassname.

<mapping><class-a>com.example.vo.InsideTestObject</class-a><class-bbean-factory="com.example.factories.SomeCustomBeanFactory"factory-bean-id="someBeanLookupId">com.example.vo.InsideTestObjectPrime</class-b></mapping>

SpecifyingDefaultFactories

Alternatively,beanfactoriescanbespecifiedinthedefaultconfigurationsectionofanyDozermappingfile(s).Thedefaultfactorywouldbeusedforanymappingsinthatfile.

<configuration><stop-on-errors>true</stop-on-errors><wildcard>true</wildcard><bean-factory>com.example.factories.SomeDefaultBeanFactory</bean-factory></configuration>

Beanfactoriescanalsobespecifiedatthemappinglevel.Thespecifiedfactorywouldbeusedforclass-aandclass-b.

<mappingbean-factory="com.example.factories.SomeCustomBeanFactory"><class-a>com.example.vo.TestObject</class-a>

CustomBeanFactories

58

<class-b>com.example.vo.TestObjectPrime</class-b></mapping>

Springbeanfactoryinjection

BeanfactoriescanbeinjectedviaSpringorsimilarinversionofcontroltechniques.

<beans><beanid="com.github.dozermapper.core.Mapper"class="com.github.dozermapper.core.DozerBeanMapper"><propertyname="mappingFiles"><list><value>dozerBeanMapping.xml</value></list></property><propertyname="factories"><map><!--thekeymatchesthenameofthefactoryinthedozerBeanMapping.xmlfile--><entrykey="com.github.dozermapper.core.factories.SampleCustomBeanFactory"><refbean="sampleCustomBeanFactory"/></entry><!--morefactoriescanbesuppliedwithadditionalentry's--></map></property></bean><beanid="sampleCustomBeanFactory"class="com.github.dozermapper.core.factories.SampleCustomBeanFactory"/></beans>

BydefiningyourfactoriesasSpringbeansyoucantheninjectthemintotheMapperinstance.

CustomBeanFactories

59

CustomCreateMethodsYoucanconfigureDozertousecustomstaticcreatemethodstocreatenewinstancesofdestinationdataobjectsduringthemappingprocess.Thiscaneitherbesetatthefieldlevelorclasslevel.

<mapping><class-acreate-method="someCreateMethod">com.github.dozermapper.core.vo.InsideTestObject</class-a><class-b>com.github.dozermapper.core.vo.InsideTestObjectPrime</class-b><field><a>label</a><b>labelPrime</b></field></mapping>

SpecifyingacustomcreatemethodattheFieldlevel….

<mapping><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><field><a>createMethodType</a><bcreate-method="someCreateMethod">createMethodType</b></field></mapping>

Itisalsopossibletoreferencedifferentclasswithstaticfactorymethod.Thisisdonebyprovidingfullyqualifiedtypenameandmethodnameseparatedbydot.

<bcreate-method="com.github.dozermapper.core.factory.Factory.create">field</b>

CustomCreateMethods

60

Customget()set()Methods

Mappingafieldwithnoget()orset()methods

Usetheattributeis-accessibletodeclarethatthefieldcanbeaccesseddirectly.Dozerisabletoaccessprivatepropertiesthatdonothavegetterorsettermethods.

<field><a>fieldAccessible</a><bis-accessible="true">fieldAccessible</b></field>

CustomSet()andGet()methods(bi-directional)

Forthosebeansthatmighthaveunorthodoxgetterandsettermethods,Dozersupportuserspecifiedsetterandgettermethods.Tomakeabi-directionalmappinginthiscase,lookatthefollowingexamplebelow.ThesourcefieldinelementAspecifiesacustomsettermethodandgettermethodusingattributes.

<field><aset-method="placeValue"get-method="buildValue">value</a><b>value</b></field>

InthiscasewearemappingaStringtoanArrayListbycallingtheaddIntegerToList()method.Notethatthisisdefinedasaone-wayfieldtypesincewecannotmapanArrayListtoaString.

<!--wecannotmapaArrayListtoaString,hencetheone-waymapping--><fieldtype="one-way"><a>integerStr</a><bset-method="addIntegerToList">integerList</b></field>

OverloadedSet()methods(bi-directional)

Sometimesset()methodscanbeoverloaded.Inordertochosethecorrectoneyoucanaddtheclasstypeasaparameter.

<field><a>overloadGetField</a><bset-method="setOverloadSetField(java.util.Date)">overloadSetField</b></field>

IterateMethodMapping(bi-directional)

Dozeralsosupportsiteratemethodlevelmapping.InthefollowingexampletheListappleComputerswillbeiteratedthroughandforeachobjectthemethodaddComptuerwillbecalled.Anyfieldthatisdenotedastype=iteraterequiresahint.Theget()methodcanreturnanArray,List,orIterator.

<field><a>appleComputers</a><bset-method="addComputer"type="iterate">computers</b>

Customget()set()Methods

61

<b-hint>com.github.dozermapper.core.vo.AppleComputer</b-hint></field>

Belowisanexamplewithiteratemethodsonbothfields.

<field><aset-method="addCar"get-method="myIterateCars"type="iterate">iterateCars</a><bset-method="addIterateCar"type="iterate">iterateCars</b><a-hint>com.github.dozermapper.core.vo.Car</a-hint><b-hint>com.github.dozermapper.core.vo.Car</b-hint></field>

Customget()set()Methods

62

ExpressionLanguage

Usage

Dozerprovidesoptionalsupportforstandardjavaexpressionlanguage(javax.el).

Currentsupportforexpressionsisstart-uptimeonly.Expressionsarenotresolvedduringeachmapping,butratherduringmappingloadingtime.EachattributeornodevaluecancontainavalidELexpression${}.

DozersupportsanyELimplementationwrittenagainstjavax.elstandardAPI.Functionalityistestedwith'glassfish'internally,butotherELprovidersshouldworkaswell.

Youcandefineglobalvariablesforthemapperinvariablesconfigurationblock.

<configuration><wildcard>true</wildcard><variables><variablename="type_name">com.github.dozermapper.core.sample.MyType</variable></variables></configuration><mapping><class-a>${type_name}</class-a><class-b>com.github.dozermapper.core.sample.OtherType</class-b></mapping>

Enabling

ELsupportisanoptionalfeature.Toenableit,youmustaddthebelowdependenciestoyourclasspath:

<dependency><groupId>javax.el</groupId><artifactId>javax.el-api</artifactId><version>3.0.0</version></dependency><dependency><groupId>org.glassfish</groupId><artifactId>javax.el</artifactId><version>3.0.0</version></dependency>

ItisthisenabledontheMapperbythebelowfluentconstruct:

Mappermapper=DozerBeanMapperBuilder.create().withMappingFiles(mappingFiles).withELEngine(newDefaultELEngine()).build();

ExpressionLanguage

63

LoggingTheloggingfacadeframeworkinDozerisSLF4J.ItreplacedCommonsLogging,whichwasusedinprojectpreviouslyuntilversion5.3.

PleaserefertoSLF4JDocumentationformoreinformationonsettingupandconfiguringdifferentloggingimplementations.

Logging

64

EventListeningByimplementingtheEventListenerinterfacedozerallowsyoutolistento4differentevents:

mappingStarted

mappingFinished

preWritingDestinationValue

postWritingDestinationValue

AnEventobjectispassedintothesecallbackmethodswhichstoresinformationabouttheClassMap,FieldMap,sourceobject,destinationobject,anddestinationvalue.ThiswillallowyoutoextendDozerandmanipulatemappedobjectsatrun-time.Theinterfaceisshownbelow:

publicinterfaceEventListener{

publicvoidonMappingStarted(Eventevent);

publicvoidonPreWritingDestinationValue(Eventevent);

publicvoidonPostWritingDestinationValue(Eventevent);

publicvoidonMappingFinished(Eventevent);}

ThelistenersthatyoucreatecanbeinjectedintotheMapperusinganIOClikeSpringorsetdirectlyduringMapperinstanceconfigurationusingDozerBeanMapperBuilder#withEventListener(..)method.BelowisanexampleusingSpringtoinjectaneventlistener:

<?xmlversion="1.0"encoding="UTF-8"?><beansdefault-lazy-init="false"><beanid="EventMapper"class="com.github.dozermapper.core.DozerBeanMapper"><propertyname="mappingFiles"><list><value>dozerBeanMapping.xml</value></list></property><propertyname="eventListeners"><list><refbean="eventTestListener"/></list></property></bean><beanid="eventTestListener"class="com.github.dozermapper.core.event.EventTestListener"/></beans>

EventListening

65

QueryingmappingmetadataThissectionwillcoverthemappingmetadatainterface.Itprovideseasytouseread-onlyaccesstoallimportantpropertiesoraspectsofthecurrentlyactivemappingdefinitions.

Thefollowingsectionswillgivesomecodeexampleshowtousethemappingqueryinterfaces.Themostimportantinterfaceinthewholeprocessiscom.github.dozermapper.core.metadata.MappingMetadata.AninstancecanbeacquiredbycallingthegetMappingMetadata()methodoftheMapperinstance.

Considerthefollowingmappingfile:

<?xmlversion="1.0"encoding="UTF-8"?><mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttp://dozermapper.github.io/schema/bean-mapping.xsd"><mapping><class-a>com.github.dozermapper.core.vo.ClassA</class-a><class-b>com.github.dozermapper.core.vo.ClassB</class-b><field><a>fieldA</a><b>fieldB</b></field></mapping></mappings>

Tobeginqueryingthemappingdefinitionsthefollowingcodeisneeded:

Mappermapper=DozerBeanMapperBuilder.create().withMappingFiles(listOfFiles).build();MappingMetadatamapMetadata=mapper.getMappingMetadata();

NowthatareferencetoMappingMetadataisobtainedwecanstartqueryingforacertainclassmappingdefinition:

try{ClassMappingMetadataclassMappingMetadata=mapMetadata.getClassMapping(ClassA.class,ClassB.class);}catch(MetadataLookupExceptione){//couldn'tfindit}

WhenholdingareferencetoaClassMappingMetadatainterface,queriesforindividualfieldmappingscanbeexecuted:

try{FieldMappingMetadatafieldMetadata=classMetadata.getFieldMappingBySource("fieldA");//Destination:fieldBSystem.out.println("Destination:"+fieldMetadata.getDestinationName());}catch(MetadataLookupExceptione){//couldn'tfindit}

ForextensivedocumentationonthedifferentinterfacespleaserefertotheJavaDoc.

MetadataQueryInterface

66

MetadataQueryInterface

67

SpringFrameworkIntegrationWeprovidethedozer-spring4forintegratingspringapplication.IfyouareusingApacheMaven,simplycopy-pastethisdependencytoyourproject.

pom.xml

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>{dozer-version}</version></dependency><dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-spring4</artifactId><version>{dozer-version}</version></dependency>

Configuration

AddtheDozerBeanMapperFactoryBeantoyourSpringconfigurationfile.ThemappingFilespropertyiswhereyoushouldspecifyanycustomdozermappingfilesthatyouhavecreated.Thislistcanbeemptyifyoudon’thaveanycustommappings.Itisalsopossibletosetcustomeventlistenersandbeanfactories.

Important

YoushoulddefinetheDozermapperbeanisdefinedassingleton="true".YoushouldconfiguretheMapperinstance(s)thiswaysothatyoudonothavetoreloadandreinitializethemappingfilesforeachindividualmappingduringthelifecycleofyourapp.Reinitializingthemappingfilesforeachmappingwouldbeinefficientandunnecessary.TheDozerBeanMapperclassisthreadsafe.

XMLbasedconfiguration

NotethatthisFactoryBeansupportsSpringResources,whichmeansthatyoucouldloadmappingXmlfilesbyclasspathmaskforexample.

<beanid="dozerMapper"class="com.github.dozermapper.spring.DozerBeanMapperFactoryBean"><propertyname="mappingFiles"value="classpath*:/*mapping.xml"/><propertyname="customConverters"><list><beanclass="com.github.dozermapper.core.converters.CustomConverter"/></list></property><propertyname="eventListeners"><list><beanclass="com.github.dozermapper.core.listeners.EventListener"/></list></property><propertyname="factories"><map><entrykey="id"value-ref="bean-factory-ref"/></map></property></bean>

Alternatively,youcandefinetheDozerBeanMapperusingthedozernamespaceasfollow:

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dozer="http://dozermapper.github.io/schema/dozer-spring"

SpringIntegration

68

xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://dozermapper.github.io/schema/dozer-springhttps://dozermapper.github.io/schema/dozer-spring.xsd">

<dozer:mapperid="dozerMapper"/>

</beans>

Javabasedconfiguration

WhenusingJavaconfiguration,beandefinitionisasfollows:

@ConfigurationpublicclassDozerConfig{@BeanpublicDozerBeanMapperFactoryBeandozerMapper(ResourcePatternResolverresourcePatternResolver)throwsIOException{DozerBeanMapperFactoryBeanfactoryBean=newDozerBeanMapperFactoryBean();factoryBean.setMappingFiles(resourcePatternResolver.getResources("classpath*:/*mapping.xml"));//...returnfactoryBean;}}

Howtouseinyourapplication

UsingSpringtoretrievetheDozerMapper……

Look-upbasedusage

YoucanusetheDozerMapperthatlookedupfromtheSpringApplicationContext(BeanFactory).

MapperdozerMapper=applicationContext.getBean("dozerMapper",Mapper.class);DestinationObjectdestObject=dozerMapper.map(sourceObject,DestinationObject.class);

Injectionbasedusage

Alternatively,youcanusetheDozerMapperthatinjectedtoyourcomponentbySpringDIcontainer.

@ComponentpublicclassYourComponent{privatefinalMapperdozerMapper;publicYourComponent(MapperdozerMapper){this.dozerMapper=dozerMapper;}publicvoidanyMethod(){//...DestinationObjectdestObject=dozerMapper.map(sourceObject,DestinationObject.class);//...}}

HowtouseinSpringBootApplication

PleaseseeSpringBootIntegrationsection.

SpringIntegration

69

SpringIntegration

70

SpringBootIntegrationWeprovidethedozer-spring-boot-starterforintegratingspringbootapplicationsince6.2.0.IfyouareusingApacheMaven,simplycopy-pastethisdependencytoyourproject.

Note FordetailsforSpringFramewrokIntegration,pleaseseehere.

pom.xml

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-spring-boot-starter</artifactId><version>{dozer-version}</version></dependency>

Youcanspecifyanycustomdozermappingfilesinyourapplicationpropertiesoryml.

application.properties

dozer.mapping-files=classpath*:/*mapping.xml

application.yml

dozer:mapping-files:classpath*:/*mapping.xml

SpringBootIntegration

71

3rdPartyObjectFactoriesDozersupportsmappingofplainJavaobjectstoframeworksthatrequireinstantiationofobjectsviacertainconventionofcallingfactorymethods.Toreproducetheexpectedbehaviorcustombeanfactoriesshouldbeused.

MappingJAXBObjects

DozerhassupportformappingPOJOstoJAXBobjects.UsetheJAXBBeanFactoryforanyJAXBobjectsyouwantcreate.

<mapping><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-bbean-factory="com.github.dozermapper.core.factory.JAXBBeanFactory">com.github.dozermapper.core.vo.jaxb.employee.Employee</class-b><field><a>name</a><b>firstName</b></field><field><a>street</a><b>address.street</b></field></mapping>

JAXB

72

FrequentlyAskedQuestions

Common

Whattypesofdataobjectsaresupported?

WillDozerautomaticallyperformdatatypeconversions?

DoesDozerautomaticallymapfieldswithmatchingpropertynames?

IsDozerrecursive?

Willthegetterandsettermethodsbeinvokedwhenfieldsaremapped?

AreCollectionsandArrayssupported?

AreMaptypeobjects(i.eHashMap)supported?

Areabstractclasses,inheritance,andinterfacemappingsupported?

CanDozerbeconfiguredviaSpring?

WhichtypesofdatamappingsdoIneedacustomxmlmappingdefinitionfor?

Ifmysrcanddestobjecthaveallmatchingattributenames,doIneedtospecifyanyxmlmappingdefinitionsatall?

Formappingsthatrequireanxmlmappingdefinition,isthemappingdefinitionbi-directional,ordoIneed2xmldefinitionsifIneedtomapthetwoobjectsbothways?

Howarethecustomxmlmappingfilesloaded?

CanIloadamappingfilethatisnotintheclasspath?

HowcanItellifDozerisinitializingcorrectlyandloadingmyxmlmappingfiles?

HowdoesDozerperform?

WhichJDKversionsaresupported?

IsDozerinthemavenrepository?

IsDozergoodfortheenvironment?

Advanced

CanIimplementcustommappinglogicbetween2datatypesandhaveDozerinvokethiscustomlogicwhenit’sperformingmappings?

CanImaponefieldintoanotherfieldthatisnestednlayersdeepinthedestinationobject?

HowdoImapmultiplefieldstoasinglefield?

IfIammappingdataobjectsthathavebi-directionalrelationships,willitresultinaninfiniteloopandeventualstackoverflowerror?

HowdoImapanobjectcontainedinacollectiontoafield?

HowdoImapaComplexobjecttoaHashMapandviceversa?

HowdoImapfieldsthatdon’thavecorrespondinggetter/settermethods?

FAQ

73

Someofmydataobjectsdon’thavepublicconstructors.DoesDozersupportthisusecase?

DoesDozersupportJDK1.5enums?

DoesDozersupportJAXBgenerateddataobjects?

IsthereanEclipsepluginorvisualeditorforDozer?

Whenmappingcollections,howdoItellDozerwhattypeofdataobjectsIwantinthedestinationcollection?

HowcanItellDozertobypassmappingnulloremptystringvalues?

Tips,Tricks,andSuggestions

ShouldIencapsulatelogicthatcopiesdatabetweenobjects?

ShouldIwriteunittestsfordatamappinglogicthatIuseDozertoperform?

ShouldtheDozermapperbeconfiguredasaSingleton?

Isitbettertohave1largexmlmappingfileortohavemultiplesmallermappingfiles?

WhatarethebestwaystodebugDozer?

Whatisthebestwaytosetuptheglobalconfiguration?

Whatisthebestwaytosubmitabug,featurerequest,orpatch?

Answers

Whattypesofdataobjectsaresupported?

Dozerusesreflectiontoaccessdataobjectproperties,soitisdesignedtoworkwithdataobjectsthathavecorrespondinggetterandsettermethodsforitsfields.Forexample,adataobjectthathasafieldnamed"message"shouldhavegetMessageandsetMessagemethods.Dataobjectsthatdon’tfollowthispatternarealsosupported,butwillmostlikelyrequireacustommappingdefinition.Fortheseunorthodoxdataobjects,youcantellDozertodirectlyaccessfields(includingprivate)and/orexplicitlyspecifywhichget/setmethodstouse.

WillDozerautomaticallyperformdatatypeconversions?

Yes.Mostscenariosaresupportedoutofthebox.Theseincludeprimitives,JavaWrapperObjects,Numbersubclasses,Dates,Calendar,Collections,Arrays,Maps,andComplextypes

DoesDozerautomaticallymapfieldswithmatchingpropertynames?

Yes.Allfieldswithmatchingpropertynamesareimplicitlymapped.Itwouldbeatypicalusage,butyoucouldsuppressthisbehaviorbysettingwilcard="false".

IsDozerrecursive?

Yes.Dozerrecursivelymapstheentireobjectgraphforallfields.

Willthegetterandsettermethodsbeinvokedwhenfieldsaremapped?

Yes.Youcanbypassthisdefaultbehaviorbyexplicitlyspecifyingis-accessible="true"foranyofyourmappings.Ifis-accessibleisspecified,thefield(includingprivatefields)isaccesseddirectlyandthegetter/settermethodsarebypassed.Itisnotrecommendedthatyousetis-accessible="true",unlessyouaredealingwithanunorthodoxdata

FAQ

74

objectthatdoesnotcontainanygetterorsettermethods.

AreCollectionsandArrayssupported?

Yes.Dozerautomaticallymapsbetweencollectiontypesandautomaticallyperformsanytypeconversion.

AreMaptypeobjects(i.eHashMap)supported?

Yes.AllJavaMapdatatypesaresupportedinadditiontoanyCustommapdatatypes.

Areabstractclasses,inheritance,andinterfacemappingsupported?

Yes.

CanDozerbeconfiguredviaSpring?

Yes.RefertoSpringIntegrationsectionofthedocumentation.

WhichtypesofdatamappingsdoIneedacustomxmlmappingdefinitionfor?

Onlyfieldsthatcan’tbeimplicitlymappedbymatchingonfieldname,needacustomxmlmappingdefinition.Ideally,thevastmajorityofyourfieldmappingscanbeperformedautomaticallyandonlythefewexceptionalcaseswillneedanexplicitfieldmappinginthexmlmappingfile.

Ifmysrcanddestobjecthaveallmatchingattributenames,doIneedtospecifyanyxmlmappingdefinitionsatall?

Nope.Justinvokethemapper.Youdon’tneedanyexplicitxmlmappingentriesforthiscombinationofsourceanddestinationobject.

Formappingsthatrequireanxmlmappingdefinition,isthemappingdefinitionbi-directional,ordoIneed2xmldefinitionsifIneedtomapthetwoobjectsbothways?

Allmappingdefinitionsarebi-directional,soyouonlyneedonemappingdefinition.Youcanmapa-→bandb-→ausingthissinglemappingdefinition.

Howarethecustomxmlmappingfilesloaded?

Dozerwillsearchtheentireclasspathlookingforthespecifiedfile(s).

CanIloadamappingfilethatisnotintheclasspath?

Yes,youcanloadfilesfromoutsidetheclasspathbyprepending"file:"totheresourcename.Ex)"file:c:\somedozermapping.xml"

HowcanItellifDozerisinitializingcorrectlyandloadingmyxmlmappingfiles?

Setthe-Ddozer.debugsystemproperty.Ifthisisset,DozerinitializationinformationisalsosenttoSystem.out.Ifyouarefamiliarwithlog4j,thisissimilartothe-Dlog4j.debugsystemproperty

FAQ

75

HowdoesDozerperform?

WebelieveDozerperformsverywellandperformanceisahighpriorityforus.Wehavespentasignificantamountoftimeprofilingthecodeandoptimizingbottlenecks.

Performanceisgoingtodependonthecomplexityoftheusecaseandthenumberoffieldsmapped.Inourperformancetestsfor"average"mappingscenarios,theclassmappingtimesvaryfrom1/8ofamillisecondto2milliseconds.Thisroughlyequatesto50-450fieldmappingspermillisecond.However,thenumberofvariablesinanydecentbenchmarkmakesitalmostimpossibletotransfertheseresultsintoreasonableconclusionsabouttheperformanceofyourownapplication.Yourapplicationisdifferentandyouwillhaveuniqueusecases.

Dozerhasbeensuccessfullyimplementedonlarge,veryhightransactionalenterprisesystems,withoutanyresultingperformanceissues.Butwealwaysrecommendthatyourunperformancetestsonyourapplicationtodeterminetheactualperformancecostswithinyoursystem.Youcandecideforyourselfwhetherthosecostsareacceptableinthecontextoftheentiresystem.

WhichJDKversionsaresupported?

JDK1.8andabove.

IsDozerinthemavenrepository?

YesandwewillcontinuetodoourbesttogetfuturereleasesofDozeruploadedintotherepository.

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>{dozer-version}</version></dependency>

IsDozergoodfortheenvironment?

Yes,dozerdoesnotburnanyfossilfuelsandiswithintheEPA’srecommendedemissions.

CanIimplementcustommappinglogicbetween2datatypesandhaveDozerinvokethiscustomlogicwhenit’sperformingmappings?

Yes.AveryusefulfeatureprovidedbyDozeristheconceptofcustomconverters.Customconvertersareusedtoperformcustommappingbetweentwoobjects.IntheConfigurationblock,youcanaddsomeXMLtotellDozertouseacustomconverterforcertainclassAandclassBtypes.WhenacustomconverterisspecifiedforaclassAandclassBcombination,Dozerwillinvokethecustomconvertertoperformthedatamappinginsteadofthestandardmappinglogic.

<custom-converters><convertertype="com.github.dozermapper.core.converters.SomeCustomConverter"><class-a>com.github.dozermapper.core.vo.SomeCustomDoubleObject</class-a><class-b>java.lang.Double</class-b></converter></custom-converters>

CanImaponefieldintoanotherfieldthatisnestednlayersdeepinthedestinationobject?

Yes.Dozersupportsdotnotationfornestedfields.Aswithotherdozerfieldmappings,thesearebi-directional.

FAQ

76

<field><a>someNestedObj.someOtherNestedObj.someField</a><b>someOtherField</b></field>

HowdoImapmultiplefieldstoasinglefield?

Dozerdoesn’tcurrentlysupportthis.Andbecauseofthecomplexitiesaroundimplementingit,thisfeatureisnotcurrentlyontheroadmap.Apossiblesolutionwouldbetowrapthemultiplefieldsinacustomcomplextypeandthendefineacustomconverterformappingbetweenthecomplextypeandthesinglefield.Thisway,youcouldhandlethecustomlogicrequiredtomapthethreefieldsintothesingleonewithinthecustomconverter.

IfIammappingdataobjectsthatcontainbi-directionalrelationships,willitresultinaninfiniteloopandeventualstackoverflowerror?

No.Dozerhasbuiltinlogicthatpreventsinfiniteloopsforbi-directionaldataobjectrelationships

HowdoImapanobjectcontainedinacollectiontoafield?

Youwoulduseindexedbasedmapping.

<field><a>usernames[0]</a><b>username1</b></field>

HowdoImapaComplexobjecttoaHashMapandviceversa?

Youcanmapentirecomplexobjectsdirectlytoajava.util.Mapandviceversa.Whendoingthisyouneedtoexplicitlydefineauniquemap-idforthemapping.Thisisusedwhendeterminingwhichmaptouseatrun-time.Everyattributeonthecomplextypewillbemappedtothejava.util.Map.YouDONOTneedtoexplicitlydefinethesemappings.Iftheattributenameisnotthesameasthemapkeyjustsetthekeyattributeforacustomfieldmapping.

<mappingmap-id="myTestMapping"><class-a>com.github.dozermapper.core.vo.map.SomeComplexType</class-a><class-b>java.util.Map</class-b><field><a>stringProperty2</a><bkey="myStringProperty">this</b></field></mapping>

HowdoImapfieldsthatdon’thavecorrespondinggetter/settermethods?

YoucantellDozertodirectlyaccessfields(includingprivatefields)byspecifyingis-accessible="true"

<field><a>fieldA</a><bis-accessible="true">fieldB</b></field>

Someofmydataobjectsdon’thavepublicconstructors.DoesDozersupportthisusecase?

FAQ

77

Yes.Whencreatinganewinstanceofthedestinationobjectifapublicno-argconstructorisnotfound,Dozerwillautodetectaprivateconstructorandusethat.Ifthedataobjectdoesnothaveaprivateconstructor,youcanspecifyacustomBeanFactoryforcreatingnewinstancesofthedestinationobject.

DoesDozersupportJDK1.5enums?

Yes.EnumtoEnummappingisautomaticallyhandled.

DoesDozersupportJAXBgenerateddataobjects?

DozerhassupportformappingPOJOstoJAXBobjects.UsetheJAXBBeanFactoryforanyJAXBobjectsyouwantcreated.

IsthereanEclipsepluginorvisualeditorforDozer?

No,butwethinkitwouldbeagreataddition.Itwouldbeverypowerfultobeabletographicallymap2objectsandhavethecustomxmldefinitionsautogenerated,alongwithbeingabletovisuallyviewamappingdefinition.Ifanyonehasexpertiseincreatingeclipsepluginsandisinterestedonworkingonthisfeature,pleaseletusknow!

Whenmappingcollections,howdoItellDozerwhattypeofdataobjectsIwantinthedestinationcollection?

Hintsaresupportedtohandlethisusecase.HintsarenotrequiredifyouareusingJDK1.5GenericsbecausethetypescanbeautodetectedbyDozer.Butifyouarenotusinggenerics,toconvertaCollection/ArraytoaCollection/ArraywithdifferenttypeobjectsyoucanspecifyaHinttoletDozerknowwhattypeofobjectsyouwantcreatedinthedestinationlist.IfaHintisnotspecifiedforthedestinationfield,thenthedestinationCollectionwillbepopulatedwithobjectsthatarethesametypeastheelementsinthesrcCollection.

<field><a>someList</a><b>otherList</b><b-hint>com.github.dozermapper.core.vo.TheFirstSubClassPrime</b-hint></field>

HowcanItellDozertobypassmappingnulloremptystringvalues?

Youcanbypassthemappingofnullvaluesbyspecifyingmap-null="false".Ifthisisspecified,thedestfieldmappingisbypassedatruntimeandthedestinationvaluesettermethodwillnotbecalledifthesrcvalueisnull.Thiscanbespecifiedatthemappingorclasslevel.

YoucanbypassthemappingofemptyStringvaluesbyspecifyingmap-empty-string="false".Ifthisisspecified,thedestfieldmappingisbypassedatruntimeandthedestinationvaluesettermethodwillnotbecalledifthesrcvalueisanemptyString.Thiscanbespecifiedatthemappingorclasslevel

ShouldIencapsulatelogicthatcopiesdatabetweenobjects?

Itisouropinionthatyoushould.RegardlessofwhetheryouuseDozertoperformdatamappingbetweenobjects,webelievethisisagooddesignpatternthatpromotesreuse,encapsulatestheunderlyingimplementation,andmakesthecodeunittestableinisolation.These"Assembler"interfacesencapsulatethelogicthatisresponsiblefortakingasrcobjectandmappingthedataintoadestobject.Usingassemblertypeofclassesgivesyoutheflexibilityofbeingabletomodifytheunderlyingmappingimplementationwithoutimpactingclientsorthecontract.OneotherimportantbenefitofusingAssemblersisthatitmakeswritingunittestsspecificforthemappingaloteasierandmorefocused.Ifyoueverneedtodetermineifaparticularbugisduetomappingofobjects,itissimpletowriteanAssemblerunittest

FAQ

78

thatreproducestheusecase.Ifyouencapsulateyourdatamappinglogic,youcoulduseDozerformostofmappingsandifyouhavearealcornercase,youhavetheflexibilitytohandcodemappingsforanyobjectsorfields.Forexample,youcouldrunyourmappingthroughDozertomap99%ofyourfieldsandthenhaveamanualmappingforsomeoddballfield.ThiswouldhappenallwithintheAssemblerwithouttheclienthavinganyknowledgeoftheunderlyingimplementation.

Itseemstoworkbestiftheseassemblertypeofclassesare"dumb"andareonlyresponsibleforsimplycopyingdatafromthesourceobjectintothedestinationobject.Anycomplexpostprocessingbusinesslogicthatneedstobeperformedonthedestinationobjectcanbedoneatahigherlevelinclasssesthathavemoreresponsibility.

ThefollowingisasimpleexampleofanassemblertypeclassthatusesDozerforitsunderlyingimplementation.

publicclassSomeAssemblerImplimplementsSomeAssembler{

privateMapperdozerMapper;

publicDestObjectassembleDestObject(SrcObjectsrc){returndozerMapper.map(src,DestObject.class);}

}

ShouldIwriteunittestsfordatamappinglogicthatIuseDozertoperform?

Absolutely.Andofcourse,westronglyrecommendwritingtheunittest(s)first.Evenifyoudon’tuseDozertoperformthedatamappingbetweentwoobjects,thislogicstillneedsisolatedunittests.Datamappinglogic(especiallyhandcoded)iserrorproneandhavingaunittestisinvaluable.Typicallymappingbetweentwoobjectsisrequiredinmultipleareasofasystem,soafocusedunittestofthecentralmappinglogicenablesyoutotestthedatamappinglogicinisolation.Thegreatthingaboutencapsulatingdatamappinglogicandhavingunittestsforthelogicisthatyoucaneasilyswitchouttheunderlyingimplementation.

ForexistingsystemsthatarewantingtomigratetoDozer,werecommendfirstencapsulatinganyexistinghandcodeddatamappingintoanassemblertypeofclassandwriteunittestsforit.ThenswitchoutthehandcodedmappinglogicwithDozerandtheunittestswillbeyoursafetynet.ThemigrationtoDozercanbeincrementalandthisisprobablythebeststrategyforexisitingsystems.

RegardlessofwhetherornotyouuseDozer,unittestingdatamappinglogicistediousandanecessaryevil,butthereisatrickthatmayhelp.Ifyouhaveanassemblerthatsupportsmapping2objectsbi-directionally,inyourunittestyoucandosomethingsimilartothefollowingexample.Thisalsoassumesyouhavedoneagoodjobofimplementingtheequals()methodforyourdataobjects.Theideaisthatifyoumapasourceobjecttoadestinationobjectandthenbackagain,theoriginalsrcobjectshouldequaltheobjectreturnedfromthelastmappingiffieldsweremappedcorrectly.Inthetestcase,youshouldpopulateallthepossiblefieldsintheoriginalsourceobjecttoensurethatallofthefieldsareaccountedforinthemappinglogic.

publicvoidtestAssembleSomeObject()throwsException{SrcObjectsrc=newSrcObject();src.setSomeField("somevalue");src.setSomeOtherField("makesureyousetallthesrcfields"+"withvaluessothatyoufullytestthedatamappings");

DestObjectdest=assembler.assembleDestObject(src);SrcObjectmappedSrc=assermbler.assembleSrcObject(dest);

assertEquals("fieldsnotmappedcorrectly",src,mappedSrc);}

FAQ

79

Itisalsogoodpracticetoverifythatyourassemblerhandlesnullvaluesproperly.Inthefollowingtestcasenoneofthesourcefieldsarepopulated.Iftheassemblerdoesn’tproperlyhandlenullvalues,anexceptionwillbethrownwhentheassemblerisinvoked.

publicvoidtestAssembleSomeObject_NullValues()throwsException{SrcObjectsrc=newSrcObject();

DestObjectdest=assembler.assembleDestObject(src);SrcObjectmappedSrc=assermbler.assembleSrcObject(dest);

assertEquals("fieldsnotmappedcorrectly",src,mappedSrc);}

ShouldtheDozermapperbeconfiguredasaSingleton?

Yes.Mapperinstancesshouldbereusedasmuchaspossible.ForeveryinstanceoftheMapper,themappingfilesareloadedandparsed.YoushouldconfiguretheMapperonceforyourconfigurationandreusethisinstancethroughoutyourapplication.TheMapperimplementationsarethreadsafe.

Isitbettertohave1largexmlmappingfileortohavemultiplesmallermappingfiles?

Werecommendcomponentizingyourmappingfilesinsteadofhaving1largemappingfile.

WhatarethebestwaystodebugDozer?

Youcanspecifythe-Ddozer.debugsystempropertytoviewtheonetimeinitializationinformation.Youwillseeoutputsimilartothefollowing….

dozer:TryingtofindDozerconfigurationfile:dozer.propertiesdozer:UsingURL[file:/local/subversion_projects/dozer/trunk/target/test-classes/dozer.properties]forDozerglobalpropertyconfigurationdozer:ReadingDozerpropertiesfromURL[file:/local/subversion_projects/dozer/trunk/target/test-classes/dozer.properties]dozer:FinishedconfiguringDozerglobalpropertiesdozer:InitializingDozer.Version:${project.version},ThreadName:maindozer:Initializinganewinstanceofthedozerbeanmapper.dozer:Usingthefollowingxmlfilestoloadcustommappingsforthebeanmapperinstance:[fieldAttributeMapping.xml]dozer:Tryingtofindxmlmappingfile:fieldAttributeMapping.xmldozer:UsingURL[file:/local/subversion_projects/dozer/trunk/target/test-classes/fieldAttributeMapping.xml]toloadcustomxmlmappingsdozer:SuccessfullyloadedcustomxmlmappingsfromURL:[file:/local/subversion_projects/dozer/trunk/target/test-classes/fieldAttributeMapping.xml]

Todebugindividualfieldmappingsbetweenclasses,setthelogginglevel"com.github.dozermapper.core.MappingProcessor=DEBUG".Forexample,ifyouareusinglog4jyouwouldaddthefollowingentrytoyourlog4jconfigurationfile"log4j.category.com.github.dozermapper.core.MappingProcessor=DEBUG".ThiswillshowyoueveryfieldmappingthatDozerperformsalongwiththeactualsourceanddestinationvalues.Youwillseeoutputsimilartothefollowing….

MAPPED:SimpleObj.field1-->SimpleObjPrime.field1VALUES:one-->oneMAPID:someMapIdMAPPED:SimpleObj.field2-->SimpleObjPrime.field2VALUES:2-->2MAPID:someMapIdMAPPED:SimpleObj.field3-->SimpleObjPrime.field3VALUES:3-->3MAPID:someMapIdMAPPED:SimpleObj.field4-->SimpleObjPrime.field4VALUES:44.44-->44.44MAPID:someMapIdMAPPED:SimpleObj.field6-->SimpleObjPrime.field6VALUES:

FAQ

80

66-->66MAPID:someMapId

Whatisthebestwaytosetuptheglobalconfiguration?

Werecommendhavingaseparatemappingxmlfileforglobalconfiguration.Youcouldnameitsomethingsimilartodozer-global-configuration.xml.Sampleglobalconfigurationfile……

<?xmlversion="1.0"encoding="UTF-8"?><mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttp://dozermapper.github.io/schema/bean-mapping.xsd"><configuration><stop-on-errors>true</stop-on-errors><date-format>MM/dd/yyyyHH:mm</date-format><wildcard>false</wildcard><custom-converters><convertertype="com.github.dozermapper.core.converters.TestCustomConverter"><class-a>com.github.dozermapper.core.vo.CustomDoubleObject</class-a><class-b>java.lang.Double</class-b></converter></custom-converters></configuration></mappings>

Whatisthebestwaytosubmitabug,featurerequest,orpatch?

Wevalueyoursuggestionsandappreciateeveryonethattakesthetimetosubmitasupportrequest.PleasesubmitallrequestsviaDozer’sGitHubprojectpage

FAQ

81

ExamplesTherearesomesamplemappingfilesunder\{dozer.home}/src/test/resources.ThesemappingfilesareusedbytheDozerunittests.

Examples

82

Migrationfromv5.5.1tov6.0.0Seeforreleasenotes.

1.JDK<1.8supportdropped

DozerisbuiltagainstJavaJDK1.8ONLY.

2.MavenGAV(GroupID,ArtifactandVersion)haschanged:

From:

<dependency><groupId>net.sf.dozer</groupId><artifactId>dozer</artifactId><version>5.5.1</version></dependency>

To:

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>6.0.0</version></dependency>

3.dozer-osgidropped

Younolongerneedtousethebelow,ifyouarerunninginanOSGienvironment:

<dependency><groupId>net.sf.dozer</groupId><artifactId>dozer-osgi</artifactId><version>5.5.1</version></dependency>

Justsimplyusethedozer-core:

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>6.0.0</version></dependency>

v5tov6

83

Migrationfromv6.0.0tov6.1.0Seeforreleasenotes.

1.Mapping.xmlXSDchanged:

From:

<mappingsxmlns="http://dozer.sourceforge.net"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozer.sourceforge.nethttp://dozer.sourceforge.net/schema/beanmapping.xsd">

To:

<mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttps://dozermapper.github.io/schema/bean-mapping.xsd">

2.Dozer-SpringXSDchanged.

From:

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dozer="http://dozer.sourceforge.net/schema/dozer-spring"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://dozer.sourceforge.net/schema/dozer-springhttp://dozer.sourceforge.net/schema/dozer-spring.xsd">

To:

<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dozer="http://dozermapper.github.io/schema/dozer-spring"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://dozermapper.github.io/schema/dozer-springhttps://dozermapper.github.io/schema/dozer-spring.xsd">

3.DozerBeanMapperusageisdeprecated

DirectinstantiationofDozerBeanMapperaswellasitsusageisdeprecated.Thisclasswillbehiddeninversion6.2.PleaseuseMapperwheneveryouneedtomap,andDozerBeanMapperBuildertoconfigurethemapper.

Deprecated:

DozerBeanMappermapper=newDozerBeanMapper();mapper.addMapping(myMappingBuilder);mapper.setMappingFiles(myFiles);

mapper.map(a,b);

Recommended:

v6.0.0tov6.1.0

84

Mappermapper=DozerBeanMapperBuilder.create().withMappingBuilder(myMappingBuilder).withMappingFiles(myFiles).build();

mapper.map(a,b);

4.DozerBeanMapperSingletonWrapperisdeprecated

DozerBeanMapperSingletonWrapperisdeprecatedandplannedforremovalinversion6.2.

DozerprojectdoesnotadvisetouseJVMsingletons.PleaseuseyourDIcontainertomanagesingleinstanceoftheMapperifrequired.ThefollowingcodecanbeusedtocreateaMapperwithdefaultconfiguration:

Mappermapper=DozerBeanMapperBuilder.buildDefault();

5.InternalAPIischanged

DozerismovingawayfromhavingJVM-globalstate.ThismeansthatsomeinternalAPIlikeBeanContainerisnotavailableanymoreviasingletonreferences,i.e.BeanContainer.getInstance()doesnotexist.Ifyouwereusingthisoranyothercodethatisreworked,pleaseletusknow.MostlikelyyoudevelopedDozerModule.Wewouldliketoknowmoreaboutreal-worldusecasestobuildconvenientpublicAPIformodulesdevelopers.

6.org.dozer.BeanFactoryinterfacechanges

Oldsignatureoforg.dozer.BeanFactoryisdeprecatedandwillberemovedinversion6.2.Pleaseusenewmethodofthisinterfacewhencreatingcustombeanfactories.

Deprecated:

ObjectcreateBean(Objectsource,Class<?>sourceClass,StringtargetBeanId)

Recommended:

ObjectcreateBean(Objectsource,Class<?>sourceClass,StringtargetBeanId,BeanContainerbeanContainer)

7.Deprecatedstatsandjmx

Deprecated:

org.dozer.statsorg.dozer.jmx

8.Updateddozer-protopackagename

From:

org.dozer

To:

com.github.dozermapper.protobuf

v6.0.0tov6.1.0

85

9.Updateddozer-springpackagename

From:

org.dozer.spring

To:

com.github.dozermapper.spring

v6.0.0tov6.1.0

86

Migrationfromv6.1.0tov6.2.0Seeforreleasenotes.

1.JMX/Statshasbeenremoved

Asper6.1.0migrationdocs,JMXandStatsweredeprecated.Theyhavenowbeenfullyremoved.

2.dozer.propertieskeyschanged

From:

dozer.cache.converter.by.dest.type.maxsizedozer.cache.super.type.maxsizeorg.dozer.util.DozerClassLoaderorg.dozer.util.DozerProxyResolver

To:

dozer.cache.converter-by-dest-type-maxsizedozer.cache.super-type-maxsizedozer.beans.class-loader-beandozer.beans.proxy-resolver-bean

3.SupportforYAML,SystemPropertiesandEnvironmentvariables

Asaswellasdozer.properties,wealsosupportseveralnewimplementations,suchasYAML,see:-https://github.com/DozerMapper/dozer/tree/6.2.0/core/src/main/java/org/dozer/config/resolvers-https://github.com/DozerMapper/dozer/tree/6.2.0/core/src/main/java/org/dozer/config/processors

4.dozer.el.enabledisdeprecated

Thepropertyfor'dozer.el.enabled'hasbeendeprecated.Instead,youshoulduse:

DefaultELEngineelEngine=newDefaultELEngine();Mappermapper=DozerBeanMapperBuilder.create().withMappingFiles(mappingFiles).withElementReader(newExpressionElementReader(elEngine)).withELEngine(elEngine).build();

5.Springmavenartifactnamehaschanged

From:

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-spring</artifactId><version>6.1.0</version></dependency>

To:

v6.1.0tov6.2.0

87

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-spring4</artifactId><version>6.2.0</version></dependency>

6.Springmavenartifactnamehaschanged

From:

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-proto</artifactId><version>6.1.0</version></dependency>

To:

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-proto3</artifactId><version>6.2.0</version></dependency>

7.Extendedspringbootsupport

dozer-spring-boot-starteranddozer-spring-boot-autoconfigureartifactsaddedtosupportspringbootautoconfigurationfeatures.

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-spring-boot-starter</artifactId><version>6.2.0</version></dependency>

8.dozer.xml.use-jaxb-mapping-enginetousenewJAXB

ThecurrentDozerXMLtoObjectsimplementationusesorg.w3c.dom.Documenttoparsethemodel.Goingforward,theintentionistouseaJAXBmodel.Thisfeatureisnotenabledbydefault,butcanbevia:

dozer.xml.use-jaxb-mapping-engine=true

v6.1.0tov6.2.0

88

Migrationfromv6.2.0tov6.3.0Seeforreleasenotes.

1.Karaf2supportdropped

Askaraf2isnowdeprecatedupstream,andisnotsupportedwithJava9,supportisdropped.

2.ApacheXMLBeanssupportdropped

Asxmlbeansisnowdeprecatedupstream,andisnotsupportedwithJava9,supportisdropped.

3.UberJARnowprovided

MavenGAV

<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>6.3.0</version><classifier>jar-with-dependencies</classifier></dependency>

4.dozer.xml.use-jaxb-mapping-engineenabledbydefault

JAXBisusedbydefault,ifthiscausesissues,itcanbedisabledvia:

-Ddozer.xml.use-jaxb-mapping-engine=false

Andthefollowingisdeprecated:

com.github.dozermapper.core.loader.xml

Infavourof:

com.github.dozermapper.core.builder.xml

5.Updateddozer-corepackagename

From:

org.dozer

To:

com.github.dozermapper.core

6.UpdatedDozerEventListenerpackage/classname

From:

v6.2.0tov6.3.0

89

org.dozer.DozerEventListener

To:

com.github.dozermapper.core.events.EventListener

v6.2.0tov6.3.0

90

PrerequisitesThePlugincurrentlydependson

WTP3.0.2orlatest

Compatibility

PluginissupportedandbeentestedonthefollowingIDEs

Eclipse3.6

RADRSA8.0.1

Installation

TheDozerPlugin-featurecanbeinstalledandupdatedusingtheEclipseUpdateManager.

AddanewUpdate-URL:

http://dozer.sourceforge.net/eclipse-plugin

Selectallrequireddependenciesandinstalltheplugin.

Alternativelyyoucandownloadthepackageatsourceforgeandunzipitinyoureclipseinstallationfolder.YoumighthavetoenablethePluginafterstartingEclipse.ThiscanbedoneatHelp>SoftwareUpdates>ManageConfiguration.

Afterinstallationisdoneyoushouldseealittlereddozer-icononallyourmapping-xmlfiles.

Installation

91

CreatenewMappingfilesThepluginprovidesasimplewizardforcreatingnewmapping-xmlfiles.Anewmapping-xmlfilecanbecreatedusingFile>New>Other>DozerMappingFramework>DozerMappingFile.Selectthecorrectdozerversion(4,DTDor5,XSD)inthewizardandcreatethefile.

ConfiguretheMapping

viaXML

viatheEditor

Usage

92

OpenmappingfileWhenopeningaDozer-mapping-filetheDozer-editorappears.IfyouwanttoedittherawXMLyoucanswitchtothe"source"view.

ContentAssist

Alltheclass-a/class-b,field,get-method,set-method,etc-nodesor-attributesautomaticlyshowcontent-assistpopupswhenpressingctrl+spaceortheconfiguredWTP-XMLcontentassistcharacters.Thesecanbechangedinthepreferences.

viaXML

93

Alltheclass-a/class-b,field,get-method,set-method,etc-nodesor-attributesautomaticlyshowcontent-assistpopupswhenpressingctrl+spaceortheconfiguredWTP-XMLcontentassistcharacters.Thesecanbechangedinthepreferences.

viaXML

94

Validation

TheDozerPluginvalidatestheMappingtofindoutifthemappedclassdoexistandifthemappedfieldsareaccessible.

viaXML

95

SettingglobaldozerconfigurationAllglobalconfigurationvaluescanbesetinthe"GlobalConfiguration"Tab.

Configuringmappings

Everyclassmappingislistedinthe"Mapping"Tab.MappingsofclassesandfieldscanbeaddedbyPopupmenuortheaction-buttonsatthetop.Ontherightsidethemappingscanbeconfigured.EveryAttributeorElementintheXMLfileisshownforediting.

viaEditor

96