Table of Contents - GitHub Pages · Getting Started Downloading the Distribution If you are using...
Transcript of Table of Contents - GitHub Pages · Getting Started Downloading the Distribution If you are using...
1.1
1.2
1.3
1.3.1
1.4
1.4.1
1.4.2
1.5
1.5.1
1.5.2
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
2.10
2.11
3.1
3.2
3.3
3.4
3.5
4.1
4.2
4.3
TableofContentsIntroduction
WhyMap?
GettingStarted
Usage
MappingsviaXML
viaAnnotations
viaAPI
Configuration
ConfigurationviaXML
ConfigurationviaAPI
DozermappingconceptsMappingClasses
BasicPropertyMapping
InheritanceMapping
ContextBasedMapping
One-WayMapping
CopyingByObjectReference
DeepPropertyMapping
IndexedPropertyMapping
ExcludingFields
AssemblerPattern
Mappingimmutabletypes
Howdoimapatypeof…?Enums
StringtoDate
CollectionsandArrays
MapBackedPropertyMapping
ProxyObjects
Whatifineedtocustomisethemapping?CustomConverters
CustomBeanFactories
CustomCreateMethods
1
4.4
4.5
5.1
5.2
5.3
6.1
6.2
6.3
7.1
7.2
8.1
8.2
8.3
8.4
9.1
9.2
9.3
10.1
10.2
10.2.1
10.2.2
Customget()set()Methods
ExpressionLanguage
ExtraLogging
EventListening
MetadataQueryInterface
3rdPartySpringIntegration
SpringBootIntegration
JAXB
OtherFAQ
Examples
Migrationv5tov6
v6.0.0tov6.1.0
v6.1.0tov6.2.0
v6.2.0tov6.3.0
SchemaMappingXSD
Spring4XSD
User’sGuidePDF
EclipsePluginInstallation
Usage
viaXML
viaEditor
2
3
Dozer
WhatisDozer?DozerisaJavaBeantoJavaBeanmapperthatrecursivelycopiesdatafromoneobjecttoanother.Typically,theseJavaBeanswillbeofdifferentcomplextypes.
Dozersupportssimplepropertymapping,complextypemapping,bi-directionalmapping,implicit-explicitmapping,aswellasrecursivemapping.Thisincludesmappingcollectionattributesthatalsoneedmmappingattheelementlevel.
PleasereadtheaboutpagefordetailedinformationonDozer.
Introduction
4
WhyMap?Amappingframeworkisusefulinalayeredarchitecturewhereyouarecreatinglayersofabstractionbyencapsulatingchangestoparticulardataobjectsvs.propagatingtheseobjectstootherlayers(i.e.externalservicedataobjects,domainobjects,datatransferobjects,internalservicedataobjects).AmappingframeworkisidealforusingwithinMappertypeclassesthatareresponsibleformappingdatafromonedataobjecttoanother.
Fordistributedsystems,asideeffectisthepassingofdomainobjectsbetweendifferentsystems.Typically,youwon’twantinternaldomainobjectsexposedexternallyandwon’tallowforexternaldomainobjectstobleedintoyoursystem.
Mappingbetweendataobjectshasbeentraditionallyaddressedbyhandcodingvalueobjectassemblers(orconverters)thatcopydatabetweentheobjects.Mostprogrammerswilldevelopsomesortofcustommappingframeworkandspendcountlesshoursandthousandsoflinesofcodemappingtoandfromtheirdifferentdataobject.
Agenericmappingframeworksolvestheseproblems.Dozerisanopensourcemappingframeworkthatisrobust,generic,flexible,reusable,andconfigurable.
Dataobjectmappingisanimportantpartoflayeredserviceorientedarchitectures.Pickandchoosethelayersyouusemappingcarefully.Donotgooverboardasthereismaintenanceandperformancecostsassociatedwithmappingdataobjectsbetweenlayers.
ParallelObjectHierarchies
Therecouldbedifferentreasonsofwhyapplicationshouldsupportparallelobjecthierarhchies.Tonameafew:
IntegrationwithExternalCode
SerializationRequirements
FrameworkIntegration
SeparationofArchitecturalLayers
Insomecasesitisefficienttoguardyourcodebasefromfrequentlychangingobjecthierarchy,whichyoudonotcontroldirectly.InthiscaseDozerservesasabridgebetweenapplicationandexternalobjects.AsmappingisperformedinreflectivemannernotallchangesbreakyourAPI.ForexampleifobjectchangesfromNumbertoStringthecodewillkeepworkingasthisisresolvedautomatically.
SomeframeworksimposeSerializationconstraints,whichdoesnotallowsendinganyJavaobjectsthroughthewire.OneofthepopularexamplesisGoogleWebToolkit(GWT)framework,whichrestrictsdevelopertosendingonlyobjectscompiledtoJavaScriptandmarkedasSerializable.DozerhelpstoconvertRichDomainModeltoPresentationModel,whichsatisfiesGWTserializationrequirements.
DozerintegratesnicelywithframeworksuseJAXBimplementations.Withhelpofprovidedfactoryclasses,conversionbetweendomainmodelandXmlobjectsisdefinedinthesamewayasplainobjecttoobjectmappings.
Incomplexenterpriseapplicationitisoftenvaluabletoseparatedesigntoseveralarchitecturallayers.Eachofthemwouldresideonitsownabstractionlevel.Atypicalsimplifiedexamplewouldbepresentation,domainandpersistencelayers.EachofthislayerscouldhaveownsetofJavaBeansrepresentingdatarelevantforthislayer.Itisnotnecessarythatalldatawilltraveltotheupperlevelsofarchitecture.Forexamplethesamedomainobjectcouldhavedifferentmappingsdependantofthepresentationlayerrequirements.
WhyMap?
5
WhyMap?
6
GettingStarted
DownloadingtheDistribution
IfyouareusingApacheMaven,simplycopy-pastethisdependencytoyourproject.
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>6.4.0</version></dependency>
1stMapping
Foryourfirstmapping,letsassumethatthetwodataobjectsshareallcommonattributenames.
Mappermapper=DozerBeanMapperBuilder.buildDefault();DestinationObjectdestObject=mapper.map(sourceObject,DestinationObject.class);
AfterperformingtheDozermapping,theresultwillbeanewinstanceofthedestinationobjectthatcontainsvaluesforallfieldsthathavethesamefieldnameasthesourceobject.Ifanyofthemappedattributesareofdifferentdatatypes,theDozermappingenginewillautomaticallyperformdatatypeconversion.AtthispointyouhavecompletedyourfirstDozermapping.Latersectionswillgooverhowtospecifycustommappingsviacustomxmlfiles.
IMPORTANT:Forreal-worldapplicationsitisNOTrecommendedtocreateanewinstanceoftheMappereachtimeyoumapobjectsbutreusecreatedinstanceinstead.
SpecifyingCustomMappingsviaXML
Ifthetwodifferenttypesofdataobjectsthatyouaremappingcontainanyfieldsthatdon’tshareacommonpropertyname,youwillneedtoaddaclassmappingentrytoyourcustommappingxmlfile.ThesemappingsxmlfilesareusedatruntimebytheDozermappingengine.
Dozerautomaticallyperformsanytypeconversionwhencopyingthesourcefielddatatothedestinationfield.TheDozermappingengineisbi-directional,soifyouwantedtomapthedestinationobjecttothesourceobject,youdonotneedtoaddanotherclassmappingtothexmlfile.
IMPORTANT:Fieldsthatareofthesamenamedonotneedtobespecifiedinthemappingxmlfile.Dozerautomaticallymapsallfieldswiththesamepropertynamefromthesourceobjectintothedestinationobject.
i.e.:
<mapping><class-a>yourpackage.yourSourceClassName</class-a><class-b>yourpackage.yourDestinationClassName</class-b><field><a>yourSourceFieldName</a><b>yourDestinationFieldName</b></field></mapping>
ThecompleteDozermappingxmlfilewouldlooklikethefollowing.TheCustomMappingssectioncontainsmoreinformationonmappingoptionsthatareavailabletoyouformorecomplexusecases.
GettingStarted
7
<?xmlversion="1.0"encoding="UTF-8"?><mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttp://dozermapper.github.io/schema/bean-mapping.xsd"><configuration><stop-on-errors>true</stop-on-errors><date-format>MM/dd/yyyyHH:mm</date-format><wildcard>true</wildcard></configuration><mapping><class-a>yourpackage.yourSourceClassName</class-a><class-b>yourpackage.yourDestinationClassName</class-b><field><A>yourSourceFieldName</A><B>yourDestinationFieldName</B></field></mapping></mappings>
DozerandDependencyInjectionFrameworks
DozerisnotdependantofanyexistingDependencyInjectionframework(DI).Howeverthegeneralaimistosupportthemosttypicalusecaseswithready-to-usewrappers.CheckSpringIntegrationmanualforoptionofinitializingDozerincontextofSpringDIframework.
GettingStarted
8
Usage
DozerBeanMapper
Beforewegooversettingupcustomxmlbeanmappings,letuslookatasimpleexampleofusingDozer.TheDozermappingimplementationhasamethodcalledmapwhichtakesasourceobjectandeitheradestinationobjectordestinationobjectclasstype.Aftermappingthetwoobjectsitthenreturnsthedestinationobjectwithallofitsmappedfields.
Mappermapper=DozerBeanMapperBuilder.buildDefault();DestinationObjectdestObject=mapper.map(sourceObject,DestinationObject.class);
Or…
DestinationObjectdestObject=newDestinationObject();mapper.map(sourceObject,destObject);
Dozeroperatesintwogeneralmodes:implicitandexplicit.
Implicitmodeisactivatedbydefaultandtriestoresolvemappingsforyou.Itusessimpleassumptionsthatiftwoobjectsarepassedformappingthenbeanpropertieswiththesamenamesshouldbemapped.Ifthereareadditionalmappingsneeded,whichcannotbederivedbythenamingyoushouldaddthoseeitherviaXML,annotationsorAPI.
Explicitmodeassumesthatnomappingsshouldbeperformedor"guessed"untilyouhavespecifiedthosespecifically.Theamountofcodingishigherinexplicitmode,butsometimesyouwouldliketohavefullcontrolonwhatisgoingonduringthemappingsprocessandthisapproachisalsousedinmanyoftheproductiveapplications.Implicit/Explicitmappingswitchiscalled"wildcard"inDozer.
InjectingCustomMappingFiles
TheDozermappingxmlfile(s)defineanycustommappingsthatcan’tbeautomaticallyperformedbytheDozermappingengine.AnycustomDozermappingfilesneedtobeinjectedintotheMapperimplementationviaDozerBeanMapperBuilder#withMappingFiles(..)method.
Preferably,youwillbeusinganIOCframeworksuchasSpringfortheseDozerinjectionrequirements.Alternatively,theinjectionofmappingfilescanbedoneprogrammatically.Belowisaprogrammaticapproachtocreatingabeanmapper.NotethatthisisNOTtherecommendedwaytoretrievethebeanmapper.Eachnewinstanceneedstobeinitializedandthisconsumestimeaswellasresources.Ifyouareusingthemapperthiswayjustwrapitusingthesingletonpattern.
Mappermapper=DozerBeanMapperBuilder.create().withMappingFiles("dozerBeanMapping.xml","someOtherDozerBeanMappings.xml").build();
DestinationObjectdestObject=mapper.map(sourceObject,DestinationObject.class);
SpringIntegration
ThefollowingisanexamplehowtheMapperbeanwouldbeconfiguredviaSpring.
<beanid="mapper"class="com.github.dozermapper.core.DozerBeanMapper"><propertyname="mappingFiles"><list>
Usage
9
<value>dozer-global-configuration.xml</value><value>dozer-bean-mappings.xml</value><value>more-dozer-bean-mappings.xml</value></list></property></bean>
Usage
10
CustomMappingsViaDozerXMLFilesThissectionwillcoversettingupcustommappingsinxmlfile(s).Ifthetwodifferenttypesofdataobjectsthatyouaremappingcontainanyfieldsthatdon’tshareacommonpropertyname,youwillneedtoaddaclassmappingentrytoyourcustommappingxmlfile.ThesemappingsxmlfilesareusedatruntimebytheDozermappingengine.
Dozerautomaticallyperformsanytypeconversionwhencopyingthesourcefielddatatothedestinationfield.TheDozermappingengineisbi-directional,soifyouwantedtomapthedestinationobjecttothesourceobject,youdonotneedtoaddanotherclassmappingtothexmlfile.
Anexampleofamappingfile….
<?xmlversion="1.0"encoding="UTF-8"?><mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttp://dozermapper.github.io/schema/bean-mapping.xsd"><mapping><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><field><a>one</a><b>onePrime</b></field></mapping><mappingwildcard="false"><class-a>com.github.dozermapper.core.vo.TestObjectFoo</class-a><class-b>com.github.dozermapper.core.vo.TestObjectFooPrime</class-b><field><a>oneFoo</a><b>oneFooPrime</b></field></mapping></mappings>
Amappingselementhasmultiplemappingelements,eachwithclassmappingdeclarationsandfieldlevelmappings.Thewildcardattributeissettotruebydefault.Thismeansthatitwillautomaticallytrytomapeverypropertyinthetwoobjects.Whentheattributeissettofalseitwillonlymapexplicitlydefinedfields.
IMPORTANT:Propertiesthatareofthesamenamedonotneedtobespecifiedinthemappingxmlfile.Dozerautomaticallymapsallfieldswiththesamepropertynamefromthesourceobjectintothedestinationobject.
HowCustomMappingFilesAreLoaded
Dozerwillsearchtheentireclasspathlookingforthespecifiedfile.Thegenerallyacceptablewayofdistributingyourmappingsistobundletheminsideyourapplicationarchive.
Alternatively,youcanloadfilesfromoutsidetheclasspathbyprepending"file:"totheresourcename.Ex)"file:c:\somedozermapping.xml"
LoadingFilesfromInputStream
Sinceversion5.4.0itispossibletoloadXMLmappingfilesfromprovidedInputStreamobject.CheckDozerMapperclassforthecorrespondingAPIcalls.
MappingsviaXML
11
MappingsviaXML
12
AnnotationMappings
WhyAnnotations?
OneofthedownsidesofusingDozerforthelongtimewasXml.SinceDozerstartedduringXml-hypeyearsmorethanfiveyearsagothatwasprettyobviouschoicebackthen.AfterthatJava5broughtusannotationsandnewindustryacceptedstyleofconfiguringbehaviourareDomain-SpecificLanguages.DSL-likesupportisprovidedinformofmappingAPI,butsinceversion5.3.2Dozerstartsprovidingannotationssupportaswell.
Theobviousreasonstouseannotationsistoavoidduplicatingfieldandmethodnamesinyourmappingcode.Theannotationcanbeputontothemappedpropertyitselfthusreducingtheamountofcode.Howevertherearecaseswhenannotationsshouldbeavoidedorevenimpossibletouse.Someofthemarethefollowing:
Youaremappingclasses,whicharenotunderyourcontrol,butprovidedinlibraries;
Themappingsarequitecomplexandrequiremanyconfigurations;
InthefirstcaseyoucouldbemappingJAXBgeneratedentitiesorthird-partyDTOsandhavenopossibilitytoputannotations.Inthesecondcasethereisachoiceofputtinglotsofmulti-lineannotationsorisolatingthemappingcodewithcertainduplicationofentitynames.Overannotatedbeanscouldbeproblematictoreadandunderstand.
Usage
WARNING:AnnotationsupportinDozerisexperimentalanddoesnotcovercomplexusecasesyet.HoweveritmaybeusefultoimplementthatsimplestmappingsyouhavehadtodoinXmlorAPIbefore.
Theideaisverysimple.Youput@Mappingannotationeitherongetteroffielddirectly.IfDozerfindsthatitaddsabi-directionalmapping.Itmeansthatputtingannotationoncewillcreatemappingsforbothconversiontypes.Typeconversions(e.g.String-Long)willbechosenautomatically.Globalcustomconvertersareresolvedaswell.Annotationsworkonlyifaconversionissubjecttowildcardrule(activebydefault).Thefollowingexampledemonstratesannotationsinaction.
publicclassSourceBean{
privateLongid;
privateStringname;
@Mapping("binaryData")privateStringdata;
@Mapping("pk")publicLonggetId(){returnthis.id;}
publicStringgetName(){returnthis.name;}}
publicclassTargetBean{
privateStringpk;
privateStringname;
viaAnnotations
13
privateStringbinaryData;
publicvoidsetPk(Stringpk){this.pk=pk;}
publicvoidsetName(Stringname){this.name=name;}}
MappingthegivenbeanswithDozerwillresultinallthreefieldsbeingmapped.Property"name"willbemappedbynamingconvention.Property"id"willbetransformedto"pk".Field"data"willbemovedto"binaryData".Donotworryaboutprivatemodifier;itwillbehandledautomatically.
CurrentlyDozeroffersonlyoneannotation,butthenextoneswillbeaddedinfollowingreleases.Asfornowyoucanmixandmatchallflavoursofmappingtypestoachievethedesiredeffect:Xml,APIandAnnotations.
viaAnnotations
14
APIMappings
XMLMappingFlaws
XML-basedapproachisstableandisusedinmanyproductionprojects.However,itimposesseverallimitations.
First,andmostimportant,isthatitcannotbedynamicallygenerated.AllXMLmappingsshouldbepresentonDozerstart-upandcannotbemodifiedafterwards.Therearetrickyways,whenyoucangenerateandputmappingstothefilesystembyyourowntemplatingengine,butthisapproachisnotsupportedbyDozeritself.Bygeneratingcustommappingsyouareabletoautomaterepetitivechunksoflow-levelDozerlanguage.
SecondproblemisthatyouareforcedtoduplicateallofyourBeanclassnamesinXmlmappings.Thisleadstolotsoftypingandcopy-pasteprogramming.ThiscanbepartlycompensatedbyuseofExpressionLanguageinsideXml,butitisnotsolvingalloftheproblems.
RefactoringsupportislimitedasIDEshouldkeeptrackofclassnamesinXmlfilesandchangethemwhenyourenameormovethereferencedclass.Auto-completionsupportisalsonotavailableinallIDEs.
APIMappings
APImappingsareintendedtosolveallofthementionedproblems.TopreservebackwardscompatibilityAPImappingscanbecombinedwithexistingXmlmappings.Infactsomepartsoftheconfiguration(e.g.globalconfigurationblock)areonlypossibletoexpressinXmlformat.
Togetafeelingofwhatarethesemappingstakealookatthefollowingcodeexample.
importcom.github.dozermapper.core.classmap.RelationshipType;importcom.github.dozermapper.core.loader.api.BeanMappingBuilder;importcom.github.dozermapper.core.loader.api.FieldsMappingOptions;importcom.github.dozermapper.core.loader.api.TypeMappingOptions;
importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.collectionStrategy;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.copyByReference;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.customConverter;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.customConverterId;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.hintA;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.hintB;importstaticcom.github.dozermapper.core.loader.api.FieldsMappingOptions.useMapId;importstaticcom.github.dozermapper.core.loader.api.TypeMappingOptions.mapId;importstaticcom.github.dozermapper.core.loader.api.TypeMappingOptions.mapNull;
publicclassMyClass{
publicvoidcreate(){BeanMappingBuilderbuilder=newBeanMappingBuilder(){protectedvoidconfigure(){mapping(Bean.class,Bean.class,TypeMappingOptions.oneWay(),mapId("A"),mapNull(true)).exclude("excluded").fields("src","dest",copyByReference(),collectionStrategy(true,RelationshipType.NON_CUMULATIVE),hintA(String.class),hintB(Integer.class),FieldsMappingOptions.oneWay(),useMapId("A"),customConverterId("id")
viaAPI
15
).fields("src","dest",customConverter("com.github.dozermapper.core.CustomConverter"));}};}}
ConstructedbuilderobjectshouldbethenpassedtoDozerBeanMapperBuilder.ItispossibletoaddmultipleBuilderclasses.
Mappermapper=DozerBeanMapperBuilder.create().withMappingBuilder(builder).build();
viaAPI
16
ConfigurationDozerconfigurationpropertiescanbecustomizedviaanoptionalDozerpropertiesfile.Bydefault,Dozerwilllookforafilenameddozer.propertiestoloadconfigurationproperties.Ifapropertiesfileisnotfoundorspecified,defaultvalueswillbeused.
Dozerisdistributedwithanexampledozer.propertiesfilein/configthatshowsthevariousoptions.Justputtheexamplefileinyourclasspathandcustomizeit.
AnalternativeDozerpropertiesfilecanbespecifiedviathedozer.configurationsystemproperty.ex)-Ddozer.configuration=someDozerConfigurationFile.properties
Table1.DozerConfigurationProperties
PropertyName Description ValidValues Default
dozer.el.enabled
SpecifieswhetherduringXmlmappingsparsingDozerwillrecognizeELexpressions.
true false false
dozer.cache.converter-by-dest-type-maxsize
SpecifiesthemaxsizeforoneofDozersinternalcaches.
0-Long.MAX_VALUE 10000
dozer.cache.super-type-maxsize
SpecifiesthemaxsizeforoneofDozersinternalcaches
0-Long.MAX_VALUE 10000
dozer.beans.proxy-resolver-bean
SpecifiesimplementationofDozerProxyResolvertobeused
Validclassname Defaultimplementation
dozer.beans.class-loader-bean
SpecifiesimplementationofDozerClassLoadertobeused
Validclassname Defaultimplementation
Configuration
17
ConfigurationviaXMLThemajorityofDozer’sbehaviourcanbeconfiguredfromwithinXMLmappingfiles.Settingscanappearinsidefivedifferentscopeswhichaffecttheelementstheyareappliedto:Global,perclassmapping,atindividualclasslevel,perfieldmapping,andatindividualfieldlevel.
ConfigurationScopes
GlobalScope
Theconfigurationblockisusedtosettheglobaldefaultsettings.Also,anyCustomConvertersaredefinedinthissection.Theconfigurationblockisentirely"optional".
Dozersupportstheabilitytohavemultiplemappingfiles.Eachofthesemappingfilescanhavetheirownconfigurationblock.Amappingwillinherititsconfigurationfromthemappingfilethatitisstoredin.Implicitmappingswillinheritthedefaultvaluesforconfiguration.
Thefollowingisthesampleconfigurationblockfromtheexamplemappingsfile:
<configuration><date-format>MM/dd/yyyyHH:mm</date-format><stop-on-errors>true</stop-on-errors><wildcard>true</wildcard><custom-converters><!--thesearealwaysbi-directional--><convertertype="com.github.dozermapper.core.converters.TestCustomConverter"><class-a>com.github.dozermapper.core.vo.TestCustomConverterObject</class-a><class-b>another.type.to.Associate</class-b></converter></custom-converters></configuration>
AllglobalsettingsappearasseparateXMLtagscontainingtheirvalue.
PerClassMapping
Globalsettings(ortheirdefaults)canbeoverriddenattheindividualmappinglevel.Here,configurationvaluesaresetusingname="value"attributes.Theywillaffectallmappingoperationsbetweenthetwoclasses.
<mappingwildcard="false"date-format="MM/dd/yyyyHH:mm"><class-a>com.github.dozermapper.core.vo.SpringBean</class-a><class-b>com.github.dozermapper.core.vo.SpringBeanPrime</class-b><field><a>anAttributeToMap</a><b>anAttributeToMapPrime</b></field></mapping>
AtIndividualClassLevel
Sometimes,youmaywanttoapplyasettingonlytooneofthetwoclasses.Thiscanbeachievedbyplacingtheattributeinsidetheclass-aorclass-btag:
<mapping><class-ais-accessible="true">com.github.dozermapper.core.vo.SpringBean</class-a>
ConfigurationviaXML
18
<class-b>com.github.dozermapper.core.vo.SpringBeanPrime</class-b><field><a>anAttributeToMap</a><b>anAttributeToMapPrime</b></field></mapping>
PerFieldMapping
Likewise,youcanchangethemappingbehaviourforspecificfieldpairs:
<mapping><class-a>com.github.dozermapper.core.vo.SpringBean</class-a><class-b>com.github.dozermapper.core.vo.SpringBeanPrime</class-b><fieldremove-orphans="false"><a>anAttributeToMap</a><b>anAttributeToMapPrime</b></field></mapping>
AtIndividualFieldLevel
Finally,somesettingscanbeappliedtoasinglefield:
<mapping><class-a>com.github.dozermapper.core.vo.SpringBean</class-a><class-b>com.github.dozermapper.core.vo.SpringBeanPrime</class-b><field><aget-method="getTheAttribute">anAttributeToMap</a><b>anAttributeToMapPrime</b></field></mapping>
AvailableConfigurationSettings
Thefollowingtableliststheavailableconfigurationoptionsandmappingdirectives,inwhichscopestheycanappear,andthesectionofthemanualcontainingmoreinformation:
Name Global ClassMapping
SingleClass
FieldMapping
SingleField
ManualSection
allowed-exceptions X seebelow
custom-converter X Custom
Converters
custom-converter-id X Custom
Converters
custom-converter-param
X CustomConverters
copy-by-reference X CopyBy
Reference
copy-by-references X CopyBy
Reference
ConfigurationviaXML
19
create-method X X
CustomCreateMethod
bean-factory X X X
CustomBeanFactories
date-format X X XStringtoDateMapping
factory-bean-id X
CustomBeanFactories
get-method X CustomMethods
is-accessible X X
Mappingimmutabletypes
key X MapMapping
map-empty-string X X X Excluding
Fields
map-id XContextBasedMapping
map-null X X X ExcludingFields
map-set-method X X Map
Mapping
map-get-method X X Map
Mapping
relationship-type X X X Collection
Mapping
remove-orphans X Collection
Mapping
set-method X CustomMethods
skip-constructor X
Mappingimmutabletypes
stop-on-errors X seebelow
ConfigurationviaXML
20
trim-strings X X seebelow
type X X One-WayMapping
variables X ExpressionLanguage
wildcard X X seebelow
wildcard-case-insensitive
X X seebelow
Errorhandling(stop-on-errors,allowed-exceptions)
Bydefault,ifDozerencountersanerrorwhileperformingafieldmapping,anexceptionisthrownandthemappingaborted.Whilethisistherecommendedbehaviour,Dozercanbeinstructedtoignoretheerrorandsimplycontinuewiththenextfield,viathestop-on-errorspolicy.
YoucanalsospecifyexceptionsthatshouldcauseDozertostopandrethrowthem,evenifstop-on-errorsissettofalse,usingtheallowed-exceptionselement:
<configuration><stop-on-errors>false</stop-on-errors><allowed-exceptions><exception>org.example.UnrecoverableError</exception><exception>org.example.BadException</exception></allowed-exceptions></configuration>
TrimmingStrings(trim-strings)
Asthenamesuggests,trim-stringsappliesJava’sString.trim()tothesourcevaluebeforecallingthetargetbeans’ssetter.
Wildcardmapping(wildcard,wildcard-case-insensitive)
Perdefault,Dozermapsallfieldsbetweensourceandtargetbeanthatsharethesamename("wildcardmapping").Listingfieldsinmappingdefinitionsdoesnotoverridethisbehaviour,exceptforthegivenfields.Forexample,giventhefollowingclasses
classPerson{privateStringfirstName;privateStringlastName;}
classContact{privateStringfirstName;privateStringsurname;}
andthemappingdefinition
<mapping>
ConfigurationviaXML
21
<class-a>com.github.dozermapper.core.vo.Person</class-a><class-b>com.github.dozermapper.core.vo.Contact</class-b><field><a>lastName</a><b>surname</b></field></mapping>
amappingfromaPersonobjectontoaContactwillmaplastNametosurnameandfirstNametofirstName,eventhoughthelatterpairisnotmentionedinthemappingdefinition.
Youcandisablewildcardmappinggloballyorattheclassmappinglevelbysettingwildcardtofalse.Ifyoudo,youhavetoexplicitlyspecifyeachpairoffieldsthatshouldbemapped:
<mappingwildcard="false"><class-a>com.github.dozermapper.core.vo.Person</class-a><class-b>com.github.dozermapper.core.vo.Contact</class-b><field><a>lastName</a><b>surname</b></field><field><a>firstName</a><b>firstName</b></field></mapping>
UptoDozerversion5.4.0,wildcardmappingswerecaseinsensitive.CurrentversionsofDozeronlyautomaticallymapfieldswiththeexactsamename.Youcanenabletheoldcaseinsensitivebehaviourbysettingthewildcard-case-insensitivepolicytotrue.Then,forexampleasourcefieldnamedcamelCasewillbemappedtotargetfieldcamelcase(andviceversa).
ConfigurationviaXML
22
ConfigurationviaAPIIfyouareusingtheMapperBuildertodefineyourmappings,youcandeclaremapping,class,andfieldconfigurationsettingsprogrammatically:
Mappermapper=DozerBeanMapperBuilder.create().withMappingBuilder(newBeanMappingBuilder(){@Overrideprotectedvoidconfigure(){mapping(type(A.class).mapEmptyString(true),type(B.class),TypeMappingOptions.wildcardCaseInsensitive(true)).fields(field("fieldOfA").getMethod("getTheField"),field("fieldOfB"),FieldsMappingOptions.oneWay());}}).build();
GlobalconfigurationiscurrentlynotsupportedbytheAPI.
PleaseseeConfigurationviaXMLforalistoftheavailableconfigurationsettings.
ConfigurationviaAPI
23
MappingClassesAnexampleofmappingtwoclassesisdefinedbelow.Note:Explicitxmlmappingfor2classesisnotrequiredifallthefieldmappingbetweensrcanddestobjectcanbeperformedbymatchingonattributename.Customxmlclassmappingisonlyrequiredwhenyouneedtospecifyanycustomfieldmappings.
<mappings><mapping><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><!--Anycustomfieldmappingxmlwouldgohere--></mapping></mappings>
Thesemappingsarebi-directionalsoyouwouldneverneedtodefineanXMLmapforTestObjectPrimetoTestObject.Ifthesetwoclasseshadreferencestocomplextypesthatneededtypetransformation,youwouldalsodefinethemasmappings.Dozerrecursivelygoesthroughanobjectandmapseverythinginit.Datatypeconversionisperformedautomatically.Dozeralsosupportsnoattributemappingsatall.Ifsuppliedtwoclassesthatarenotmapped,itsimplytriestomappropertiesthatarethesamename.
MappingClasses
24
BasicPropertyMapping
ImplicitPropertyMapping(bi-directional)
MatchingfieldnamesareautomaticallyhandledbyDozer.
Propertiesthatareofthesamenamedonotneedtobespecifiedinthemappingxmlfile.
SimpleMappings(bi-directional)
Wewillstartoffsimple.Ifyouhavetwopropertieswithdifferentnamestheycanbemappedassuch:
<field><a>one</a><b>onePrime</b></field>
Datatypeconversion
DatatypecoversionisperformedautomaticallybytheDozermappingengine.Currently,Dozersupportsthefollowingtypesofconversions:(theseareallbi-directional)
PrimitivetoPrimitiveWrapper
PrimitivetoCustomWrapper
PrimitiveWrappertoPrimitiveWrapper
PrimitivetoPrimitive
ComplexTypetoComplexType
StringtoPrimitive
StringtoPrimitiveWrapper
StringtoComplexTypeiftheComplexTypecontainsaStringconstructor
StringtoMap
CollectiontoCollection
CollectiontoArray
MaptoComplexType
MaptoCustomMapType
EnumtoEnum
Eachofthesecanbemappedtooneanother:java.util.Date,java.sql.Date,java.sql.Time,java.sql.Timestamp,java.util.Calendar,java.util.GregorianCalendar
StringtoanyofthesupportedDate/CalendarObjects.
ObjectscontainingatoString()methodthatproducesalongrepresentingtimein(ms)toanysupportedDate/Calendarobject.
RecursiveMapping(bi-directional)
BasicPropertyMapping
25
DozersupportsfullClasslevelmappingrecursion.Ifyouhaveanycomplextypesdefinedasfieldlevelmappingsinyourobject,DozerwillsearchthemappingsfileforaClasslevelmappingbetweenthetwoClassesthatyouhavemapped.Ifyoudonothaveanymappings,itwillonlymapfieldsthatareofthesamenamebetweenthecomplextypes.
BasicPropertyMapping
26
InheritanceMapping
ReducingMappingXMLwhenusingbaseclassattributes
Propertiesthatareofthesamenamedonotneedtobespecifiedinthemappingxmlfileunlesshintsareneeded.
IfyouaremappingsubclassesthatalsohavehavebaseclassattributesrequiringmappingXML,youmightbeinclinedtoreproducebaseclassfieldmapsineachsubclassmappingelement,likethefollowingexample:
<mapping><class-a>com.github.dozermapper.core.vo.SubClass</class-a><class-b>com.github.dozermapper.core.vo.SubClassPrime</class-b><field><!--thisisthesameforallsubclasses--><a>superAttribute</a><b>superAttr</b></field><field><a>attribute2</a><b>attributePrime2</b></field></mapping><mapping><class-a>com.github.dozermapper.core.vo.SubClass2</class-a><class-b>com.github.dozermapper.core.vo.SubClassPrime2</class-b><field><!--thisisthesameforallsubclasses--><a>superAttribute</a><b>superAttr</b></field><field><a>attribute2</a><b>attributePrime2</b></field></mapping>
Inthepreviousmapping,someofthefieldswerefromacommonbaseclass,butyouhadtoreproducethemintoeachmappingofthesubclasses.
However,abetterwaytodoitwouldbetomapthebaseclassindividually.Thiscanbedoneforeachbaseclass(inthecaseofalargerheirarchy).Assumingthebaseclassname,belowistherefactoredmappingxml:
<mapping><class-a>com.github.dozermapper.core.vo.SuperClass</class-a><class-b>com.github.dozermapper.core.vo.SuperClassPrime</class-b><field><a>superAttribute</a><b>superAttr</b></field></mapping><mapping><class-a>com.github.dozermapper.core.vo.SubClass</class-a><class-b>com.github.dozermapper.core.vo.SubClassPrime</class-b><field><a>attribute</a><b>attributePrime</b></field></mapping><mapping><class-a>com.github.dozermapper.core.vo.SubClass2</class-a>
InheritanceMapping
27
<class-b>com.github.dozermapper.core.vo.SubClassPrime2</class-b><field><a>attribute2</a><b>attributePrime2</b></field></mapping>
Thefollowingimagesexplainsomeofthedifferentscenariosdozerhandles.Eachdiagramshowstwomappedclasshierarchiesandexistingrelations,whichDozerrecognizesandmaps.
Scenario1showsthatifyoumapSubClasstoClassPrimeallattributesfromSuperClass→ClassPrimewillbemappedaswell.
Scenario2showsthatDozerhasnolimitationsontheinheritancedepthitanalyzestofindparentmappings.
InheritanceMapping
28
Scenario3showsthatitispossibletomaptwocollectionswithdifferentsubctypesofthesameparenttype.Thisisdonebyprovidinghintstothecollectionmapping,describingallpotentialsubclasses.
<field><a>aList</a><b>bList</b><a-hint>B1,B2</a-hint><b-hint>BPrime1,BPrime2</b-hint></field>
InheritanceMapping
29
ContextBasedMappingContextbasedmappingcanbespecifiedbyusingthemap-idattribute.Notethatwealsosupportnestedcontextmappingbyspecifyingamap-idatthefieldlevel.
<mappingmap-id="caseA"><class-a>com.github.dozermapper.core.vo.context.ContextMapping</class-a><class-b>com.github.dozermapper.core.vo.context.ContextMappingPrime</class-b><field-exclude><a>loanNo</a><b>loanNo</b></field-exclude><fieldmap-id="caseC"><a>contextList</a><b>contextList</b><b-hint>com.github.dozermapper.core.vo.context.ContextMappingNestedPrime</b-hint></field></mapping><mappingmap-id="caseB"><class-a>com.github.dozermapper.core.vo.context.ContextMapping</class-a><class-b>com.github.dozermapper.core.vo.context.ContextMappingPrime</class-b></mapping><mappingmap-id="caseC"><class-a>com.github.dozermapper.core.vo.context.ContextMappingNested</class-a><class-b>com.github.dozermapper.core.vo.context.ContextMappingNestedPrime</class-b><field-exclude><a>loanNo</a><b>loanNo</b></field-exclude></mapping><mappingmap-id="caseD"><class-a>com.github.dozermapper.core.vo.context.ContextMappingNested</class-a><class-b>com.github.dozermapper.core.vo.context.ContextMappingNestedPrime</class-b></mapping>
TouseaparticularcontextwheninvokingtheMapper,yousimplyspecifythemap-idinyourmappingcall.
ContextMappingPrimecmpA=mapper.map(cm,ContextMappingPrime.class,"caseA");
ContextBasedMapping
30
One-WayMappingYoucansethowamappingdefinitionbehavesasfarasdirectiongoes.Ifyouonlywanttomaptwoclassestogoone-wayyoucansetthisatthemappinglevel.Thedefaultisbi-directional.ThiscanbesetatthemappinglevelORthefieldlevel.Whenone-wayisspecified,"a"isalwaysthesrcobjectand"b"isalwaysthedestinationobject.
<mappingtype="one-way"><class-a>com.github.dozermapper.core.vo.TestObjectFoo</class-a><class-b>com.github.dozermapper.core.vo.TestObjectFooPrime</class-b><field><a>oneFoo</a><b>oneFooPrime</b></field></mapping>
Inthefollowingexampletheone-wayfieldsareonlymappedwhen"a"objectismappedto"b"object.If"b"ismappedto"a",thenthefieldisnotmapped.
<mapping><class-a>com.github.dozermapper.core.vo.TestObjectFoo2</class-a><class-b>com.github.dozermapper.core.vo.TestObjectFooPrime2</class-b><fieldtype="one-way"><a>oneFoo2</a><b>oneFooPrime2</b></field><fieldtype="one-way"><a>oneFoo3.prime</a><b>oneFooPrime3</b></field></mapping>
ExcludingFieldsOne-Way
Dozersupportsfieldexcludesgoingone-wayasshownintheexample.Intheexamplethefieldisonlyexcludedwhen"a"ismappedto"b".If"b"ismappedto"a",thenthefieldisnotexcluded.
<field-excludetype="one-way"><a>fieldToExclude</a><b>fieldToExclude</b></field-exclude>
One-WayMapping
31
CopyingByObjectReferenceDozersupportscopyinganobjectbyreference.Noconversion/transformationisdoneforsuchobjects.Thisapproachallowstodecreaseanumberofobjectallocations,butisapplicableonlywhenJavaBeansaretobethrownaway(GarbageCollected)aftertransformation.Thisapproachisgenerallyrecommendedforperformancetuningofthemappingprocesswhenpossible.Makesurethatbothobjecttypesarethesameoryouwillrunintocastingproblems.Thedefaultvalueis'false'.
<fieldcopy-by-reference="true"><a>copyByReference</a><b>copyByReferencePrime</b></field>
Thisisalsosupportedattheclasslevel.Justdefinetheclassesyouwanttobecopiedbyreferenceintheconfigurationblock.
<configuration><copy-by-references><copy-by-reference>com.github.dozermapper.core.vo.NoExtendBaseObjectGlobalCopyByReference</copy-by-reference></copy-by-references></configuration>
Ontheclasslevelwildcardexpressionsareallowed.Copybyreferenceisappliedviamask,whichcaninlcudemultiplewildcard(*)characters.
<configuration><copy-by-references><copy-by-reference>com.github.dozermapper.core.vo.*</copy-by-reference><copy-by-reference>com.github.dozermapper.core.*.vo.*DTO</copy-by-reference></copy-by-references></configuration>
Referencingself(this)inafieldmapping
UsingafieldmappingitispossibletomapwhereN==0(self,orthis).InthefollowingexampleSimpleAccountismappedtoAddress.ItisalsomappedtoAccount.SupposeAddresswasanattributeonAccount.HowcouldwemapthevaluesonSimpleAccounttothatproperty?Theansweristousethekeyword(this)todenoteusingtheclassbeingmappedasthesourceobject.
<mapping><classa>com.github.dozermapper.core.vo.self.SimpleAccount</classa><classb>com.github.dozermapper.core.vo.self.Account</classb><field><a>this</a><b>address</b></field></mapping><mapping><classa>com.github.dozermapper.core.vo.self.SimpleAccount</classa><classb>com.github.dozermapper.core.vo.self.Address</classb>
CopyingByObjectReference
32
<field><a>streetName</a><b>street</b></field></mapping>
CopyingByObjectReference
33
DeepPropertyMappingItispossibletomapdeepproperties.AnexamplewouldbewhenyouhaveanobjectwithaStringproperty.YourotherobjecthasaStringpropertybutitisseverallevelsdeepwithintheobjectgraph.IntheexamplebelowtheDestDeepObjhasnestedattributeswithintheobjectgraphthatneedtobemapped.Typehintsaresupportedfordeepfieldmappings.Theattributescopy-by-reference,type=one-way,andrelationship-typecanalsobeused.
<mapping><class-a>com.github.dozermapper.core.vo.deep.SrcDeepObj</class-a><class-b>com.github.dozermapper.core.vo.deep.DestDeepObj</class-b><field><a>srcNestedObj.src1</a><b>dest1</b></field><field><a>srcNestedObj.src2</a><b>dest2</b></field><field><a>srcNestedObj.srcNestedObj2.src5</a><b>dest5</b></field><field><!--java.util.Listtojava.util.List--><a>srcNestedObj.hintList</a><b>hintList</b><a-hint>java.lang.String</a-hint><b-hint>java.lang.Integer</b-hint></field><field><a>srcNestedObj.hintList2</a><b>hintList2</b><a-hint>com.github.dozermapper.core.vo.TheFirstSubClass</a-hint><b-hint>com.github.dozermapper.core.vo.TheFirstSubClassPrime</b-hint></field><fieldcopy-by-reference="true"><a>srcNestedObj.hintList3</a><b>hintList3</b></field></mapping>
DeepIndexedMapping
Indexedmappingwithindeepmappingissupported.
<field><a>offSpringName</a><b>pets[1].offSpring[2].petName</b></field>
DestinationHintsareNOTrequirediftheindexedcollectionisanArrayorifyouareusingjdk1.5Generics.Dozerisabletoautomaticallydeterminethepropertytypefortheseusecases.ButyouwillneedtoprovidehintsifthedatatypesarenotArraysorifyouarenotusingGenerics.ThisisrequiredsothatDozerknowswhattypesofdestobjectstocreatewhileittraversesthedeepfieldmapping.
Thefollowingisanexampleofusinghints…..
<field><a>someField</a>
DeepPropertyMapping
34
<b>someList[1].someOtherList[0].someOtherField</b><b-deep-index-hint>com.github.dozermapper.core.vo.TestObject,com.github.dozermapper.core.vo.AnotherTestObject</b-deep-index-hint></field>
DeepPropertyMapping
35
IndexedPropertyMappingFieldsthatneedtobelookeduporwrittentobyindexedpropertyaresupported.
<mapping><class-a>com.github.dozermapper.core.vo.Individuals</class-a><class-b>com.github.dozermapper.core.vo.FlatIndividual</class-b><field><a>usernames[0]</a><b>username1</b></field><field><a>usernames[1]</a><b>username2</b></field><field><a>individual.username</a><b>username2</b></field><field><a>secondNames[1]</a><b>secondName1</b></field><field><a>secondNames[2]</a><b>secondName2</b></field><field><a>aliases.otherAliases[0]</a><b>primaryAlias</b></field></mapping>
IndexedPropertyMapping
36
ExcludingFieldsDozersupportsexcludingfieldsfromamappingusingthefield-excludetag.Wealsosupportfieldexcludesgoingone-wayasshownintheexample.
<field-exclude><a>fieldToExclude</a><b>fieldToExclude</b></field-exclude>
<field-excludetype="one-way"><a>fieldToExclude</a><b>fieldToExclude</b></field-exclude>
Wildcard-excludingdefaultfieldmappings
There’salsoaflag(wildcard)setonclassmappingwhichcontrolswhetherthedefaultmapping(whichappliestopairofpropertiesofthesamename)shouldbedone.Thedefaultvalueistrue.Forexample:
<mappingwildcard="false"><class-a>com.github.dozermapper.core.vo.AnotherTestObject</class-a><class-b>com.github.dozermapper.core.vo.AnotherTestObjectPrime</class-b><field><a>field1</a><b>field1</b></field></mapping>
Thisconfigurationwouldcauseonlythefieldsfield1inbothclassestobemapped,evenifbothclassesshareapropertywiththesamenamecalled`field2`.
ExcludeMappingNullValues
Youcanbypassthemappingofnullvalues.Ifthisisspecified,thedestfieldmappingisbypassedatruntimeandthedestinationvaluesettermethodwillnotbecalledifthesrcvalueisnull.Thiscanbespecifiedatthemappingorclasslevel.Forexample:
<mappingmap-null="false"><class-a>com.github.dozermapper.core.vo.AnotherTestObject</class-a><class-b>com.github.dozermapper.core.vo.AnotherTestObjectPrime</class-b><field><a>field4</a><b>to.one</b></field></mapping>
OR…
<mapping><class-a>com.github.dozermapper.core.vo.AnotherTestObject</class-a><class-bmap-null="false">com.github.dozermapper.core.vo.AnotherTestObjectPrime</class-b><field><a>field4</a><b>to.one</b></field>
ExcludingFields
37
</mapping>
ExcludeMappingEmptyStrings
YoucanbypassthemappingofemptyStringvalues.Ifthisisspecified,thedestfieldmappingisbypassedatruntimeandthedestinationvaluesettermethodwillnotbecalledifthesrcvalueisanemptyString.Thiscanbespecifiedatthemappingorclasslevel.Forexample:
<mappingmap-empty-string="false"><class-a>com.github.dozermapper.core.vo.AnotherTestObject</class-a><class-b>com.github.dozermapper.core.vo.AnotherTestObjectPrime</class-b><field><a>field4</a><b>to.one</b></field></mapping>
OR…
<mapping><class-a>com.github.dozermapper.core.vo.AnotherTestObject</class-a><class-bmap-empty-string="false">com.github.dozermapper.core.vo.AnotherTestObjectPrime</class-b><field><a>field4</a><b>to.one</b></field></mapping>
ExcludingFields
38
MappingConcepts
AssemblerPattern
DozercanbeusedasanAssembler.MartinFowlerhasagreatexplanationofwhyandwhenyouwoulduseanAssembler.Basically,itisawaytotakemultiplefinegrainobjectsandcreateonecoarsegrainobjectusedfordatatransfer.Aslongasyouhavemappingsdefinedforeachofyourfinegrainedobjectstoyourcoarsegrainobjectyoucancallthemappermultipletimestoachievethedesiredassemblerpattern.
mapper.map(sourceA,ClassB.class);
Let’ssaythatClassA,ClassB,andClassCallmaptoClassD.Firstcreatetheseindividualmappingsinthemappingfile.Next,callthemapperonceforeachmapping.Notethatthiswouldalsoworkinabi-directinonalmanner.
ClassDd=newClassD();mapper.map(sourceA,d);mapper.map(sourceB,d);mapper.map(sourceC,d);
AssemblerPattern
39
MappingimmutabletypesYoucancreateobjectswhenconstructorisnotavailable,orwhenthereisnono-argsconstructorintheclass.Featureisdesignedformappingimmutabletypes.Touseit,atthemappingleveladdanoptiontoskiptheconstructor,thenatthefieldlevelchoosetoinjectthevaluedirectlytothefield,skippingthesetter.
<mapping><class-a>com.github.dozermapper.core.vo.AnyExternalModelClass</class-a><class-bskip-constructor="true">com.github.dozermapper.core.vo.ImmutableModelClass</class-b><field><a>externalModelField</a><bis-accessible="true">ourFinalField</b></field></mapping>
Mappingimmutabletypes
40
EnumMappingTomapanenumsvaluetoanotherenumisshownbelow.
<field><a>status</a><b>statusPrime</b></field>
Basedonthefollowingcode:
enumStatus{PROCESSING,SUCCESS,ERROR}
publicclassUserGroup{
privateStatusstatus;
publicStatusgetStatus(){returnstatus;}
publicvoidsetStatus(Statusstatus){this.status=status;}
}
enumStatusPrime{PROCESSING,SUCCESS,ERROR}
publicclassUserGroupPrime{
privateStatusPrimestatusPrime;
publicStatusPrimegetStatusPrime(){returnstatusPrime;}
publicvoidsetStatusPrime(StatusPrimestatusPrime){this.statusPrime=statusPrime;}
}
Enums
41
StringtoDateMappingAdateformatfortheStringcanbespecifiedatthefieldlevelsothatthenecessarydatatypeconversioncanbeperformed.
<field><adate-format="MM/dd/yyyyHH:mm:ss:SS">dateString</a><b>dateObject</b></field>
Adefaultdateformatcanalsobespecifiedattheclassmappinglevel.Thisdefaultdateformatwillbeappliedtoallfieldmappingsunlessitisoverriddenatthefieldlevel.
<mappingdate-format="MM-dd-yyyyHH:mm:ss"><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><field><a>dateString</a><b>dateObject</b></field></mapping>
Adefaultdateformatcanalsobespecifiedattheverytopmappingslevel.Thisdefaultdateformatwillbeappliedtoallfieldmapppingsunlessitisoverriddenatalowerlevel
<mappings><configuration><date-format>MM/dd/yyyyHH:mm</date-format></configuration><mappingwildcard="true"><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><field><a>dateString</a><b>dateObject</b></field></mapping><mapping><class-a>com.github.dozermapper.core.vo.SomeObject</class-a><class-b>com.github.dozermapper.core.vo.SomeOtherObject</class-b><field><a>srcField</a><b>destField</b></field></mapping></mappings>
StringtoDate
42
CollectionandArrayMappingDozerautomaticallymapsbetweencollectiontypesandautomaticallyperformsanytypeconversion.Eachelementinthesourcecollectionismappedtoanelementinthedestobject.Hintsareusedtospecifywhattypeofobjectsarecreatedinthedestinationcollection.ThefollowingcollectionmappingisautomaticallyhandledbyDozer:(Theseareallbi-directional)
ListtoList
ListtoArray
ArraytoArray
SettoSet
SettoArray
SettoList
UsingHintsforCollectionMapping
HintsarenotrequiredifyouareusingJDK1.5GenericsorArraysbecausethetypescanbeautodetectedbyDozer.ButifyouarenotusinggenericsorArrays,toconvertaCollection/ArraytoaCollection/ArraywithdifferenttypeobjectsyoucanspecifyaHinttoletDozerknowwhattypeofobjectsyouwantcreatedinthedestinationlist.IfaHintisnotspecifiedforthedestinationfield,thenthedestinationCollectionwillbepopulatedwithobjectsthatarethesametypeastheelementsinthesrcCollection.
<!--convertingTheFirstSubClassListtoTheFirstSubClassPrimeList--><field><a>hintList</a><b>hintList</b><b-hint>com.github.dozermapper.core.vo.TheFirstSubClassPrime</b-hint></field>
BelowisasummaryofthemappinglogicusedwhenmappingArrays,Sets,andLists.Thisgivesabreakdownofwhathappenswhenhintsareorarenotused.
ListtoList
**DestHintreq’d:NO
DestHintallowed:YES
Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource
Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type
ArraytoList
**DestHintreq’d:NO
DestHintallowed:YES
Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource
Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type
ListtoArray
CollectionsandArrays
43
**DestHintreq’d:NO
DestHintallowed:YES
Ifnodesthintspecified:Destarraywillcontaindatatypesdefinedbythearray
Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type(onlyifObjectArray)
ArraytoArray
**DestHintreq’d:NO
DestHintallowed:YES
Ifnodesthintspecified:Destarraywillcontaindatatypesdefinedbythearray
Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type(onlyifObjectArray)
SettoSet
**DestHintreq’d:NO
DestHintallowed:YES
Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource
Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type
ArraytoSet
**DestHintreq’d:NO
DestHintallowed:YES
Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource
Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type
SettoArray
**DestHintreq’d:NO
DestHintallowed:YES
Ifnodesthintspecified:Destarraywillcontaindatatypesdefinedbythearray
Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type(onlyifObjectArray)
ListtoSet
**DestHintreq’d:NO
DestHintallowed:YES
Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource
Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type
SettoList
**DestHintreq’d:NO
DestHintallowed:YES
Ifnodesthintspecified:Destlistwillcontainthesamedatatypesinthesource
Ifhintisspeficied:Destlistwillcontainobjectsthatmatchdesthint(s)type
CollectionsandArrays
44
UsingJDK1.5GenericsforCollectionMappingHintsarenotrequiredwhenJDK1.5Genericsareused.ToconvertaCollection/ArraytoaCollection/Arraywithdifferenttypeobjectsdozercandetermineparameterizedtypesatruntime.
publicclassUserGroup{
privateSet<User>users;
publicSet<User>getUsers(){returnusers;}
publicvoidsetUsers(Set<User>aUsers){users=aUsers;}
}publicclassUserGroupPrime{
privateList<UserPrime>users;
publicList<UserPrime>getUsers(){returnusers;}
publicvoidsetUsers(List<UserPrime>aUsers){users=aUsers;}
}
ObjectArraytoList(bi-directional)
WhenconvertinganObjectarraytoaList,bydefaultthedestinationListwillcontainthesamedatatypeasthesourceArray.
<!--changinganInteger[]toListandbackagain--><field><a>arrayForLists</a><b>listForArray</b></field>
Useahintfordatatypeconversion.Becauseahintisspecified,thedestinationListwillcontainStringelementsinsteadofIntegers.
<!--changinganInteger[]toListandbackagain--><field><a>arrayForLists</a><b>listForArray</b><b-hint>java.lang.String</b-hint></field>
PrimitiveArraytoPrimitiveArray(bi-directional)
WhenconvertinganObjectarraytoanArray,bydefaultthedestinationArraywillcontainthesamedatatypeasthesourceArray.
<!--convertingint[]toint[]bynameonly-->
CollectionsandArrays
45
<field><a>anArray</a><b>theMappedArray</b></field>
Cumulativevs.Non-CumulativeListMapping(bi-directional)
IfyouaremappingtoaClasswhichhasalreadybeeninitialized,dozerwilleither'add'or'update'objectstoyourList.IfyourListorSetalreadyhasobjectsinitdozerchecksthemappedList,Set,orArrayandcallsthecontains()methodtodetermineifitneedsto'add'or'update'.Thisisdeterminedusingtherelationship-typeattributeonthefieldtag.Thedefaultis'cumulative'.relationship-typecanbespecifedatthefieldmapping,classmapping,orglobalconfigurationlevel.
globalconfigurationlevel….
<mappings><configuration><relationship-type>non-cumulative</relationship-type></configuration></mappings>
classmappinglevel….
<mappings><mappingrelationship-type="non-cumulative"><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><field><a>someList</a><b>someList</b></field></mapping></mappings>
fieldmappinglevel….
<!--objectswillalwaysbeaddedtoanexistingList--><fieldrelationship-type="cumulative"><a>hintList</a><b>hintList</b><a-hint>com.github.dozermapper.core.vo.TheFirstSubClass</a-hint><b-hint>com.github.dozermapper.core.vo.TheFirstSubClassPrime</b-hint></field>
<!--objectswillupdatedifalreadyexistinList,addediftheyarenotpresent--><fieldrelationship-type="non-cumulative"><a>unequalNamedList</a><b>theMappedUnequallyNamedList</b></field>
Note:ifyoudonotdefinecustomequals()andhashCode()methodsnon-cumulativeoptionwillnotfunctionproperly,asDozerwillfailtodetermineobjectequalityandwillrelyonJDKgeneratedobjectIds.Indefaultcasetwoinstancesofaclassarealwaystreatedasdifferentandupdatewillnotoccure.
RemovingOrphans
CollectionsandArrays
46
Orphansareelementswhichexistinadestinationcollectionthatdidnotexistwithinthesourcecollection.Dozerwillremoveorphansbycallingthe'remove'methodonactualorphansoftheunderlyingdestinationcollection;itwillnotclearall.Todetermineelementswhichareorphansdozerusesthecontains()methodtocheckiftheresultscontainsorphans.Thedefaultsettingvalueisfalse.
<!--orphanobjectswillalwaysberemovedfromanexistingdestinationList--><fieldremove-orphans="true"><a>srcList</a><b>destList</b></field>
CollectionsandArrays
47
MapBackedPropertyMapping
MaptoMap
Dozerwillmapajava.util.Maptoajava.util.Map.Iftherearecomplextypeswithhintsitwilldodeeprecursionmappingaswell.Ifthedestinationmapexistsitwilladdelementstotheexistingmap.
<mapping><class-a>com.github.dozermapper.core.vo.map.MapToMap</class-a><class-b>com.github.dozermapper.core.vo.map.MapToMapPrime</class-b><field><a>standardMapWithHint</a><b>standardMapWithHint</b><a-hint>com.github.dozermapper.core.vo.TestObject</a-hint><b-hint>com.github.dozermapper.core.vo.TestObjectPrime</b-hint></field></mapping>
MappingFieldLevelPropertiestoajava.util.MaporaCustomMapwithuniqueGet/Setmethods
Dozersupportsmappingmapbackedpropertiesatthefieldlevel.Themapcaneitherimplementthejava.util.MapInterfaceorbeacustommapwithasetofuniqueGet/Setmethods.
InthisexampleFieldAisabasicStringanditismappedtoFieldBwhichisaHashMap.ThekeyintheHashMapwillbe"stringProperty"(theattributename)andthevaluewillbewhatevervalueisstoredinthatattribute.
<mapping><class-a>com.github.dozermapper.core.vo.map.PropertyToMap</class-a><class-b>com.github.dozermapper.core.vo.map.MapToProperty</class-b><field><a>stringProperty</a><b>hashMap</b></field></mapping>
ThisexampleshowsFieldAisabasicStringanditismappedtoFieldBwhichisaHashMap.ThekeyintheHashMapwillbe"myStringProperty"andthevaluewillbewhatevervalueisstoredinthatattribute.AlsonoticethatFieldAhasauniquesetter()methodname.
<mapping><class-a>com.github.dozermapper.core.vo.map.PropertyToMap</class-a><class-b>com.github.dozermapper.core.vo.map.MapToProperty</class-b><field><aset-method="addStringProperty2">stringProperty2</a><bkey="myStringProperty">hashMap</b></field></mapping>
ThisexampleshowsFieldAisabasicStringanditismappedtoFieldBwhichisacustommap.Thekeyinthecustommapwillbe"myCustomProperty"andthevaluewillbewhatevervalueisstoredinthatattribute.NoticethatFieldBhasuniquemapgetter()andmapsetter()methodnames.IfyouareusingacustommapyoumustexplicitlysetthemapGet/Setmethodnames.AdestinationhintcanalsobeprovidedifyourcustommapimplementsanInterfaceorisanAbstractclass.
MapBackedPropertyMapping
48
<mapping><class-a>com.github.dozermapper.core.vo.map.PropertyToMap</class-a><class-b>com.github.dozermapper.core.vo.map.MapToProperty</class-b><field><a>stringProperty3</a><bmap-get-method="getValue"map-set-method="putValue"key="myCustomProperty">customMap</b></field><field><a>stringProperty4</a><bmap-get-method="getValue"map-set-method="putValue"key="myCustomNullProperty">nullCustomMap</b><b-hint>com.github.dozermapper.core.vo.map.CustomMap</b-hint></field><field><a>stringProperty5</a><bmap-get-method="getValue"map-set-method="putValue">customMap</b></field></mapping>
MappingClassLevelPropertiestoajava.util.MaporaCustomMapwithuniqueGet/Setmethods
Dozercanalsomapentirecomplexobjectsdirectlytoajava.util.Maporacustommapobject.Thisexampleshowsthedeclarationofamappingbetweenacomplexobject(PropertyToMap)andajava.util.Map.Whendoingthisyouneedtoexplicitlydefineauniquemap-idforthemapping.Thisisusedwhendeterminingwhichmaptouseatrun-time.EveryattributeonthePropertyToMapclasswillbemappedtothejava.util.Map.YouDONOTneedtoexplicitlydefinethesemappings.Fieldexcludemappingscanbeusedtoexcludefieldsatrun-time.Iftheattributenameisnotthesameasthemapkeyjustsetthekeyattributeforacustomfieldmapping.ThemappingtostringProperty2showsanexampleofthis.
Thesecondexampleshowshowtosetupacustommapobject.Theonlydifferencehereisthatyouneedtoexplicitlydefinemap-set-methodandmap-get-methodvalues.Thesecorrespondtothejava.util.Mapget()andput()methods.
<mappingmap-id="myTestMapping"><class-a>com.github.dozermapper.core.vo.map.PropertyToMap</class-a><class-b>java.util.Map</class-b><field><aset-method="addStringProperty2">stringProperty2</a><bkey="myStringProperty">this</b></field><field-exclude><a>excludeMe</a><b>this</b></field-exclude></mapping><mappingmap-id="myCustomTestMapping"><class-a>com.github.dozermapper.core.vo.map.PropertyToMap</class-a><class-bmap-set-method="putValue"map-get-method="getValue">com.github.dozermapper.core.vo.map.CustomMap</class-b><field><aset-method="addStringProperty2">stringProperty2</a><bkey="myStringProperty">this</b></field><field-exclude><a>excludeMe</a><b>this</b></field-exclude></mapping>
MapBackedPropertyMapping
49
Theexamplebelowshowshowtousethesemappings.Noticethatthefieldmappingsreferenceamap-id.ThefirstfieldmappingwillusethemyTestMappingdefinedmappingandmapaccordingly.Samegoeswiththecustommapping.
<mapping><class-a>com.github.dozermapper.core.vo.map.MapTestObject</class-a><class-b>com.github.dozermapper.core.vo.map.MapTestObjectPrime</class-b><fieldmap-id="myTestMapping"><a>propertyToMap</a><b>propertyToMapMap</b></field><fieldmap-id="myTestMapping"><a>propertyToMapToNullMap</a><b>nullPropertyToMapMap</b><b-hint>java.util.HashMap</b-hint></field><fieldmap-id="myCustomTestMapping"><a>propertyToCustomMap</a><b>propertyToCustomMapMap</b></field></mapping>
TheClassLevelmapbackedmappingscanalsobeusedasastandardmapping.ForthisdozerhasanewAPI.InadditiontothesourceanddestinationclassesyoucannowpassinthemapreferenceId.
//Example1PropertyToMapptm=newPropertyToMap();ptm.setStringProperty("stringPropertyValue");ptm.addStringProperty2("stringProperty2Value");Mapmap=Mapper.map(ptm,HashMap.class,"myTestMapping");
//Example2CustomMapcustomMap=mapper.map(ptm,CustomMap.class,"myCustomTestMapping");
//Example3CustomMapcustom=newCustomMap();custom.putValue("myKey","myValue");Mapper.map(ptm,custom,"myCustomTestMapping");
//Example4-MapBackMapmap=newHashMap();map.put("stringProperty","stringPropertyValue");PropertyToMapproperty=mapper.map(map,PropertyToMap.class,"myTestMapping");assertEquals("stringPropertyValue",property.getStringProperty());
MapBackedPropertyMapping
50
ProxyObjects
Overview
Dozersupportsmappingsdoneonproxyobjects.Thisistypicallythecasewhenusingpersistenceframework,whichsupportssophisticatedfeatureslikelazy-loading.Inthiscaseapplicationisworkingwithfakeobjects,containingtherealobjectsencapsulated.Implementationofproxiesisdependantonthetechnologyyouuse.Generallyspeaking,therearetwopopularlibrariesforcreatingJavaproxies(CglibandJavassist).However,howparticularframeworkmakesusesofthemcouldalsovary.Dozeroffersbydefaultagenericwaytohandlesimpleproxyscenarios,bothJavassistandCglib.Howeveritisstronglyrecommendedtotuneproxyhandlingbehaviorforyourparticularscenario.
Configuration
Proxyimplementationisset-upbymodifyingconfigurationfile.Currently,besidesofdefaultbehavior,HibernateandNo-Proxymodesaresupported.Forthefulllistoftheimplementations,seethelistofcom.github.dozermapper.core.util.DozerProxyResolverinterfaceimplementations.ThelistcouldberetrievedfromJavaDocs.
Incaseyoudonotmapproxiedobjects-useNoProxyresolver,whichimposesminimumperformanceoverhead.
CustomScenarios
Forcustomscenariositispossibletoprovideyourownimplementationofcom.github.dozermapper.core.util.DozerProxyResolverinterface.Itisconfiguredinthesamewayasthestandardclasses.
ProxyObjects
51
CustomConvertersCustomconvertersareusedtoperformcustommappingbetweentwoobjects.IntheConfigurationblock,youcanaddsomeXMLtotellDozertouseacustomconverterforcertainclassAandclassBtypes.WhenacustomconverterisspecifiedforaclassAandclassBcombination,Dozerwillinvokethecustomconvertertoperformthedatamappinginsteadofthestandardmappinglogic.
Yourcustomconvertermustimplementthecom.github.dozermapper.core.CustomConverterinterfaceinorderforDozertoacceptit.Otherwiseanexceptionwillbethrown.
Customconvertersaresharedacrossmappingfiles.ThismeansthatyoucandefinethemonceinamappingfileanditwillbeappliedtoallclassmappingsinothermappingfilesthatmatchtheClassA-ClassBpattern.Intheexamplebelow,wheneverDozercomesacrossamappingwherethesrc/destclassmatchthecustomconverterdefinition,itwillinvokethecustomconverterclassinsteadofperformingthetypicalmapping.
<?xmlversion="1.0"encoding="UTF-8"?><mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttp://dozermapper.github.io/schema/bean-mapping.xsd"><configuration><custom-converters><!--thesearealwaysbi-directional--><convertertype="com.github.dozermapper.core.converters.TestCustomConverter"><class-a>com.github.dozermapper.core.vo.CustomDoubleObject</class-a><class-b>java.lang.Double</class-b></converter><!--YouareresponsibleformappingeverythingbetweenClassAandClassB--><convertertype="com.github.dozermapper.core.converters.TestCustomHashMapConverter"><class-a>com.github.dozermapper.core.vo.TestCustomConverterHashMapObject</class-a><class-b>com.github.dozermapper.core.vo.TestCustomConverterHashMapPrimeObject</class-b></converter></custom-converters></configuration></mappings>
Customconverterscanalsobespecifiedattheindividualfieldlevel.Intheexamplebelow,Dozerwillinvokethecustomconvertertoperformthefieldmapping.
<mapping><class-a>com.github.dozermapper.core.vo.SimpleObj</class-a><class-b>com.github.dozermapper.core.vo.SimpleObjPrime2</class-b><fieldcustom-converter="com.github.dozermapper.core.converters.StringAppendCustomConverter"><a>field1</a><b>field1Prime</b></field></mapping>
Customconverter'instances'canbereusedattheindividualfieldlevel.Intheexamplebelow,Dozerwillinvokethecustomconvertertoperformthefieldmapping.
<mapping><class-a>com.github.dozermapper.core.vo.SimpleObj</class-a><class-b>com.github.dozermapper.core.vo.SimpleObjPrime2</class-b>
CustomConverters
52
<fieldcustom-converter-id="CustomConverterWithId"><a>field1</a><b>field1Prime</b></field></mapping>
CustomConverterinstancescanbeprovidedduringconfigurationofMapperviaDozerBeanMapperBuilder#withCustomConverter(..)method.
<?xmlversion="1.0"encoding="UTF-8"?><beansdefault-lazy-init="false"><beanid="com.github.dozermapper.core.Mapper"class="com.github.dozermapper.core.DozerBeanMapper"><propertyname="mappingFiles"><list><value>dozerBeanMapping.xml</value><value>injectedCustomConverter.xml</value></list></property><propertyname="customConvertersWithId"><map><entrykey="CustomConverterWithId"ref="configurableConverterBeanInstance1"/><entrykey="CustomConverterWithId2"ref="configurableConverterBeanInstance2"/></map></property></bean></beans>
Samplecustomconverterimplementation:
Note:CustomConvertersgetinvokedwhenthesourcevalueisnull,soyouneedtoexplicitlyhandlenullvaluesinyourcustomconverterimplementation.
importcom.github.dozermapper.core.CustomConverter;importcom.github.dozermapper.core.MappingException;
publicclassTestCustomConverterimplementsCustomConverter{
@OverridepublicObjectconvert(ObjectexistingDestinationFieldValue,ObjectsourceFieldValue,Class<?>destinationClass,Class<?>sourceClass){if(sourceFieldValue==null){returnnull;}
CustomDoubleObjectdest;if(sourceinstanceofDouble){//checktoseeiftheobjectalreadyexistsif(destination==null){dest=newCustomDoubleObject();}else{dest=(CustomDoubleObject)destination;}
dest.setTheDouble(((Double)source).doubleValue());
returndest;}elseif(sourceinstanceofCustomDoubleObject){doublesourceObj=((CustomDoubleObject)source).getTheDouble();returnnewDouble(sourceObj);}else{thrownewMappingException("ConverterTestCustomConverter"+"usedincorrectly.Argumentspassedinwere:"+destination+"and"+source);
CustomConverters
53
}}}
CustomConverterscanalsobeinjectedintotheMapperifyouneedtodosomemanipulationwiththembeforetheyareusedindozer.
<?xmlversion="1.0"encoding="UTF-8"?><beansdefault-lazy-init="false"><beanid="com.github.dozermapper.core.Mapper"class="com.github.dozermapper.core.DozerBeanMapper"><propertyname="mappingFiles"><list><value>dozerBeanMapping.xml</value><value>injectedCustomConverter.xml</value></list></property><propertyname="customConverters"><list><refbean="customConverterTest"/></list></property></bean><!--customconverter--><beanid="customConverterTest"class="com.github.dozermapper.core.converters.InjectedCustomConverter"><propertyname="injectedName"><value>injectedName</value></property></bean></beans>
SupportforArrayTypes
YoucanspecifyacustomconverterforArraytypes.Forexample,ifyouwanttouseacustomconverterformappingbetweenanarrayofobjectsandaStringyouwouldusethefollowingmappingnotation.DozergenericallyusesClassLoader.loadClass()whenparsingthemappingfiles.Forarrays,javaexpectstheclassnameinthefollowingformat:[Lcom.github.dozermapper.core.vo.SimpleObj;
<convertertype="com.github.dozermapper.core.converters.StringAppendCustomConverter"><class-a>[Lcom.github.dozermapper.core.vo.SimpleObj;</class-a><class-b>java.lang.String</class-b></converter>
Supportforprimitives
Youcanspecifyacustomconverterforprimitivetypes.Justusetheprimitivewrapperclasswhendefiningthecustomconvertermapping.Inthefollowingexample,DozerwillusethespecifiedcustomconverterwhenmappingbetweenSomeObjectandtheintprimitivetype.NotethatDozerwillalsousethecustomconverterwhenmappingbetweenSomeObjectandtheIntegerwrappertype.
<convertertype="somePackage.SomeCustomConverter"><class-a>somePackage.SomeObject</class-a><class-b>java.lang.Integer</class-b></converter>
ConfigurableCustomConverters
CustomConverters
54
Youcandefineacustomconverter,whichcanbeconfiguredfrommappingsviaconfigurationparameter.InthiscaseyoushouldimplementConfigurableCustomConverterinterfaceinsteadofusualCustomConverter.Configurableconverterhasadditionalattributeprovidedinruntime-param.Parameterisprovidedusingcustom-converter-paramattribute.
<mapping><class-a>com.github.dozermapper.core.vo.BeanA</class-a><class-b>com.github.dozermapper.core.vo.BeanB</class-b><fieldcustom-converter="com.github.dozermapper.core.converters.MathOperationConverter"custom-converter-param="+"><a>amount</a><b>amount</b></field></mapping>
Configurablecustomconvertershouldbeusedwhenyouhavesimilarbehaviourinmanycases,whichcanbeparametrized,butthenumberofcombinationsistoohightodosimpleCustomConvertersubclassing.
importcom.github.dozermapper.core.ConfigurableCustomConverter;importcom.github.dozermapper.core.MappingException;
publicclassMathOperationConverterimplementsConfigurableCustomConverter{
privateStringparameter;
@OverridepublicvoidsetParameter(Stringparameter){this.parameter=parameter;}
@OverridepublicObjectconvert(ObjectexistingDestinationFieldValue,ObjectsourceFieldValue,Class<?>destinationClass,Class<?>sourceClass){Integersource=(Integer)sourceFieldValue;Integerdestination=(Integer)existingDestinationFieldValue;
if("+".equals(parameter)){returndestination.intValue+source.intValue();}
if("-".equals(parameter)){returndestination.intValue-source.intValue();}
thrownewMappingException("ConverterMathOperationConverter"+"usedincorrectly.Argumentspassedinwere:"+destination+","+source+"and"+parameter);}}
NewCustomConverterAPI
WhileprovidinggreatdealofflexibilityCustomConverterAPIdescribedaboveiswrittenonfairlylowlevelofabstraction.Thisresultsinconverter,whichcodeisdifficulttounderstandandtoreuseinotherwaysthanpluggingintoDozermapping.Howeveritisnotuncommonsituationwhenthesameconversionlogicshouldbecalledfromaplaceotherthanbeanmappingframework.versionofDozergetsshippedwithnew-cleanerAPIfordefiningcustomconverter,whichgivesyoumoreobviousAPIwhiletakingawaycertainpartofcontroloftheexecutionsflow.Thefollowingexampledemonstratessimple,yetworkingconverterusingnewAPI.
CustomConverters
55
importcom.github.dozermapper.core.DozerConverter;
publicclassNewDozerConverterextendsDozerConverter<String,Boolean>{
publicNewDozerConverter(){super(String.class,Boolean.class);}
@OverridepublicBooleanconvertTo(Stringsource,Booleandestination){if("yes".equals(source)){returnBoolean.TRUE;}elseif("no".equals(source)){returnBoolean.FALSE;}thrownewIllegalStateException("Unknownvalue!");}
@OverridepublicStringconvertFrom(Booleansource,Stringdestination){if(Boolean.TRUE.equals(source)){return"yes";}elseif(Boolean.FALSE.equals(source)){return"no";}thrownewIllegalStateException("Unknownvalue!");}}
NotethatJava5Genericsaresupportedandyoudonotneedtocastsourceobjecttodesiredtypeaspreviously.
DataStructureConversions
Therearecaseswhereitisrequiredtoperformprogrammaticdatastructureconversion,saycopyeachoddelementinalistasmapkey,buteachevenasmapvalue.InthiscaseitisneededtodefinetransformationofthestructurewhilerelyingonusualDozermappingsupportforindividualvalues.ForthispurposesitispossibletouseMapperAwareinterface,whichinjectscurrentmapperinstanceinsidecustomconverter.
importjava.util.HashMap;importjava.util.List;importjava.util.Map;
importcom.github.dozermapper.core.DozerConverter;importcom.github.dozermapper.core.Mapper;importcom.github.dozermapper.core.MapperAware;
publicclassConverterextendsDozerConverter<List,Map>implementsMapperAware{
privateMappermapper;
publicConverter(){super(List.class,Map.class);}
@OverridepublicvoidsetMapper(Mappermapper){this.mapper=mapper;}
@OverridepublicMapconvertTo(Listsource,Mapdestination){MaporiginalToMapped=newHashMap();for(Sourceitem:source){TargetmappedItem=mapper.map(item,Target.class);
CustomConverters
56
originalToMapped.put(item,mappedItem);}returnoriginalToMapped;}
@OverridepublicListconvertFrom(Mapsource,Listdestination){thrownewIllegalStateException("Notimplemented");}}
CustomConverters
57
CustomBeanFactoriesYoucanconfigureDozertousecustombeanfactoriestocreatenewinstancesofdestinationdataobjectsduringthemappingprocess.BydefaultDozerjustcreatesanewinstanceofanydestinationobjectsusingadefaultconstructor.Thisissufficientformostusecases,butifyouneedmoreflexibilityyoucanspecifyyourownbeanfactoriestoinstantiatethedataobjects.
Yourcustombeanfactorymustimplementthecom.github.dozermapper.core.BeanFactoryinterface.BydefaulttheDozermappingenginewillusethedestinationobjectclassnameforthebeanidwhencallingthefactory.
publicinterfaceBeanFactory{publicObjectcreateBean(Objectsource,ClasssourceClass,StringtargetBeanId,BeanContainerbeanContainer);}
Next,inyourDozermappingfile(s)youjustneedtospecifyabean-factoryxmlattributeforanymappingsthatyouwanttouseacustomfactory.
Inthefollowingexample,theSampleCustomBeanFactorywillbeusedtocreateanynewinstancesoftheInsideTestObjectPrimejavabeandataobject.
<mapping><class-a>com.example.vo.InsideTestObject</class-a><class-bbean-factory="com.example.factories.SomeCustomBeanFactory">com.example.vo.InsideTestObjectPrime</class-b></mapping>
Ifyourfactorylooksupbeansbasedonadifferentidthanclassname,youcanspecifyafactory-bean-idxmlattribute.Atruntimethespecifiedfactory-bean-idwillbepassedtothefactoryinsteadofclassname.
<mapping><class-a>com.example.vo.InsideTestObject</class-a><class-bbean-factory="com.example.factories.SomeCustomBeanFactory"factory-bean-id="someBeanLookupId">com.example.vo.InsideTestObjectPrime</class-b></mapping>
SpecifyingDefaultFactories
Alternatively,beanfactoriescanbespecifiedinthedefaultconfigurationsectionofanyDozermappingfile(s).Thedefaultfactorywouldbeusedforanymappingsinthatfile.
<configuration><stop-on-errors>true</stop-on-errors><wildcard>true</wildcard><bean-factory>com.example.factories.SomeDefaultBeanFactory</bean-factory></configuration>
Beanfactoriescanalsobespecifiedatthemappinglevel.Thespecifiedfactorywouldbeusedforclass-aandclass-b.
<mappingbean-factory="com.example.factories.SomeCustomBeanFactory"><class-a>com.example.vo.TestObject</class-a>
CustomBeanFactories
58
<class-b>com.example.vo.TestObjectPrime</class-b></mapping>
Springbeanfactoryinjection
BeanfactoriescanbeinjectedviaSpringorsimilarinversionofcontroltechniques.
<beans><beanid="com.github.dozermapper.core.Mapper"class="com.github.dozermapper.core.DozerBeanMapper"><propertyname="mappingFiles"><list><value>dozerBeanMapping.xml</value></list></property><propertyname="factories"><map><!--thekeymatchesthenameofthefactoryinthedozerBeanMapping.xmlfile--><entrykey="com.github.dozermapper.core.factories.SampleCustomBeanFactory"><refbean="sampleCustomBeanFactory"/></entry><!--morefactoriescanbesuppliedwithadditionalentry's--></map></property></bean><beanid="sampleCustomBeanFactory"class="com.github.dozermapper.core.factories.SampleCustomBeanFactory"/></beans>
BydefiningyourfactoriesasSpringbeansyoucantheninjectthemintotheMapperinstance.
CustomBeanFactories
59
CustomCreateMethodsYoucanconfigureDozertousecustomstaticcreatemethodstocreatenewinstancesofdestinationdataobjectsduringthemappingprocess.Thiscaneitherbesetatthefieldlevelorclasslevel.
<mapping><class-acreate-method="someCreateMethod">com.github.dozermapper.core.vo.InsideTestObject</class-a><class-b>com.github.dozermapper.core.vo.InsideTestObjectPrime</class-b><field><a>label</a><b>labelPrime</b></field></mapping>
SpecifyingacustomcreatemethodattheFieldlevel….
<mapping><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-b>com.github.dozermapper.core.vo.TestObjectPrime</class-b><field><a>createMethodType</a><bcreate-method="someCreateMethod">createMethodType</b></field></mapping>
Itisalsopossibletoreferencedifferentclasswithstaticfactorymethod.Thisisdonebyprovidingfullyqualifiedtypenameandmethodnameseparatedbydot.
<bcreate-method="com.github.dozermapper.core.factory.Factory.create">field</b>
CustomCreateMethods
60
Customget()set()Methods
Mappingafieldwithnoget()orset()methods
Usetheattributeis-accessibletodeclarethatthefieldcanbeaccesseddirectly.Dozerisabletoaccessprivatepropertiesthatdonothavegetterorsettermethods.
<field><a>fieldAccessible</a><bis-accessible="true">fieldAccessible</b></field>
CustomSet()andGet()methods(bi-directional)
Forthosebeansthatmighthaveunorthodoxgetterandsettermethods,Dozersupportuserspecifiedsetterandgettermethods.Tomakeabi-directionalmappinginthiscase,lookatthefollowingexamplebelow.ThesourcefieldinelementAspecifiesacustomsettermethodandgettermethodusingattributes.
<field><aset-method="placeValue"get-method="buildValue">value</a><b>value</b></field>
InthiscasewearemappingaStringtoanArrayListbycallingtheaddIntegerToList()method.Notethatthisisdefinedasaone-wayfieldtypesincewecannotmapanArrayListtoaString.
<!--wecannotmapaArrayListtoaString,hencetheone-waymapping--><fieldtype="one-way"><a>integerStr</a><bset-method="addIntegerToList">integerList</b></field>
OverloadedSet()methods(bi-directional)
Sometimesset()methodscanbeoverloaded.Inordertochosethecorrectoneyoucanaddtheclasstypeasaparameter.
<field><a>overloadGetField</a><bset-method="setOverloadSetField(java.util.Date)">overloadSetField</b></field>
IterateMethodMapping(bi-directional)
Dozeralsosupportsiteratemethodlevelmapping.InthefollowingexampletheListappleComputerswillbeiteratedthroughandforeachobjectthemethodaddComptuerwillbecalled.Anyfieldthatisdenotedastype=iteraterequiresahint.Theget()methodcanreturnanArray,List,orIterator.
<field><a>appleComputers</a><bset-method="addComputer"type="iterate">computers</b>
Customget()set()Methods
61
<b-hint>com.github.dozermapper.core.vo.AppleComputer</b-hint></field>
Belowisanexamplewithiteratemethodsonbothfields.
<field><aset-method="addCar"get-method="myIterateCars"type="iterate">iterateCars</a><bset-method="addIterateCar"type="iterate">iterateCars</b><a-hint>com.github.dozermapper.core.vo.Car</a-hint><b-hint>com.github.dozermapper.core.vo.Car</b-hint></field>
Customget()set()Methods
62
ExpressionLanguage
Usage
Dozerprovidesoptionalsupportforstandardjavaexpressionlanguage(javax.el).
Currentsupportforexpressionsisstart-uptimeonly.Expressionsarenotresolvedduringeachmapping,butratherduringmappingloadingtime.EachattributeornodevaluecancontainavalidELexpression${}.
DozersupportsanyELimplementationwrittenagainstjavax.elstandardAPI.Functionalityistestedwith'glassfish'internally,butotherELprovidersshouldworkaswell.
Youcandefineglobalvariablesforthemapperinvariablesconfigurationblock.
<configuration><wildcard>true</wildcard><variables><variablename="type_name">com.github.dozermapper.core.sample.MyType</variable></variables></configuration><mapping><class-a>${type_name}</class-a><class-b>com.github.dozermapper.core.sample.OtherType</class-b></mapping>
Enabling
ELsupportisanoptionalfeature.Toenableit,youmustaddthebelowdependenciestoyourclasspath:
<dependency><groupId>javax.el</groupId><artifactId>javax.el-api</artifactId><version>3.0.0</version></dependency><dependency><groupId>org.glassfish</groupId><artifactId>javax.el</artifactId><version>3.0.0</version></dependency>
ItisthisenabledontheMapperbythebelowfluentconstruct:
Mappermapper=DozerBeanMapperBuilder.create().withMappingFiles(mappingFiles).withELEngine(newDefaultELEngine()).build();
ExpressionLanguage
63
LoggingTheloggingfacadeframeworkinDozerisSLF4J.ItreplacedCommonsLogging,whichwasusedinprojectpreviouslyuntilversion5.3.
PleaserefertoSLF4JDocumentationformoreinformationonsettingupandconfiguringdifferentloggingimplementations.
Logging
64
EventListeningByimplementingtheEventListenerinterfacedozerallowsyoutolistento4differentevents:
mappingStarted
mappingFinished
preWritingDestinationValue
postWritingDestinationValue
AnEventobjectispassedintothesecallbackmethodswhichstoresinformationabouttheClassMap,FieldMap,sourceobject,destinationobject,anddestinationvalue.ThiswillallowyoutoextendDozerandmanipulatemappedobjectsatrun-time.Theinterfaceisshownbelow:
publicinterfaceEventListener{
publicvoidonMappingStarted(Eventevent);
publicvoidonPreWritingDestinationValue(Eventevent);
publicvoidonPostWritingDestinationValue(Eventevent);
publicvoidonMappingFinished(Eventevent);}
ThelistenersthatyoucreatecanbeinjectedintotheMapperusinganIOClikeSpringorsetdirectlyduringMapperinstanceconfigurationusingDozerBeanMapperBuilder#withEventListener(..)method.BelowisanexampleusingSpringtoinjectaneventlistener:
<?xmlversion="1.0"encoding="UTF-8"?><beansdefault-lazy-init="false"><beanid="EventMapper"class="com.github.dozermapper.core.DozerBeanMapper"><propertyname="mappingFiles"><list><value>dozerBeanMapping.xml</value></list></property><propertyname="eventListeners"><list><refbean="eventTestListener"/></list></property></bean><beanid="eventTestListener"class="com.github.dozermapper.core.event.EventTestListener"/></beans>
EventListening
65
QueryingmappingmetadataThissectionwillcoverthemappingmetadatainterface.Itprovideseasytouseread-onlyaccesstoallimportantpropertiesoraspectsofthecurrentlyactivemappingdefinitions.
Thefollowingsectionswillgivesomecodeexampleshowtousethemappingqueryinterfaces.Themostimportantinterfaceinthewholeprocessiscom.github.dozermapper.core.metadata.MappingMetadata.AninstancecanbeacquiredbycallingthegetMappingMetadata()methodoftheMapperinstance.
Considerthefollowingmappingfile:
<?xmlversion="1.0"encoding="UTF-8"?><mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttp://dozermapper.github.io/schema/bean-mapping.xsd"><mapping><class-a>com.github.dozermapper.core.vo.ClassA</class-a><class-b>com.github.dozermapper.core.vo.ClassB</class-b><field><a>fieldA</a><b>fieldB</b></field></mapping></mappings>
Tobeginqueryingthemappingdefinitionsthefollowingcodeisneeded:
Mappermapper=DozerBeanMapperBuilder.create().withMappingFiles(listOfFiles).build();MappingMetadatamapMetadata=mapper.getMappingMetadata();
NowthatareferencetoMappingMetadataisobtainedwecanstartqueryingforacertainclassmappingdefinition:
try{ClassMappingMetadataclassMappingMetadata=mapMetadata.getClassMapping(ClassA.class,ClassB.class);}catch(MetadataLookupExceptione){//couldn'tfindit}
WhenholdingareferencetoaClassMappingMetadatainterface,queriesforindividualfieldmappingscanbeexecuted:
try{FieldMappingMetadatafieldMetadata=classMetadata.getFieldMappingBySource("fieldA");//Destination:fieldBSystem.out.println("Destination:"+fieldMetadata.getDestinationName());}catch(MetadataLookupExceptione){//couldn'tfindit}
ForextensivedocumentationonthedifferentinterfacespleaserefertotheJavaDoc.
MetadataQueryInterface
66
MetadataQueryInterface
67
SpringFrameworkIntegrationWeprovidethedozer-spring4forintegratingspringapplication.IfyouareusingApacheMaven,simplycopy-pastethisdependencytoyourproject.
pom.xml
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>{dozer-version}</version></dependency><dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-spring4</artifactId><version>{dozer-version}</version></dependency>
Configuration
AddtheDozerBeanMapperFactoryBeantoyourSpringconfigurationfile.ThemappingFilespropertyiswhereyoushouldspecifyanycustomdozermappingfilesthatyouhavecreated.Thislistcanbeemptyifyoudon’thaveanycustommappings.Itisalsopossibletosetcustomeventlistenersandbeanfactories.
Important
YoushoulddefinetheDozermapperbeanisdefinedassingleton="true".YoushouldconfiguretheMapperinstance(s)thiswaysothatyoudonothavetoreloadandreinitializethemappingfilesforeachindividualmappingduringthelifecycleofyourapp.Reinitializingthemappingfilesforeachmappingwouldbeinefficientandunnecessary.TheDozerBeanMapperclassisthreadsafe.
XMLbasedconfiguration
NotethatthisFactoryBeansupportsSpringResources,whichmeansthatyoucouldloadmappingXmlfilesbyclasspathmaskforexample.
<beanid="dozerMapper"class="com.github.dozermapper.spring.DozerBeanMapperFactoryBean"><propertyname="mappingFiles"value="classpath*:/*mapping.xml"/><propertyname="customConverters"><list><beanclass="com.github.dozermapper.core.converters.CustomConverter"/></list></property><propertyname="eventListeners"><list><beanclass="com.github.dozermapper.core.listeners.EventListener"/></list></property><propertyname="factories"><map><entrykey="id"value-ref="bean-factory-ref"/></map></property></bean>
Alternatively,youcandefinetheDozerBeanMapperusingthedozernamespaceasfollow:
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dozer="http://dozermapper.github.io/schema/dozer-spring"
SpringIntegration
68
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://dozermapper.github.io/schema/dozer-springhttps://dozermapper.github.io/schema/dozer-spring.xsd">
<dozer:mapperid="dozerMapper"/>
</beans>
Javabasedconfiguration
WhenusingJavaconfiguration,beandefinitionisasfollows:
@ConfigurationpublicclassDozerConfig{@BeanpublicDozerBeanMapperFactoryBeandozerMapper(ResourcePatternResolverresourcePatternResolver)throwsIOException{DozerBeanMapperFactoryBeanfactoryBean=newDozerBeanMapperFactoryBean();factoryBean.setMappingFiles(resourcePatternResolver.getResources("classpath*:/*mapping.xml"));//...returnfactoryBean;}}
Howtouseinyourapplication
UsingSpringtoretrievetheDozerMapper……
Look-upbasedusage
YoucanusetheDozerMapperthatlookedupfromtheSpringApplicationContext(BeanFactory).
MapperdozerMapper=applicationContext.getBean("dozerMapper",Mapper.class);DestinationObjectdestObject=dozerMapper.map(sourceObject,DestinationObject.class);
Injectionbasedusage
Alternatively,youcanusetheDozerMapperthatinjectedtoyourcomponentbySpringDIcontainer.
@ComponentpublicclassYourComponent{privatefinalMapperdozerMapper;publicYourComponent(MapperdozerMapper){this.dozerMapper=dozerMapper;}publicvoidanyMethod(){//...DestinationObjectdestObject=dozerMapper.map(sourceObject,DestinationObject.class);//...}}
HowtouseinSpringBootApplication
PleaseseeSpringBootIntegrationsection.
SpringIntegration
69
SpringIntegration
70
SpringBootIntegrationWeprovidethedozer-spring-boot-starterforintegratingspringbootapplicationsince6.2.0.IfyouareusingApacheMaven,simplycopy-pastethisdependencytoyourproject.
Note FordetailsforSpringFramewrokIntegration,pleaseseehere.
pom.xml
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-spring-boot-starter</artifactId><version>{dozer-version}</version></dependency>
Youcanspecifyanycustomdozermappingfilesinyourapplicationpropertiesoryml.
application.properties
dozer.mapping-files=classpath*:/*mapping.xml
application.yml
dozer:mapping-files:classpath*:/*mapping.xml
SpringBootIntegration
71
3rdPartyObjectFactoriesDozersupportsmappingofplainJavaobjectstoframeworksthatrequireinstantiationofobjectsviacertainconventionofcallingfactorymethods.Toreproducetheexpectedbehaviorcustombeanfactoriesshouldbeused.
MappingJAXBObjects
DozerhassupportformappingPOJOstoJAXBobjects.UsetheJAXBBeanFactoryforanyJAXBobjectsyouwantcreate.
<mapping><class-a>com.github.dozermapper.core.vo.TestObject</class-a><class-bbean-factory="com.github.dozermapper.core.factory.JAXBBeanFactory">com.github.dozermapper.core.vo.jaxb.employee.Employee</class-b><field><a>name</a><b>firstName</b></field><field><a>street</a><b>address.street</b></field></mapping>
JAXB
72
FrequentlyAskedQuestions
Common
Whattypesofdataobjectsaresupported?
WillDozerautomaticallyperformdatatypeconversions?
DoesDozerautomaticallymapfieldswithmatchingpropertynames?
IsDozerrecursive?
Willthegetterandsettermethodsbeinvokedwhenfieldsaremapped?
AreCollectionsandArrayssupported?
AreMaptypeobjects(i.eHashMap)supported?
Areabstractclasses,inheritance,andinterfacemappingsupported?
CanDozerbeconfiguredviaSpring?
WhichtypesofdatamappingsdoIneedacustomxmlmappingdefinitionfor?
Ifmysrcanddestobjecthaveallmatchingattributenames,doIneedtospecifyanyxmlmappingdefinitionsatall?
Formappingsthatrequireanxmlmappingdefinition,isthemappingdefinitionbi-directional,ordoIneed2xmldefinitionsifIneedtomapthetwoobjectsbothways?
Howarethecustomxmlmappingfilesloaded?
CanIloadamappingfilethatisnotintheclasspath?
HowcanItellifDozerisinitializingcorrectlyandloadingmyxmlmappingfiles?
HowdoesDozerperform?
WhichJDKversionsaresupported?
IsDozerinthemavenrepository?
IsDozergoodfortheenvironment?
Advanced
CanIimplementcustommappinglogicbetween2datatypesandhaveDozerinvokethiscustomlogicwhenit’sperformingmappings?
CanImaponefieldintoanotherfieldthatisnestednlayersdeepinthedestinationobject?
HowdoImapmultiplefieldstoasinglefield?
IfIammappingdataobjectsthathavebi-directionalrelationships,willitresultinaninfiniteloopandeventualstackoverflowerror?
HowdoImapanobjectcontainedinacollectiontoafield?
HowdoImapaComplexobjecttoaHashMapandviceversa?
HowdoImapfieldsthatdon’thavecorrespondinggetter/settermethods?
FAQ
73
Someofmydataobjectsdon’thavepublicconstructors.DoesDozersupportthisusecase?
DoesDozersupportJDK1.5enums?
DoesDozersupportJAXBgenerateddataobjects?
IsthereanEclipsepluginorvisualeditorforDozer?
Whenmappingcollections,howdoItellDozerwhattypeofdataobjectsIwantinthedestinationcollection?
HowcanItellDozertobypassmappingnulloremptystringvalues?
Tips,Tricks,andSuggestions
ShouldIencapsulatelogicthatcopiesdatabetweenobjects?
ShouldIwriteunittestsfordatamappinglogicthatIuseDozertoperform?
ShouldtheDozermapperbeconfiguredasaSingleton?
Isitbettertohave1largexmlmappingfileortohavemultiplesmallermappingfiles?
WhatarethebestwaystodebugDozer?
Whatisthebestwaytosetuptheglobalconfiguration?
Whatisthebestwaytosubmitabug,featurerequest,orpatch?
Answers
Whattypesofdataobjectsaresupported?
Dozerusesreflectiontoaccessdataobjectproperties,soitisdesignedtoworkwithdataobjectsthathavecorrespondinggetterandsettermethodsforitsfields.Forexample,adataobjectthathasafieldnamed"message"shouldhavegetMessageandsetMessagemethods.Dataobjectsthatdon’tfollowthispatternarealsosupported,butwillmostlikelyrequireacustommappingdefinition.Fortheseunorthodoxdataobjects,youcantellDozertodirectlyaccessfields(includingprivate)and/orexplicitlyspecifywhichget/setmethodstouse.
WillDozerautomaticallyperformdatatypeconversions?
Yes.Mostscenariosaresupportedoutofthebox.Theseincludeprimitives,JavaWrapperObjects,Numbersubclasses,Dates,Calendar,Collections,Arrays,Maps,andComplextypes
DoesDozerautomaticallymapfieldswithmatchingpropertynames?
Yes.Allfieldswithmatchingpropertynamesareimplicitlymapped.Itwouldbeatypicalusage,butyoucouldsuppressthisbehaviorbysettingwilcard="false".
IsDozerrecursive?
Yes.Dozerrecursivelymapstheentireobjectgraphforallfields.
Willthegetterandsettermethodsbeinvokedwhenfieldsaremapped?
Yes.Youcanbypassthisdefaultbehaviorbyexplicitlyspecifyingis-accessible="true"foranyofyourmappings.Ifis-accessibleisspecified,thefield(includingprivatefields)isaccesseddirectlyandthegetter/settermethodsarebypassed.Itisnotrecommendedthatyousetis-accessible="true",unlessyouaredealingwithanunorthodoxdata
FAQ
74
objectthatdoesnotcontainanygetterorsettermethods.
AreCollectionsandArrayssupported?
Yes.Dozerautomaticallymapsbetweencollectiontypesandautomaticallyperformsanytypeconversion.
AreMaptypeobjects(i.eHashMap)supported?
Yes.AllJavaMapdatatypesaresupportedinadditiontoanyCustommapdatatypes.
Areabstractclasses,inheritance,andinterfacemappingsupported?
Yes.
CanDozerbeconfiguredviaSpring?
Yes.RefertoSpringIntegrationsectionofthedocumentation.
WhichtypesofdatamappingsdoIneedacustomxmlmappingdefinitionfor?
Onlyfieldsthatcan’tbeimplicitlymappedbymatchingonfieldname,needacustomxmlmappingdefinition.Ideally,thevastmajorityofyourfieldmappingscanbeperformedautomaticallyandonlythefewexceptionalcaseswillneedanexplicitfieldmappinginthexmlmappingfile.
Ifmysrcanddestobjecthaveallmatchingattributenames,doIneedtospecifyanyxmlmappingdefinitionsatall?
Nope.Justinvokethemapper.Youdon’tneedanyexplicitxmlmappingentriesforthiscombinationofsourceanddestinationobject.
Formappingsthatrequireanxmlmappingdefinition,isthemappingdefinitionbi-directional,ordoIneed2xmldefinitionsifIneedtomapthetwoobjectsbothways?
Allmappingdefinitionsarebi-directional,soyouonlyneedonemappingdefinition.Youcanmapa-→bandb-→ausingthissinglemappingdefinition.
Howarethecustomxmlmappingfilesloaded?
Dozerwillsearchtheentireclasspathlookingforthespecifiedfile(s).
CanIloadamappingfilethatisnotintheclasspath?
Yes,youcanloadfilesfromoutsidetheclasspathbyprepending"file:"totheresourcename.Ex)"file:c:\somedozermapping.xml"
HowcanItellifDozerisinitializingcorrectlyandloadingmyxmlmappingfiles?
Setthe-Ddozer.debugsystemproperty.Ifthisisset,DozerinitializationinformationisalsosenttoSystem.out.Ifyouarefamiliarwithlog4j,thisissimilartothe-Dlog4j.debugsystemproperty
FAQ
75
HowdoesDozerperform?
WebelieveDozerperformsverywellandperformanceisahighpriorityforus.Wehavespentasignificantamountoftimeprofilingthecodeandoptimizingbottlenecks.
Performanceisgoingtodependonthecomplexityoftheusecaseandthenumberoffieldsmapped.Inourperformancetestsfor"average"mappingscenarios,theclassmappingtimesvaryfrom1/8ofamillisecondto2milliseconds.Thisroughlyequatesto50-450fieldmappingspermillisecond.However,thenumberofvariablesinanydecentbenchmarkmakesitalmostimpossibletotransfertheseresultsintoreasonableconclusionsabouttheperformanceofyourownapplication.Yourapplicationisdifferentandyouwillhaveuniqueusecases.
Dozerhasbeensuccessfullyimplementedonlarge,veryhightransactionalenterprisesystems,withoutanyresultingperformanceissues.Butwealwaysrecommendthatyourunperformancetestsonyourapplicationtodeterminetheactualperformancecostswithinyoursystem.Youcandecideforyourselfwhetherthosecostsareacceptableinthecontextoftheentiresystem.
WhichJDKversionsaresupported?
JDK1.8andabove.
IsDozerinthemavenrepository?
YesandwewillcontinuetodoourbesttogetfuturereleasesofDozeruploadedintotherepository.
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>{dozer-version}</version></dependency>
IsDozergoodfortheenvironment?
Yes,dozerdoesnotburnanyfossilfuelsandiswithintheEPA’srecommendedemissions.
CanIimplementcustommappinglogicbetween2datatypesandhaveDozerinvokethiscustomlogicwhenit’sperformingmappings?
Yes.AveryusefulfeatureprovidedbyDozeristheconceptofcustomconverters.Customconvertersareusedtoperformcustommappingbetweentwoobjects.IntheConfigurationblock,youcanaddsomeXMLtotellDozertouseacustomconverterforcertainclassAandclassBtypes.WhenacustomconverterisspecifiedforaclassAandclassBcombination,Dozerwillinvokethecustomconvertertoperformthedatamappinginsteadofthestandardmappinglogic.
<custom-converters><convertertype="com.github.dozermapper.core.converters.SomeCustomConverter"><class-a>com.github.dozermapper.core.vo.SomeCustomDoubleObject</class-a><class-b>java.lang.Double</class-b></converter></custom-converters>
CanImaponefieldintoanotherfieldthatisnestednlayersdeepinthedestinationobject?
Yes.Dozersupportsdotnotationfornestedfields.Aswithotherdozerfieldmappings,thesearebi-directional.
FAQ
76
<field><a>someNestedObj.someOtherNestedObj.someField</a><b>someOtherField</b></field>
HowdoImapmultiplefieldstoasinglefield?
Dozerdoesn’tcurrentlysupportthis.Andbecauseofthecomplexitiesaroundimplementingit,thisfeatureisnotcurrentlyontheroadmap.Apossiblesolutionwouldbetowrapthemultiplefieldsinacustomcomplextypeandthendefineacustomconverterformappingbetweenthecomplextypeandthesinglefield.Thisway,youcouldhandlethecustomlogicrequiredtomapthethreefieldsintothesingleonewithinthecustomconverter.
IfIammappingdataobjectsthatcontainbi-directionalrelationships,willitresultinaninfiniteloopandeventualstackoverflowerror?
No.Dozerhasbuiltinlogicthatpreventsinfiniteloopsforbi-directionaldataobjectrelationships
HowdoImapanobjectcontainedinacollectiontoafield?
Youwoulduseindexedbasedmapping.
<field><a>usernames[0]</a><b>username1</b></field>
HowdoImapaComplexobjecttoaHashMapandviceversa?
Youcanmapentirecomplexobjectsdirectlytoajava.util.Mapandviceversa.Whendoingthisyouneedtoexplicitlydefineauniquemap-idforthemapping.Thisisusedwhendeterminingwhichmaptouseatrun-time.Everyattributeonthecomplextypewillbemappedtothejava.util.Map.YouDONOTneedtoexplicitlydefinethesemappings.Iftheattributenameisnotthesameasthemapkeyjustsetthekeyattributeforacustomfieldmapping.
<mappingmap-id="myTestMapping"><class-a>com.github.dozermapper.core.vo.map.SomeComplexType</class-a><class-b>java.util.Map</class-b><field><a>stringProperty2</a><bkey="myStringProperty">this</b></field></mapping>
HowdoImapfieldsthatdon’thavecorrespondinggetter/settermethods?
YoucantellDozertodirectlyaccessfields(includingprivatefields)byspecifyingis-accessible="true"
<field><a>fieldA</a><bis-accessible="true">fieldB</b></field>
Someofmydataobjectsdon’thavepublicconstructors.DoesDozersupportthisusecase?
FAQ
77
Yes.Whencreatinganewinstanceofthedestinationobjectifapublicno-argconstructorisnotfound,Dozerwillautodetectaprivateconstructorandusethat.Ifthedataobjectdoesnothaveaprivateconstructor,youcanspecifyacustomBeanFactoryforcreatingnewinstancesofthedestinationobject.
DoesDozersupportJDK1.5enums?
Yes.EnumtoEnummappingisautomaticallyhandled.
DoesDozersupportJAXBgenerateddataobjects?
DozerhassupportformappingPOJOstoJAXBobjects.UsetheJAXBBeanFactoryforanyJAXBobjectsyouwantcreated.
IsthereanEclipsepluginorvisualeditorforDozer?
No,butwethinkitwouldbeagreataddition.Itwouldbeverypowerfultobeabletographicallymap2objectsandhavethecustomxmldefinitionsautogenerated,alongwithbeingabletovisuallyviewamappingdefinition.Ifanyonehasexpertiseincreatingeclipsepluginsandisinterestedonworkingonthisfeature,pleaseletusknow!
Whenmappingcollections,howdoItellDozerwhattypeofdataobjectsIwantinthedestinationcollection?
Hintsaresupportedtohandlethisusecase.HintsarenotrequiredifyouareusingJDK1.5GenericsbecausethetypescanbeautodetectedbyDozer.Butifyouarenotusinggenerics,toconvertaCollection/ArraytoaCollection/ArraywithdifferenttypeobjectsyoucanspecifyaHinttoletDozerknowwhattypeofobjectsyouwantcreatedinthedestinationlist.IfaHintisnotspecifiedforthedestinationfield,thenthedestinationCollectionwillbepopulatedwithobjectsthatarethesametypeastheelementsinthesrcCollection.
<field><a>someList</a><b>otherList</b><b-hint>com.github.dozermapper.core.vo.TheFirstSubClassPrime</b-hint></field>
HowcanItellDozertobypassmappingnulloremptystringvalues?
Youcanbypassthemappingofnullvaluesbyspecifyingmap-null="false".Ifthisisspecified,thedestfieldmappingisbypassedatruntimeandthedestinationvaluesettermethodwillnotbecalledifthesrcvalueisnull.Thiscanbespecifiedatthemappingorclasslevel.
YoucanbypassthemappingofemptyStringvaluesbyspecifyingmap-empty-string="false".Ifthisisspecified,thedestfieldmappingisbypassedatruntimeandthedestinationvaluesettermethodwillnotbecalledifthesrcvalueisanemptyString.Thiscanbespecifiedatthemappingorclasslevel
ShouldIencapsulatelogicthatcopiesdatabetweenobjects?
Itisouropinionthatyoushould.RegardlessofwhetheryouuseDozertoperformdatamappingbetweenobjects,webelievethisisagooddesignpatternthatpromotesreuse,encapsulatestheunderlyingimplementation,andmakesthecodeunittestableinisolation.These"Assembler"interfacesencapsulatethelogicthatisresponsiblefortakingasrcobjectandmappingthedataintoadestobject.Usingassemblertypeofclassesgivesyoutheflexibilityofbeingabletomodifytheunderlyingmappingimplementationwithoutimpactingclientsorthecontract.OneotherimportantbenefitofusingAssemblersisthatitmakeswritingunittestsspecificforthemappingaloteasierandmorefocused.Ifyoueverneedtodetermineifaparticularbugisduetomappingofobjects,itissimpletowriteanAssemblerunittest
FAQ
78
thatreproducestheusecase.Ifyouencapsulateyourdatamappinglogic,youcoulduseDozerformostofmappingsandifyouhavearealcornercase,youhavetheflexibilitytohandcodemappingsforanyobjectsorfields.Forexample,youcouldrunyourmappingthroughDozertomap99%ofyourfieldsandthenhaveamanualmappingforsomeoddballfield.ThiswouldhappenallwithintheAssemblerwithouttheclienthavinganyknowledgeoftheunderlyingimplementation.
Itseemstoworkbestiftheseassemblertypeofclassesare"dumb"andareonlyresponsibleforsimplycopyingdatafromthesourceobjectintothedestinationobject.Anycomplexpostprocessingbusinesslogicthatneedstobeperformedonthedestinationobjectcanbedoneatahigherlevelinclasssesthathavemoreresponsibility.
ThefollowingisasimpleexampleofanassemblertypeclassthatusesDozerforitsunderlyingimplementation.
publicclassSomeAssemblerImplimplementsSomeAssembler{
privateMapperdozerMapper;
publicDestObjectassembleDestObject(SrcObjectsrc){returndozerMapper.map(src,DestObject.class);}
}
ShouldIwriteunittestsfordatamappinglogicthatIuseDozertoperform?
Absolutely.Andofcourse,westronglyrecommendwritingtheunittest(s)first.Evenifyoudon’tuseDozertoperformthedatamappingbetweentwoobjects,thislogicstillneedsisolatedunittests.Datamappinglogic(especiallyhandcoded)iserrorproneandhavingaunittestisinvaluable.Typicallymappingbetweentwoobjectsisrequiredinmultipleareasofasystem,soafocusedunittestofthecentralmappinglogicenablesyoutotestthedatamappinglogicinisolation.Thegreatthingaboutencapsulatingdatamappinglogicandhavingunittestsforthelogicisthatyoucaneasilyswitchouttheunderlyingimplementation.
ForexistingsystemsthatarewantingtomigratetoDozer,werecommendfirstencapsulatinganyexistinghandcodeddatamappingintoanassemblertypeofclassandwriteunittestsforit.ThenswitchoutthehandcodedmappinglogicwithDozerandtheunittestswillbeyoursafetynet.ThemigrationtoDozercanbeincrementalandthisisprobablythebeststrategyforexisitingsystems.
RegardlessofwhetherornotyouuseDozer,unittestingdatamappinglogicistediousandanecessaryevil,butthereisatrickthatmayhelp.Ifyouhaveanassemblerthatsupportsmapping2objectsbi-directionally,inyourunittestyoucandosomethingsimilartothefollowingexample.Thisalsoassumesyouhavedoneagoodjobofimplementingtheequals()methodforyourdataobjects.Theideaisthatifyoumapasourceobjecttoadestinationobjectandthenbackagain,theoriginalsrcobjectshouldequaltheobjectreturnedfromthelastmappingiffieldsweremappedcorrectly.Inthetestcase,youshouldpopulateallthepossiblefieldsintheoriginalsourceobjecttoensurethatallofthefieldsareaccountedforinthemappinglogic.
publicvoidtestAssembleSomeObject()throwsException{SrcObjectsrc=newSrcObject();src.setSomeField("somevalue");src.setSomeOtherField("makesureyousetallthesrcfields"+"withvaluessothatyoufullytestthedatamappings");
DestObjectdest=assembler.assembleDestObject(src);SrcObjectmappedSrc=assermbler.assembleSrcObject(dest);
assertEquals("fieldsnotmappedcorrectly",src,mappedSrc);}
FAQ
79
Itisalsogoodpracticetoverifythatyourassemblerhandlesnullvaluesproperly.Inthefollowingtestcasenoneofthesourcefieldsarepopulated.Iftheassemblerdoesn’tproperlyhandlenullvalues,anexceptionwillbethrownwhentheassemblerisinvoked.
publicvoidtestAssembleSomeObject_NullValues()throwsException{SrcObjectsrc=newSrcObject();
DestObjectdest=assembler.assembleDestObject(src);SrcObjectmappedSrc=assermbler.assembleSrcObject(dest);
assertEquals("fieldsnotmappedcorrectly",src,mappedSrc);}
ShouldtheDozermapperbeconfiguredasaSingleton?
Yes.Mapperinstancesshouldbereusedasmuchaspossible.ForeveryinstanceoftheMapper,themappingfilesareloadedandparsed.YoushouldconfiguretheMapperonceforyourconfigurationandreusethisinstancethroughoutyourapplication.TheMapperimplementationsarethreadsafe.
Isitbettertohave1largexmlmappingfileortohavemultiplesmallermappingfiles?
Werecommendcomponentizingyourmappingfilesinsteadofhaving1largemappingfile.
WhatarethebestwaystodebugDozer?
Youcanspecifythe-Ddozer.debugsystempropertytoviewtheonetimeinitializationinformation.Youwillseeoutputsimilartothefollowing….
dozer:TryingtofindDozerconfigurationfile:dozer.propertiesdozer:UsingURL[file:/local/subversion_projects/dozer/trunk/target/test-classes/dozer.properties]forDozerglobalpropertyconfigurationdozer:ReadingDozerpropertiesfromURL[file:/local/subversion_projects/dozer/trunk/target/test-classes/dozer.properties]dozer:FinishedconfiguringDozerglobalpropertiesdozer:InitializingDozer.Version:${project.version},ThreadName:maindozer:Initializinganewinstanceofthedozerbeanmapper.dozer:Usingthefollowingxmlfilestoloadcustommappingsforthebeanmapperinstance:[fieldAttributeMapping.xml]dozer:Tryingtofindxmlmappingfile:fieldAttributeMapping.xmldozer:UsingURL[file:/local/subversion_projects/dozer/trunk/target/test-classes/fieldAttributeMapping.xml]toloadcustomxmlmappingsdozer:SuccessfullyloadedcustomxmlmappingsfromURL:[file:/local/subversion_projects/dozer/trunk/target/test-classes/fieldAttributeMapping.xml]
Todebugindividualfieldmappingsbetweenclasses,setthelogginglevel"com.github.dozermapper.core.MappingProcessor=DEBUG".Forexample,ifyouareusinglog4jyouwouldaddthefollowingentrytoyourlog4jconfigurationfile"log4j.category.com.github.dozermapper.core.MappingProcessor=DEBUG".ThiswillshowyoueveryfieldmappingthatDozerperformsalongwiththeactualsourceanddestinationvalues.Youwillseeoutputsimilartothefollowing….
MAPPED:SimpleObj.field1-->SimpleObjPrime.field1VALUES:one-->oneMAPID:someMapIdMAPPED:SimpleObj.field2-->SimpleObjPrime.field2VALUES:2-->2MAPID:someMapIdMAPPED:SimpleObj.field3-->SimpleObjPrime.field3VALUES:3-->3MAPID:someMapIdMAPPED:SimpleObj.field4-->SimpleObjPrime.field4VALUES:44.44-->44.44MAPID:someMapIdMAPPED:SimpleObj.field6-->SimpleObjPrime.field6VALUES:
FAQ
80
66-->66MAPID:someMapId
Whatisthebestwaytosetuptheglobalconfiguration?
Werecommendhavingaseparatemappingxmlfileforglobalconfiguration.Youcouldnameitsomethingsimilartodozer-global-configuration.xml.Sampleglobalconfigurationfile……
<?xmlversion="1.0"encoding="UTF-8"?><mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttp://dozermapper.github.io/schema/bean-mapping.xsd"><configuration><stop-on-errors>true</stop-on-errors><date-format>MM/dd/yyyyHH:mm</date-format><wildcard>false</wildcard><custom-converters><convertertype="com.github.dozermapper.core.converters.TestCustomConverter"><class-a>com.github.dozermapper.core.vo.CustomDoubleObject</class-a><class-b>java.lang.Double</class-b></converter></custom-converters></configuration></mappings>
Whatisthebestwaytosubmitabug,featurerequest,orpatch?
Wevalueyoursuggestionsandappreciateeveryonethattakesthetimetosubmitasupportrequest.PleasesubmitallrequestsviaDozer’sGitHubprojectpage
FAQ
81
ExamplesTherearesomesamplemappingfilesunder\{dozer.home}/src/test/resources.ThesemappingfilesareusedbytheDozerunittests.
Examples
82
Migrationfromv5.5.1tov6.0.0Seeforreleasenotes.
1.JDK<1.8supportdropped
DozerisbuiltagainstJavaJDK1.8ONLY.
2.MavenGAV(GroupID,ArtifactandVersion)haschanged:
From:
<dependency><groupId>net.sf.dozer</groupId><artifactId>dozer</artifactId><version>5.5.1</version></dependency>
To:
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>6.0.0</version></dependency>
3.dozer-osgidropped
Younolongerneedtousethebelow,ifyouarerunninginanOSGienvironment:
<dependency><groupId>net.sf.dozer</groupId><artifactId>dozer-osgi</artifactId><version>5.5.1</version></dependency>
Justsimplyusethedozer-core:
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>6.0.0</version></dependency>
v5tov6
83
Migrationfromv6.0.0tov6.1.0Seeforreleasenotes.
1.Mapping.xmlXSDchanged:
From:
<mappingsxmlns="http://dozer.sourceforge.net"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozer.sourceforge.nethttp://dozer.sourceforge.net/schema/beanmapping.xsd">
To:
<mappingsxmlns="http://dozermapper.github.io/schema/bean-mapping"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mappinghttps://dozermapper.github.io/schema/bean-mapping.xsd">
2.Dozer-SpringXSDchanged.
From:
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dozer="http://dozer.sourceforge.net/schema/dozer-spring"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://dozer.sourceforge.net/schema/dozer-springhttp://dozer.sourceforge.net/schema/dozer-spring.xsd">
To:
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dozer="http://dozermapper.github.io/schema/dozer-spring"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://dozermapper.github.io/schema/dozer-springhttps://dozermapper.github.io/schema/dozer-spring.xsd">
3.DozerBeanMapperusageisdeprecated
DirectinstantiationofDozerBeanMapperaswellasitsusageisdeprecated.Thisclasswillbehiddeninversion6.2.PleaseuseMapperwheneveryouneedtomap,andDozerBeanMapperBuildertoconfigurethemapper.
Deprecated:
DozerBeanMappermapper=newDozerBeanMapper();mapper.addMapping(myMappingBuilder);mapper.setMappingFiles(myFiles);
mapper.map(a,b);
Recommended:
v6.0.0tov6.1.0
84
Mappermapper=DozerBeanMapperBuilder.create().withMappingBuilder(myMappingBuilder).withMappingFiles(myFiles).build();
mapper.map(a,b);
4.DozerBeanMapperSingletonWrapperisdeprecated
DozerBeanMapperSingletonWrapperisdeprecatedandplannedforremovalinversion6.2.
DozerprojectdoesnotadvisetouseJVMsingletons.PleaseuseyourDIcontainertomanagesingleinstanceoftheMapperifrequired.ThefollowingcodecanbeusedtocreateaMapperwithdefaultconfiguration:
Mappermapper=DozerBeanMapperBuilder.buildDefault();
5.InternalAPIischanged
DozerismovingawayfromhavingJVM-globalstate.ThismeansthatsomeinternalAPIlikeBeanContainerisnotavailableanymoreviasingletonreferences,i.e.BeanContainer.getInstance()doesnotexist.Ifyouwereusingthisoranyothercodethatisreworked,pleaseletusknow.MostlikelyyoudevelopedDozerModule.Wewouldliketoknowmoreaboutreal-worldusecasestobuildconvenientpublicAPIformodulesdevelopers.
6.org.dozer.BeanFactoryinterfacechanges
Oldsignatureoforg.dozer.BeanFactoryisdeprecatedandwillberemovedinversion6.2.Pleaseusenewmethodofthisinterfacewhencreatingcustombeanfactories.
Deprecated:
ObjectcreateBean(Objectsource,Class<?>sourceClass,StringtargetBeanId)
Recommended:
ObjectcreateBean(Objectsource,Class<?>sourceClass,StringtargetBeanId,BeanContainerbeanContainer)
7.Deprecatedstatsandjmx
Deprecated:
org.dozer.statsorg.dozer.jmx
8.Updateddozer-protopackagename
From:
org.dozer
To:
com.github.dozermapper.protobuf
v6.0.0tov6.1.0
85
9.Updateddozer-springpackagename
From:
org.dozer.spring
To:
com.github.dozermapper.spring
v6.0.0tov6.1.0
86
Migrationfromv6.1.0tov6.2.0Seeforreleasenotes.
1.JMX/Statshasbeenremoved
Asper6.1.0migrationdocs,JMXandStatsweredeprecated.Theyhavenowbeenfullyremoved.
2.dozer.propertieskeyschanged
From:
dozer.cache.converter.by.dest.type.maxsizedozer.cache.super.type.maxsizeorg.dozer.util.DozerClassLoaderorg.dozer.util.DozerProxyResolver
To:
dozer.cache.converter-by-dest-type-maxsizedozer.cache.super-type-maxsizedozer.beans.class-loader-beandozer.beans.proxy-resolver-bean
3.SupportforYAML,SystemPropertiesandEnvironmentvariables
Asaswellasdozer.properties,wealsosupportseveralnewimplementations,suchasYAML,see:-https://github.com/DozerMapper/dozer/tree/6.2.0/core/src/main/java/org/dozer/config/resolvers-https://github.com/DozerMapper/dozer/tree/6.2.0/core/src/main/java/org/dozer/config/processors
4.dozer.el.enabledisdeprecated
Thepropertyfor'dozer.el.enabled'hasbeendeprecated.Instead,youshoulduse:
DefaultELEngineelEngine=newDefaultELEngine();Mappermapper=DozerBeanMapperBuilder.create().withMappingFiles(mappingFiles).withElementReader(newExpressionElementReader(elEngine)).withELEngine(elEngine).build();
5.Springmavenartifactnamehaschanged
From:
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-spring</artifactId><version>6.1.0</version></dependency>
To:
v6.1.0tov6.2.0
87
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-spring4</artifactId><version>6.2.0</version></dependency>
6.Springmavenartifactnamehaschanged
From:
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-proto</artifactId><version>6.1.0</version></dependency>
To:
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-proto3</artifactId><version>6.2.0</version></dependency>
7.Extendedspringbootsupport
dozer-spring-boot-starteranddozer-spring-boot-autoconfigureartifactsaddedtosupportspringbootautoconfigurationfeatures.
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-spring-boot-starter</artifactId><version>6.2.0</version></dependency>
8.dozer.xml.use-jaxb-mapping-enginetousenewJAXB
ThecurrentDozerXMLtoObjectsimplementationusesorg.w3c.dom.Documenttoparsethemodel.Goingforward,theintentionistouseaJAXBmodel.Thisfeatureisnotenabledbydefault,butcanbevia:
dozer.xml.use-jaxb-mapping-engine=true
v6.1.0tov6.2.0
88
Migrationfromv6.2.0tov6.3.0Seeforreleasenotes.
1.Karaf2supportdropped
Askaraf2isnowdeprecatedupstream,andisnotsupportedwithJava9,supportisdropped.
2.ApacheXMLBeanssupportdropped
Asxmlbeansisnowdeprecatedupstream,andisnotsupportedwithJava9,supportisdropped.
3.UberJARnowprovided
MavenGAV
<dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>6.3.0</version><classifier>jar-with-dependencies</classifier></dependency>
4.dozer.xml.use-jaxb-mapping-engineenabledbydefault
JAXBisusedbydefault,ifthiscausesissues,itcanbedisabledvia:
-Ddozer.xml.use-jaxb-mapping-engine=false
Andthefollowingisdeprecated:
com.github.dozermapper.core.loader.xml
Infavourof:
com.github.dozermapper.core.builder.xml
5.Updateddozer-corepackagename
From:
org.dozer
To:
com.github.dozermapper.core
6.UpdatedDozerEventListenerpackage/classname
From:
v6.2.0tov6.3.0
89
org.dozer.DozerEventListener
To:
com.github.dozermapper.core.events.EventListener
v6.2.0tov6.3.0
90
PrerequisitesThePlugincurrentlydependson
WTP3.0.2orlatest
Compatibility
PluginissupportedandbeentestedonthefollowingIDEs
Eclipse3.6
RADRSA8.0.1
Installation
TheDozerPlugin-featurecanbeinstalledandupdatedusingtheEclipseUpdateManager.
AddanewUpdate-URL:
http://dozer.sourceforge.net/eclipse-plugin
Selectallrequireddependenciesandinstalltheplugin.
Alternativelyyoucandownloadthepackageatsourceforgeandunzipitinyoureclipseinstallationfolder.YoumighthavetoenablethePluginafterstartingEclipse.ThiscanbedoneatHelp>SoftwareUpdates>ManageConfiguration.
Afterinstallationisdoneyoushouldseealittlereddozer-icononallyourmapping-xmlfiles.
Installation
91
CreatenewMappingfilesThepluginprovidesasimplewizardforcreatingnewmapping-xmlfiles.Anewmapping-xmlfilecanbecreatedusingFile>New>Other>DozerMappingFramework>DozerMappingFile.Selectthecorrectdozerversion(4,DTDor5,XSD)inthewizardandcreatethefile.
ConfiguretheMapping
viaXML
viatheEditor
Usage
92
OpenmappingfileWhenopeningaDozer-mapping-filetheDozer-editorappears.IfyouwanttoedittherawXMLyoucanswitchtothe"source"view.
ContentAssist
Alltheclass-a/class-b,field,get-method,set-method,etc-nodesor-attributesautomaticlyshowcontent-assistpopupswhenpressingctrl+spaceortheconfiguredWTP-XMLcontentassistcharacters.Thesecanbechangedinthepreferences.
viaXML
93
Alltheclass-a/class-b,field,get-method,set-method,etc-nodesor-attributesautomaticlyshowcontent-assistpopupswhenpressingctrl+spaceortheconfiguredWTP-XMLcontentassistcharacters.Thesecanbechangedinthepreferences.
viaXML
94
Validation
TheDozerPluginvalidatestheMappingtofindoutifthemappedclassdoexistandifthemappedfieldsareaccessible.
viaXML
95
SettingglobaldozerconfigurationAllglobalconfigurationvaluescanbesetinthe"GlobalConfiguration"Tab.
Configuringmappings
Everyclassmappingislistedinthe"Mapping"Tab.MappingsofclassesandfieldscanbeaddedbyPopupmenuortheaction-buttonsatthetop.Ontherightsidethemappingscanbeconfigured.EveryAttributeorElementintheXMLfileisshownforediting.
viaEditor
96