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
Top Related