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], null, null, 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, null, null, 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 null} if 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 null} if 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, null, null);
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<List<String>>() {}.getType();
497 * List<String> 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<List<String>>() {}.getType();
525 * List<String> 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