1 /*
2  * Copyright 2011 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.modelmapper;
17
18 import net.jodah.typetools.TypeResolver;
19
20 import java.lang.reflect.Type;
21 import java.util.Collection;
22
23 import org.modelmapper.config.Configuration;
24 import org.modelmapper.internal.Errors;
25 import org.modelmapper.internal.InheritingConfiguration;
26 import org.modelmapper.internal.MappingEngineImpl;
27 import org.modelmapper.internal.util.Assert;
28 import org.modelmapper.internal.util.Types;
29
30 /**
31  * ModelMapper - Performs object mapping, maintains {@link Configuration} and stores {@link TypeMap
32  * TypeMaps}.
33  * 
34  * <ul>
35  * <li>To perform object mapping use {@link #map(Object, Class) map}.</li>
36  * <li>To configure the mapping of one type to another use {@link #createTypeMap(Class, Class)
37  * createTypeMap}.</li>
38  * <li>To add mappings for specific properties use {@link #addMappings(PropertyMap) addMappings}
39  * supplying a {@link PropertyMap}.</li>
40  * <li>To configure ModelMapper use {@link #getConfiguration}.
41  * <li>To validate mappings use {@link #validate}.
42  * </ul>
43  * 
44  * @author Jonathan Halterman
45  */

46 public class ModelMapper {
47   private final InheritingConfiguration config;
48   private final MappingEngineImpl engine;
49
50   /**
51    * Creates a new ModelMapper.
52    */

53   public ModelMapper() {
54     config = new InheritingConfiguration();
55     engine = new MappingEngineImpl(config);
56   }
57
58   /**
59    * Registers the {@code converter} to use when mapping instances of types {@code S} to {@code D}.
60    * The {@code converter} will be {@link TypeMap#setConverter(Converter) set} against TypeMap
61    * corresponding to the {@code converter}'s type arguments {@code S} and {@code D}.
62    * 
63    * @param <S> source type
64    * @param <D> destination type
65    * @param converter to register
66    * @throws IllegalArgumentException if {@code converter} is null or if type arguments {@code S}
67    *           and {@code D} are not declared for the {@code converter}
68    * @see TypeMap#setConverter(Converter)
69    */

70   @SuppressWarnings("unchecked")
71   public <S, D> void addConverter(Converter<S, D> converter) {
72     Assert.notNull(converter, "converter");
73     Class<?>[] typeArguments = TypeResolver.resolveRawArguments(Converter.class, converter.getClass());
74     Assert.notNull(typeArguments, "Must declare source type argument <S> and destination type argument <D> for converter");
75     config.typeMapStore.<S, D>getOrCreate(null, (Class<S>) typeArguments[0],
76         (Class<D>) typeArguments[1], nullnull, converter, engine);
77   }
78
79   /**
80    * Registers the {@code converter} to use when mapping instances of types {@code S} to {@code D}.
81    * The {@code converter} will be {@link TypeMap#setConverter(Converter) set} against TypeMap
82    * corresponding to the {@code converter}'s type arguments {@code S} and {@code D}.
83    *
84    * @param <S> source type
85    * @param <D> destination type
86    * @param converter to register
87    * @throws IllegalArgumentException if {@code converter} is null or if type arguments {@code S}
88    *           and {@code D} are not declared for the {@code converter}
89    * @see TypeMap#setConverter(Converter)
90    */

91   @SuppressWarnings("unchecked")
92   public <S, D> void addConverter(Converter<S, D> converter, Class<S> sourceType, Class<D> destinationType) {
93     Assert.notNull(converter, "converter");
94     config.typeMapStore.<S, D>getOrCreate(null, sourceType,
95             destinationType, nullnull, converter, engine);
96   }
97
98   /**
99    * Adds mappings from the {@code propertyMap} into the TypeMap corresponding to source type
100    * {@code S} and destination type {@code D}. Explicit mappings defined in the {@code propertyMap}
101    * will override any implicit mappings for the same properties.
102    * 
103    * @param <S> source type
104    * @param <D> destination type
105    * @param propertyMap from which mappings should be loaded
106    * @return TypeMap corresponding to the {@code propertyMap}
107    * @throws IllegalArgumentException if {@code propertyMap} is null
108    * @throws ConfigurationException if a configuration error occurs while adding mappings for the
109    *           {@code propertyMap}
110    */

111   public <S, D> TypeMap<S, D> addMappings(PropertyMap<S, D> propertyMap) {
112     Assert.notNull(propertyMap, "propertyMap");
113     return config.typeMapStore.getOrCreate(null, propertyMap.sourceType,
114         propertyMap.destinationType, null, propertyMap, null, engine);
115   }
116
117   /**
118    * Creates a TypeMap for the {@code sourceType} and {@code destinationType} using the
119    * ModelMapper's configuration.
120    * 
121    * @param <S> source type
122    * @param <D> destination type
123    * @param sourceType
124    * @param destinationType
125    * @throws IllegalArgumentException if {@code sourceType} or {@code destinationType} are null
126    * @throws IllegalStateException if a TypeMap already exists for {@code sourceType} and
127    *           {@code destinationType}
128    * @throws ConfigurationException if the ModelMapper cannot create the TypeMap
129    * @see #getTypeMap(Class, Class)
130    */

131   public <S, D> TypeMap<S, D> createTypeMap(Class<S> sourceType, Class<D> destinationType) {
132     return this.<S, D>createTypeMap(sourceType, destinationType, config);
133   }
134
135   /**
136    * Creates a TypeMap for the {@code sourceType} and {@code destinationType} using the
137    * {@code configuration}.
138    * 
139    * @param <S> source type
140    * @param <D> destination type
141    * @param sourceType
142    * @param destinationType
143    * @param configuration to apply to TypeMap
144    * @throws IllegalArgumentException if {@code sourceType}, {@code destinationType} or
145    *           {@code configuration} are null
146    * @throws IllegalStateException if a TypeMap already exists for {@code sourceType} and
147    *           {@code destinationType}
148    * @throws ConfigurationException if the ModelMapper cannot create the TypeMap
149    * @see #getTypeMap(Class, Class)
150    */

151   public <S, D> TypeMap<S, D> createTypeMap(Class<S> sourceType, Class<D> destinationType,
152       Configuration configuration) {
153     Assert.notNull(sourceType, "sourceType");
154     Assert.notNull(destinationType, "destinationType");
155     Assert.notNull(configuration, "configuration");
156     return this.<S, D>createTypeMapInternal(null, sourceType, destinationType, null, configuration);
157   }
158
159   /**
160    * Creates a TypeMap for the {@code sourceType} and {@code destinationType} identified by the
161    * {@code typeMapName} using the ModelMapper's configuration.
162    * 
163    * @param <S> source type
164    * @param <D> destination type
165    * @param sourceType
166    * @param destinationType
167    * @param typeMapName
168    * @throws IllegalArgumentException if {@code sourceType}, {@code destinationType} or
169    *           {@code typeMapName} are null
170    * @throws IllegalStateException if a TypeMap already exists for {@code sourceType},
171    *           {@code destinationType} and {@code typeMapName}
172    * @throws ConfigurationException if the ModelMapper cannot create the TypeMap
173    * @see #getTypeMap(Class, Class, String)
174    */

175   public <S, D> TypeMap<S, D> createTypeMap(Class<S> sourceType, Class<D> destinationType,
176       String typeMapName) {
177     return this.<S, D>createTypeMap(sourceType, destinationType, typeMapName, config);
178   }
179
180   /**
181    * Creates a TypeMap for the {@code sourceType} and {@code destinationType} identified by the
182    * {@code typeMapName} using the {@code configuration}.
183    * 
184    * @param <S> source type
185    * @param <D> destination type
186    * @param sourceType
187    * @param destinationType
188    * @param typeMapName
189    * @param configuration to apply to TypeMap
190    * @throws IllegalArgumentException if {@code sourceType}, {@code destinationType},
191    *           {@code typeMapName} or {@code configuration} are null
192    * @throws IllegalStateException if a TypeMap already exists for {@code sourceType},
193    *           {@code destinationType} and {@code typeMapName}
194    * @throws ConfigurationException if the ModelMapper cannot create the TypeMap
195    * @see #getTypeMap(Class, Class, String)
196    */

197   public <S, D> TypeMap<S, D> createTypeMap(Class<S> sourceType, Class<D> destinationType,
198       String typeMapName, Configuration configuration) {
199     Assert.notNull(sourceType, "sourceType");
200     Assert.notNull(destinationType, "destinationType");
201     Assert.notNull(typeMapName, "typeMapName");
202     Assert.notNull(configuration, "configuration");
203     return createTypeMapInternal(null, sourceType, destinationType, typeMapName, configuration);
204   }
205
206   /**
207    * Creates a TypeMap for the {@code source}'s type and {@code destinationType} using the
208    * ModelMapper's configuration. Useful for creating TypeMaps for generic source data structures.
209    * 
210    * @param <S> source type
211    * @param <D> destination type
212    * @param source
213    * @param destinationType
214    * @throws IllegalArgumentException if {@code source} or {@code destinationType} are null
215    * @throws IllegalStateException if a TypeMap already exists for {@code source}'s type and
216    *           {@code destinationType}
217    * @throws ConfigurationException if the ModelMapper cannot create the TypeMap
218    * @see #getTypeMap(Class, Class)
219    */

220   public <S, D> TypeMap<S, D> createTypeMap(S source, Class<D> destinationType) {
221     return this.<S, D>createTypeMap(source, destinationType, config);
222   }
223
224   /**
225    * Creates a TypeMap for the {@code source}'s type and {@code destinationType} using the
226    * {@code configuration}. Useful for creating TypeMaps for generic source data structures.
227    * 
228    * @param <S> source type
229    * @param <D> destination type
230    * @param source
231    * @param destinationType
232    * @param configuration to apply to TypeMap
233    * @throws IllegalArgumentException if {@code source}, {@code destinationType} or
234    *           {@code configuration} are null
235    * @throws IllegalStateException if a TypeMap already exists for {@code source}'s type and
236    *           {@code destinationType}
237    * @throws ConfigurationException if the ModelMapper cannot create the TypeMap
238    * @see #getTypeMap(Class, Class)
239    */

240   public <S, D> TypeMap<S, D> createTypeMap(S source, Class<D> destinationType,
241       Configuration configuration) {
242     Assert.notNull(source, "source");
243     Assert.notNull(destinationType, "destinationType");
244     Assert.notNull(configuration, "configuration");
245     return this.<S, D>createTypeMapInternal(source, null, destinationType, null, configuration);
246   }
247
248   /**
249    * Creates a TypeMap for the {@code source}'s type and {@code destinationType} identified by the
250    * {@code typeMapName} using the ModelMapper's configuration. Useful for creating TypeMaps for
251    * generic source data structures.
252    * 
253    * @param <S> source type
254    * @param <D> destination type
255    * @param source
256    * @param destinationType
257    * @param typeMapName
258    * @throws IllegalArgumentException if {@code source}, {@code destinationType} or
259    *           {@code typeMapName} are null
260    * @throws IllegalStateException if a TypeMap already exists for {@code source}'s type,
261    *           {@code destinationType} and {@code typeMapName}
262    * @throws ConfigurationException if the ModelMapper cannot create the TypeMap
263    * @see #getTypeMap(Class, Class, String)
264    */

265   public <S, D> TypeMap<S, D> createTypeMap(S source, Class<D> destinationType, String typeMapName) {
266     return this.<S, D>createTypeMap(source, destinationType, typeMapName, config);
267   }
268
269   /**
270    * Creates a TypeMap for the {@code source}'s type and {@code destinationType} identified by the
271    * {@code typeMapName} using the {@code configuration}. Useful for creating TypeMaps for generic
272    * source data structures.
273    * 
274    * @param <S> source type
275    * @param <D> destination type
276    * @param source
277    * @param destinationType
278    * @param typeMapName
279    * @param configuration to apply to TypeMap
280    * @throws IllegalArgumentException if {@code source}, {@code destinationType},
281    *           {@code typeMapName} or {@code configuration} are null
282    * @throws IllegalStateException if a TypeMap already exists for {@code source}'s type,
283    *           {@code destinationType} and {@code typeMapName}
284    * @throws ConfigurationException if the ModelMapper cannot create the TypeMap
285    * @see #getTypeMap(Class, Class, String)
286    */

287   public <S, D> TypeMap<S, D> createTypeMap(S source, Class<D> destinationType, String typeMapName,
288       Configuration configuration) {
289     Assert.notNull(source, "source");
290     Assert.notNull(destinationType, "destinationType");
291     Assert.notNull(typeMapName, "typeMapName");
292     Assert.notNull(configuration, "configuration");
293     return createTypeMapInternal(source, null, destinationType, typeMapName, configuration);
294   }
295
296   /**
297    * Returns the ModelMapper's configuration.
298    */

299   public Configuration getConfiguration() {
300     return config;
301   }
302
303   /**
304    * Returns the TypeMap for the {@code sourceType} and {@code destinationType}, else returns
305    * {@code nullif none exists.
306    * 
307    * @param <S> source type
308    * @param <D> destination type
309    * @throws IllegalArgumentException is {@code sourceType} or {@code destinationType} are null
310    * @see #createTypeMap(Class, Class)
311    */

312   public <S, D> TypeMap<S, D> getTypeMap(Class<S> sourceType, Class<D> destinationType) {
313     Assert.notNull(sourceType, "sourceType");
314     Assert.notNull(destinationType, "destinationType");
315     return config.typeMapStore.<S, D>get(sourceType, destinationType, null);
316   }
317
318   /**
319    * Returns the TypeMap for the {@code sourceType}, {@code destinationType} and {@code typeMapName}
320    * , else returns {@code nullif none exists.
321    * 
322    * @param <S> source type
323    * @param <D> destination type
324    * @throws IllegalArgumentException is {@code sourceType}, {@code destinationType} or
325    *           {@code typeMapName} are null
326    * @see #createTypeMap(Class, Class, String)
327    */

328   public <S, D> TypeMap<S, D> getTypeMap(Class<S> sourceType, Class<D> destinationType,
329       String typeMapName) {
330     Assert.notNull(sourceType, "sourceType");
331     Assert.notNull(destinationType, "destinationType");
332     Assert.notNull(typeMapName, "typeMapName");
333     return config.typeMapStore.<S, D>get(sourceType, destinationType, typeMapName);
334   }
335
336   /**
337    * Returns the TypeMap for the {@code sourceType}, {@code destinationType}, creates TypeMap
338    * automatically if none exists.
339    *
340    * @param <S> source type
341    * @param <D> destination type
342    * @throws IllegalArgumentException is {@code sourceType}, {@code destinationType} are null
343    */

344   public <S, D> TypeMap<S, D> typeMap(Class<S> sourceType, Class<D> destinationType) {
345     Assert.notNull(sourceType, "sourceType");
346     Assert.notNull(destinationType, "destinationType");
347     return config.typeMapStore.getOrCreate(null, sourceType, destinationType, null, engine);
348   }
349
350   /**
351    * Returns the TypeMap for the {@code sourceType}, {@code destinationType}, and {@code typeMapName}
352    * creates TypeMap automatically if none exists.
353    *
354    * @param <S> source type
355    * @param <D> destination type
356    * @throws IllegalArgumentException is {@code sourceType}, {@code destinationType} or
357    *           {@code typeMapName} are null
358    */

359   public <S, D> TypeMap<S, D> typeMap(Class<S> sourceType, Class<D> destinationType,
360       String typeMapName) {
361     Assert.notNull(sourceType, "sourceType");
362     Assert.notNull(destinationType, "destinationType");
363     Assert.notNull(typeMapName, "typeMapName");
364     return config.typeMapStore.getOrCreate(null, sourceType, destinationType, typeMapName, engine);
365   }
366
367   /**
368    * Creates an empty TypeMap for the {@code sourceType}, {@code destinationType}.
369    *
370    * @param <S> source type
371    * @param <D> destination type
372    * @throws IllegalArgumentException is {@code sourceType} or {@code destinationType} are null, or {@code TypeMap<SourceType, DestinationType}
373    *  already defined in the TypeMapStore
374    */

375   public <S, D> TypeMap<S, D> emptyTypeMap(Class<S> sourceType, Class<D> destinationType) {
376     Assert.notNull(sourceType, "sourceType");
377     Assert.notNull(destinationType, "destinationType");
378     Assert.isNull(config.typeMapStore.get(sourceType, destinationType, null), "TypeMap already defined");
379     return config.typeMapStore.createEmptyTypeMap(sourceType, destinationType, null, config, engine);
380   }
381
382   /**
383    * Creates an empty TypeMap for the {@code sourceType}, {@code destinationType}.
384    *
385    * @param <S> source type
386    * @param <D> destination type
387    * @throws IllegalArgumentException is {@code sourceType} or {@code destinationType} are null, or {@code TypeMap<Source Type, DestinationType}
388    *  already defined in the TypeMapStore
389    */

390   public <S, D> TypeMap<S, D> emptyTypeMap(Class<S> sourceType, Class<D> destinationType, String typeMapName) {
391     Assert.notNull(sourceType, "sourceType");
392     Assert.notNull(destinationType, "destinationType");
393     Assert.notNull(typeMapName, "typeMapName");
394     Assert.isNull(config.typeMapStore.get(sourceType, destinationType, typeMapName), "TypeMap already defined");
395     return config.typeMapStore.createEmptyTypeMap(sourceType, destinationType, typeMapName, config, engine);
396   }
397
398   /**
399    * Returns all TypeMaps for the ModelMapper.
400    */

401   public Collection<TypeMap<?, ?>> getTypeMaps() {
402     return config.typeMapStore.get();
403   }
404
405   /**
406    * Maps {@code source} to an instance of {@code destinationType}. Mapping is performed according
407    * to the corresponding TypeMap. If no TypeMap exists for {@code source.getClass()} and
408    * {@code destinationType} then one is created.
409    * 
410    * @param <D> destination type
411    * @param source object to map from
412    * @param destinationType type to map to
413    * @return fully mapped instance of {@code destinationType}
414    * @throws IllegalArgumentException if {@code source} or {@code destinationType} are null
415    * @throws ConfigurationException if the ModelMapper cannot find or create a TypeMap for the
416    *           arguments
417    * @throws MappingException if a runtime error occurs while mapping
418    */

419   public <D> D map(Object source, Class<D> destinationType) {
420     Assert.notNull(source, "source");
421     Assert.notNull(destinationType, "destinationType");
422     return mapInternal(source, null, destinationType, null);
423   }
424
425   /**
426    * Maps {@code source} to an instance of {@code destinationType}. Mapping is performed according
427    * to the corresponding TypeMap for the {@code typeMapName}. If no TypeMap exists for the
428    * {@code source.getClass()}, {@code destinationType} and {@code typeMapName} then one is created.
429    * 
430    * @param <D> destination type
431    * @param source object to map from
432    * @param destinationType type to map to
433    * @param typeMapName name of existing TypeMap to use mappings from
434    * @return fully mapped instance of {@code destinationType}
435    * @throws IllegalArgumentException if {@code source}, {@code destinationType} or
436    *           {@code typeMapName} are null
437    * @throws ConfigurationException if the ModelMapper cannot find or create a TypeMap for the
438    *           arguments
439    * @throws MappingException if a runtime error occurs while mapping
440    */

441   public <D> D map(Object source, Class<D> destinationType, String typeMapName) {
442     Assert.notNull(source, "source");
443     Assert.notNull(destinationType, "destinationType");
444     Assert.notNull(typeMapName, "typeMapName");
445     return mapInternal(source, null, destinationType, typeMapName);
446   }
447
448   /**
449    * Maps {@code source} to {@code destination}. Mapping is performed according to the corresponding
450    * TypeMap. If no TypeMap exists for {@code source.getClass()} and {@code destination.getClass()}
451    * then one is created.
452    * 
453    * @param source object to map from
454    * @param destination object to map to
455    * @throws IllegalArgumentException if {@code source} or {@code destination} are null
456    * @throws ConfigurationException if the ModelMapper cannot find or create a TypeMap for the
457    *           arguments
458    * @throws MappingException if an error occurs while mapping
459    */

460   public void map(Object source, Object destination) {
461     Assert.notNull(source, "source");
462     Assert.notNull(destination, "destination");
463     mapInternal(source, destination, nullnull);
464   }
465
466   /**
467    * Maps {@code source} to {@code destination}. Mapping is performed according to the corresponding
468    * TypeMap for the {@code typeMapName}. If no TypeMap exists for the {@code source.getClass()},
469    * {@code destination.getClass()} and {@code typeMapName} then one is created.
470    * 
471    * @param source object to map from
472    * @param destination object to map to
473    * @param typeMapName name of existing TypeMap to use mappings from
474    * @throws IllegalArgumentException if {@code source}, {@code destination} or {@code typeMapName}
475    *           are null
476    * @throws ConfigurationException if the ModelMapper cannot find or create a TypeMap for the
477    *           arguments
478    * @throws MappingException if an error occurs while mapping
479    */

480   public void map(Object source, Object destination, String typeMapName) {
481     Assert.notNull(source, "source");
482     Assert.notNull(destination, "destination");
483     Assert.notNull(typeMapName, "typeMapName");
484     mapInternal(source, destination, null, typeMapName);
485   }
486
487   /**
488    * Maps {@code source} to an instance of {@code destinationType}. Mapping is performed according
489    * to the corresponding TypeMap. If no TypeMap exists for {@code source.getClass()} and
490    * {@code destinationType} then one is created.
491    * 
492    * <p>
493    * To map a parameterized destination type, subclass {@link TypeToken} and obtain its Type:
494    * 
495    * <pre>
496    * Type listType = new TypeToken&lt;List&lt;String&gt;&gt;() {}.getType();
497    * List&lt;String&gt; strings = modelMapper.map(source, listType);
498    * </pre>
499    * 
500    * @param <D> destination type
501    * @param source object to map from
502    * @param destinationType type to map to
503    * @return fully mapped instance of {@code destinationType}
504    * @throws IllegalArgumentException if {@code source} or {@code destinationType} are null
505    * @throws ConfigurationException if the ModelMapper cannot find or create the TypeMap
506    * @throws MappingException if a runtime error occurs while mapping
507    */

508   public <D> D map(Object source, Type destinationType) {
509     Assert.notNull(source, "source");
510     Assert.notNull(destinationType, "destinationType");
511     return mapInternal(source, null, destinationType, null);
512   }
513
514   /**
515    * Maps {@code source} to an instance of {@code destinationType}. Mapping is performed according
516    * to the corresponding TypeMap for the {@code typeMapName}. If no TypeMap exists for the
517    * {@code source.getClass()}, {@code destination.getClass()} and {@code typeMapName} then one is
518    * created.
519    * 
520    * <p>
521    * To map a parameterized destination type, subclass {@link TypeToken} and obtain its Type:
522    * 
523    * <pre>
524    * Type listType = new TypeToken&lt;List&lt;String&gt;&gt;() {}.getType();
525    * List&lt;String&gt; strings = modelMapper.map(source, listType, "string-list");
526    * </pre>
527    * 
528    * @param <D> destination type
529    * @param source object to map from
530    * @param destinationType type to map to
531    * @param typeMapName name of existing TypeMap to use mappings from
532    * @return fully mapped instance of {@code destinationType}
533    * @throws IllegalArgumentException if {@code source}, {@code destinationType} or
534    *           {@code typeMapName} are null
535    * @throws ConfigurationException if the ModelMapper cannot find or create the TypeMap
536    * @throws MappingException if a runtime error occurs while mapping
537    */

538   public <D> D map(Object source, Type destinationType, String typeMapName) {
539     Assert.notNull(source, "source");
540     Assert.notNull(destinationType, "destinationType");
541     Assert.notNull(typeMapName, "typeMapName");
542     return mapInternal(source, null, destinationType, typeMapName);
543   }
544
545   /**
546    * Validates that <b>every</b> top level destination property for each configured TypeMap is
547    * mapped to one and only one source property, or that a {@code Converter} was
548    * {@link TypeMap#setConverter(Converter) set} for the TypeMap. If not, a ConfigurationException
549    * is thrown detailing any missing mappings.
550    * 
551    * @throws ValidationException if any TypeMaps contain unmapped properties
552    */

553   public void validate() {
554     Errors errors = new Errors();
555     for (TypeMap<?, ?> typeMap : getTypeMaps()) {
556       try {
557         typeMap.validate();
558       } catch (ValidationException e) {
559         errors.merge(e.getErrorMessages());
560       }
561     }
562
563     errors.throwValidationExceptionIfErrorsExist();
564   }
565
566   /**
567    * Register a module
568    *
569    * @param module a module for extension
570    */

571   public ModelMapper registerModule(Module module) {
572     module.setupModule(this);
573     return this;
574   }
575
576   private <S, D> TypeMap<S, D> createTypeMapInternal(S source, Class<S> sourceType,
577       Class<D> destinationType, String typeMapName, Configuration configuration) {
578     if (source != null)
579       sourceType = Types.<S>deProxy(source.getClass());
580     Assert.state(config.typeMapStore.get(sourceType, destinationType, typeMapName) == null,
581         "A TypeMap already exists for %s and %s", sourceType, destinationType);
582     return config.typeMapStore.create(source, sourceType, destinationType, typeMapName,
583         (InheritingConfiguration) configuration, engine);
584   }
585
586   private <D> D mapInternal(Object source, D destination, Type destinationType, String typeMapName) {
587     if (destination != null)
588       destinationType = Types.<D>deProxy(destination.getClass());
589     return engine.<Object, D>map(source, Types.<Object>deProxy(source.getClass()), destination,
590         TypeToken.<D>of(destinationType), typeMapName);
591   }
592 }
593