KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > dozer > util > mapping > MappingProcessor


1 /*
2  * Copyright 2005-2007 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 net.sf.dozer.util.mapping;
17
18 import java.lang.reflect.Array JavaDoc;
19 import java.lang.reflect.InvocationTargetException JavaDoc;
20 import java.lang.reflect.Method JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.Arrays JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Set JavaDoc;
30
31 import net.sf.dozer.util.mapping.cache.Cache;
32 import net.sf.dozer.util.mapping.cache.CacheEntry;
33 import net.sf.dozer.util.mapping.cache.CacheKeyFactory;
34 import net.sf.dozer.util.mapping.cache.CacheManagerIF;
35 import net.sf.dozer.util.mapping.converters.CustomConverter;
36 import net.sf.dozer.util.mapping.converters.CustomConverterContainer;
37 import net.sf.dozer.util.mapping.converters.PrimitiveOrWrapperConverter;
38 import net.sf.dozer.util.mapping.event.DozerEvent;
39 import net.sf.dozer.util.mapping.event.DozerEventManager;
40 import net.sf.dozer.util.mapping.event.EventManagerIF;
41 import net.sf.dozer.util.mapping.fieldmap.ClassMap;
42 import net.sf.dozer.util.mapping.fieldmap.Configuration;
43 import net.sf.dozer.util.mapping.fieldmap.ExcludeFieldMap;
44 import net.sf.dozer.util.mapping.fieldmap.FieldMap;
45 import net.sf.dozer.util.mapping.fieldmap.GenericFieldMap;
46 import net.sf.dozer.util.mapping.fieldmap.MapFieldMap;
47 import net.sf.dozer.util.mapping.stats.StatisticTypeConstants;
48 import net.sf.dozer.util.mapping.stats.StatisticsManagerIF;
49 import net.sf.dozer.util.mapping.util.ClassMapBuilder;
50 import net.sf.dozer.util.mapping.util.ClassMapFinder;
51 import net.sf.dozer.util.mapping.util.ClassMapKeyFactory;
52 import net.sf.dozer.util.mapping.util.CollectionUtils;
53 import net.sf.dozer.util.mapping.util.DateFormatContainer;
54 import net.sf.dozer.util.mapping.util.DestBeanCreator;
55 import net.sf.dozer.util.mapping.util.LogMsgFactory;
56 import net.sf.dozer.util.mapping.util.MapperConstants;
57 import net.sf.dozer.util.mapping.util.MappingUtils;
58 import net.sf.dozer.util.mapping.util.MappingValidator;
59 import net.sf.dozer.util.mapping.util.ReflectionUtils;
60
61 import org.apache.commons.collections.IteratorUtils;
62 import org.apache.commons.collections.set.ListOrderedSet;
63 import org.apache.commons.lang.StringUtils;
64 import org.apache.commons.logging.Log;
65 import org.apache.commons.logging.LogFactory;
66
67 /**
68  * Dozer's Internal Mapping Engine
69  *
70  * @author garsombke.franz
71  * @author sullins.ben
72  * @author tierney.matt
73  *
74  */

75 public class MappingProcessor implements MapperIF {
76
77   private static final Log log = LogFactory.getLog(MappingProcessor.class);
78
79   /*
80    * Not Accessible
81    */

82   private List JavaDoc superListOfFieldNames = null;
83   private final transient Map JavaDoc customMappings;
84   private final Configuration globalConfiguration;
85   private final List JavaDoc customConverterObjects;//actual converter object instances
86
private final StatisticsManagerIF statsMgr;
87   private final EventManagerIF eventMgr;
88   private final CustomFieldMapperIF customFieldMapper;
89   private final ClassMapFinder classMapFinder = new ClassMapFinder();
90   private final MappingUtils mappingUtils = new MappingUtils();
91   private final ReflectionUtils reflectionUtils = new ReflectionUtils();
92   private final CollectionUtils collectionUtils = new CollectionUtils();
93   private final MappingValidator mappingValidator = new MappingValidator();
94   private final ClassMapBuilder classMapBuilder = new ClassMapBuilder();
95   private final LogMsgFactory logMsgFactory = new LogMsgFactory();
96   private final DestBeanCreator destBeanCreator = new DestBeanCreator(MappingUtils.storedFactories);//only temp use the static var. the stored factories need to be relocated
97
private final PrimitiveOrWrapperConverter primitiveOrWrapperConverter = new PrimitiveOrWrapperConverter();
98   private final Map JavaDoc mappedFields = new HashMap JavaDoc();
99   private final Cache converterByDestTypeCache;
100   private final Cache superTypeCache;
101   
102   public MappingProcessor(Map JavaDoc mappings, Configuration globalConfiguration, CacheManagerIF cacheMgr,
103       StatisticsManagerIF statsMgr, List JavaDoc customConverterObjects, List JavaDoc eventListeners,
104       CustomFieldMapperIF customFieldMapper) {
105     this.customMappings = mappings;
106     this.globalConfiguration = globalConfiguration;
107     this.statsMgr = statsMgr;
108     this.customConverterObjects = customConverterObjects;
109     this.eventMgr = new DozerEventManager(eventListeners);
110     this.customFieldMapper = customFieldMapper;
111     this.converterByDestTypeCache = cacheMgr.getCache(MapperConstants.CONVERTER_BY_DEST_TYPE_CACHE);
112     this.superTypeCache = cacheMgr.getCache(MapperConstants.SUPER_TYPE_CHECK_CACHE);
113   }
114
115   public Object JavaDoc map(Object JavaDoc sourceObj, Class JavaDoc destClass) {
116     //map-id is optional, so just pass in null
117
return map(sourceObj, destClass, (String JavaDoc) null);
118   }
119
120   public Object JavaDoc map(Object JavaDoc sourceObj, Class JavaDoc destClass, String JavaDoc mapId) {
121     Object JavaDoc destObj = null;
122     ClassMap classMap = null;
123     try {
124       mappingValidator.validateMappingRequest(sourceObj, destClass);
125       classMap = getClassMap(sourceObj, destClass, mapId, false);
126       
127       //Check to see if custom converter has been specified for this mapping combination. If so, just use it.
128
CustomConverterContainer customConverterContainer = classMap.getConfiguration().getCustomConverters();
129       Class JavaDoc converterClass = mappingUtils.findCustomConverter(converterByDestTypeCache, customConverterContainer, sourceObj.getClass(), destClass);
130       if (converterClass != null) {
131         eventMgr.fireEvent(new DozerEvent(MapperConstants.MAPPING_STARTED_EVENT, classMap, null, sourceObj, destObj, null));
132         return mapUsingCustomConverter(converterClass, sourceObj.getClass(), sourceObj, destClass, destObj, null, true);
133       }
134       
135       //Create destination object. It will be populated in the call to map()
136
destObj = destBeanCreator.create(sourceObj, classMap, destClass);
137       
138       //Fire event to any listeners
139
eventMgr.fireEvent(new DozerEvent(MapperConstants.MAPPING_STARTED_EVENT, classMap, null, sourceObj, destObj, null));
140       
141       //Map src values to dest object
142
map(classMap, sourceObj, destObj, null, null);
143     } catch (Throwable JavaDoc e) {
144       mappingUtils.throwMappingException(e);
145     }
146     eventMgr.fireEvent(new DozerEvent(MapperConstants.MAPPING_FINISHED_EVENT, classMap, null, sourceObj, destObj, null));
147     return destObj;
148   }
149
150   public void map(Object JavaDoc sourceObj, Object JavaDoc destObj) {
151     map(sourceObj, destObj, null);
152   }
153
154   public void map(Object JavaDoc sourceObj, Object JavaDoc destObj, String JavaDoc mapId) {
155     ClassMap classMap = null;
156     try {
157       //validate request and find the appropriate class map for the source/dest obj combination
158
mappingValidator.validateMappingRequest(sourceObj, destObj);
159       classMap = getClassMap(sourceObj, destObj.getClass(), mapId, true);
160
161       //Check to see if custom converter has been specified for this mapping combination. If so, just use it.
162
CustomConverterContainer customConverterContainer = classMap.getConfiguration().getCustomConverters();
163       Class JavaDoc converterClass = mappingUtils.findCustomConverter(converterByDestTypeCache, customConverterContainer, sourceObj.getClass(), destObj.getClass());
164       eventMgr.fireEvent(new DozerEvent(MapperConstants.MAPPING_STARTED_EVENT, classMap, null, sourceObj, destObj, null));
165
166       if (converterClass != null) {
167         mapUsingCustomConverter(converterClass, sourceObj.getClass(), sourceObj, destObj.getClass(), destObj, null,
168             true);
169         return;
170       }
171       
172       //Map src values to dest object
173
map(classMap, sourceObj, destObj, null, null);
174     } catch (Throwable JavaDoc e) {
175       mappingUtils.throwMappingException(e);
176     }
177     eventMgr.fireEvent(new DozerEvent(MapperConstants.MAPPING_FINISHED_EVENT, classMap, null, sourceObj, destObj, null));
178   }
179
180   private void map(ClassMap classMap, Object JavaDoc sourceObj, Object JavaDoc destObj, ClassMap parentClassMap, FieldMap parentFieldMap)
181       throws NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc, IllegalAccessException JavaDoc,
182       InvocationTargetException JavaDoc, InstantiationException JavaDoc {
183     mappingValidator.validateMappingRequest(sourceObj, destObj);
184
185     //1596766 - Recursive object mapping issue. Prevent recursive mapping infinite loop
186
//Keep a record of mapped fields by storing the id of the sourceObj and the destObj to be mapped
187
//This can be referred to later to avoid recursive mapping loops
188
String JavaDoc key = mappingUtils.getMappedFieldKey(sourceObj);
189     mappedFields.put(key, destObj);
190
191     // see if we need to pull a referenced mapId
192
String JavaDoc mapId = null;
193     if (parentFieldMap != null) {
194       mapId = parentFieldMap.getMapId();
195     }
196
197     //If class map hasnt already been determined, find the appropriate one for the src/dest object combination
198
if (classMap == null) {
199       classMap = getClassMap(sourceObj, destObj.getClass(), mapId, true);
200     }
201
202     //What is this and why here?
203
if (parentClassMap != null) {
204       if (superListOfFieldNames == null) {
205         superListOfFieldNames = new ArrayList JavaDoc();
206       }
207     }
208
209     Class JavaDoc sourceClass = sourceObj.getClass();
210     Class JavaDoc destClass = destObj.getClass();
211
212     //Check to see if custom converter has been specified for this mapping combination. If so, just use it.
213
CustomConverterContainer customConverterContainer = classMap.getConfiguration().getCustomConverters();
214     Class JavaDoc converterClass = mappingUtils.findCustomConverter(converterByDestTypeCache, customConverterContainer, sourceObj.getClass(), destClass);
215     if (converterClass != null) {
216       Object JavaDoc rvalue = mapUsingCustomConverter(converterClass, sourceObj.getClass(), sourceObj, destClass, destObj,
217           null, true);
218       if (rvalue != null) {
219         destObj = rvalue;
220       }
221       return;
222     }
223
224     //Now check for super class mappings as a convenience -assuming for now that super class mappings are at the same level
225
List JavaDoc parentFieldNames = null;
226     if (parentClassMap == null) {
227       // check for super classes
228
List JavaDoc superClasses = checkForSuperTypeMapping(sourceClass, destClass);
229       // check for interfaces
230
superClasses.addAll(classMapFinder.findInterfaceMappings(this.customMappings, sourceClass, destClass));
231       if (superClasses != null && superClasses.size() > 0) {
232         parentFieldNames = processSuperTypeMapping(superClasses, sourceObj, destObj, sourceClass, parentFieldMap);
233       }
234     }
235
236     // Perform mappings for each field. Iterate through Fields Maps for this class mapping
237
List JavaDoc fieldMaps = classMap.getFieldMaps();
238     int size = fieldMaps.size();
239     for (int i = 0; i < size; i++) {
240       FieldMap fieldMapping = (FieldMap) fieldMaps.get(i);
241       mapField(fieldMapping, classMap, sourceObj, destObj, parentClassMap, parentFieldMap, parentFieldNames);
242     }
243   }
244
245   private void mapField(FieldMap fieldMapping, ClassMap classMap, Object JavaDoc sourceObj, Object JavaDoc destObj,
246       ClassMap parentClassMap, FieldMap parentFieldMap, List JavaDoc parentFieldNames) {
247
248     //The field has been explicitly excluded from mapping. So just return, as no further processing is needed for this field
249
if (fieldMapping instanceof ExcludeFieldMap) {
250       return;
251     }
252     
253     Class JavaDoc sourceClass = sourceObj.getClass();
254     Class JavaDoc destClass = destObj.getClass();
255     Object JavaDoc sourceFieldValue = null;
256     try {
257       sourceFieldValue = fieldMapping.getSrcFieldValue(sourceObj);
258       // check for super class names
259
String JavaDoc parentSourceField = null;
260       if (parentFieldMap != null) {
261         parentSourceField = parentFieldMap.getSourceField().getName();
262       }
263
264       String JavaDoc methodName = fieldMapping.getDestFieldReadMethodName(destClass);
265       String JavaDoc sourceMethodName = fieldMapping.getSourceFieldReadMethodName(sourceClass);
266       String JavaDoc key = mappingUtils.getParentFieldNameKey(parentSourceField, sourceObj, sourceClass.getName(),
267           sourceMethodName, methodName, fieldMapping.getSourceField().getName(), fieldMapping.getDestField().getName());
268       if (parentClassMap != null) {
269         if (superListOfFieldNames.contains(key)) {
270           return;
271         } else {
272           superListOfFieldNames.add(key);
273         }
274       }
275       // check for parent field names
276
if (parentFieldNames != null && parentFieldNames.size() > 0) {
277         if (parentFieldNames.contains(key)) {
278           return;
279         } else {
280           parentFieldNames.add(key);
281         }
282       }
283       
284       //If a custom field mapper was specified, then invoke it. If not, or the custom
285
//field mapper returns false(indicating the field was not actually mapped by
286
//the custom field mapper), proceed as normal(use Dozer to map the field)
287
boolean fieldMapped = false;
288       if (customFieldMapper != null ) {
289         fieldMapped = customFieldMapper.mapField(sourceObj, destObj, sourceFieldValue, classMap, fieldMapping);
290       }
291       
292       if (!fieldMapped) {
293         if (fieldMapping instanceof GenericFieldMap && ((GenericFieldMap) fieldMapping).isMethodMap()
294             && fieldMapping.getDestField().getType().equals(MapperConstants.ITERATE)) {
295           //special logic for iterate feature
296
mapFromIterateMethodFieldMap(sourceObj, destObj, sourceFieldValue, classMap, fieldMapping);
297         } else {
298           //either deep field map or generic map. The is the most likely scenario
299
mapFromFieldMap(sourceObj, destObj, sourceFieldValue, classMap, fieldMapping);
300         }
301       }
302
303       statsMgr.increment(StatisticTypeConstants.FIELD_MAPPING_SUCCESS_COUNT);
304
305     } catch (Throwable JavaDoc e) {
306       log.error(logMsgFactory.createFieldMappingErrorMsg(sourceObj, fieldMapping, sourceFieldValue, destObj, e), e);
307       statsMgr.increment(StatisticTypeConstants.FIELD_MAPPING_FAILURE_COUNT);
308
309       // check error handling policy.
310
if (classMap.getStopOnErrors()) {
311         mappingUtils.throwMappingException(e);
312       } else {
313           //check if any Exceptions should be allowed to be thrown
314
if (!classMap.getAllowedExceptions().isEmpty()) {
315               if (e.getCause() instanceof InvocationTargetException JavaDoc) {
316                   Throwable JavaDoc thrownType = ((InvocationTargetException JavaDoc)e.getCause()).getTargetException();
317                   Class JavaDoc exceptionClass = thrownType.getClass();
318                   if(classMap.getAllowedExceptions().contains(exceptionClass)) {
319                       throw (RuntimeException JavaDoc)thrownType;
320                   }
321               }
322           }
323         statsMgr.increment(StatisticTypeConstants.FIELD_MAPPING_FAILURE_IGNORED_COUNT);
324       }
325     }
326   }
327
328   private void mapFromFieldMap(Object JavaDoc sourceObj, Object JavaDoc destObj, Object JavaDoc sourceFieldValue, ClassMap classMap,
329       FieldMap fieldMapping) throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc, InvocationTargetException JavaDoc,
330       InstantiationException JavaDoc, NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc, NoSuchFieldException JavaDoc {
331     Class JavaDoc destFieldType = null;
332     // methodmap logic should be encapsulated and figured out at the fieldmap level
333
if (fieldMapping instanceof GenericFieldMap && ((GenericFieldMap) fieldMapping).isMethodMap()) {
334       destFieldType = fieldMapping.getDestFieldWriteMethod(destObj.getClass()).getParameterTypes()[0];
335     } else {
336       destFieldType = fieldMapping.getDestFieldType(destObj.getClass());
337     }
338         
339     //1476780 - 12/2006 mht - Add support for field level custom converters
340
//Use field level custom converter if one was specified. Otherwise, map or recurse the object as normal
341
Object JavaDoc destFieldValue = null;
342     if (mappingUtils.isBlankOrNull(fieldMapping.getCustomConverter())) {
343       destFieldValue = mapOrRecurseObject(sourceObj, sourceFieldValue, destFieldType, classMap, fieldMapping, destObj);
344     } else {
345       Class JavaDoc sourceFieldClass = sourceFieldValue != null ? sourceFieldValue.getClass() : fieldMapping.getSourceFieldType(sourceObj.getClass());
346       destFieldValue = mapUsingCustomConverter(Class.forName(fieldMapping.getCustomConverter()), sourceFieldClass, sourceFieldValue,
347           destFieldType, null, fieldMapping, false);
348     }
349     
350     writeDestinationValue(destObj, destFieldValue, classMap, fieldMapping);
351     
352     if(log.isDebugEnabled()) {
353       log.debug(logMsgFactory.createFieldMappingSuccessMsg(sourceObj.getClass(), destObj.getClass(), fieldMapping.getSourceField().getName(),
354           fieldMapping.getDestField().getName(), sourceFieldValue, destFieldValue));
355     }
356   }
357
358   // TODO there has to be a much better way then ignoreClassMap flag
359
// this is related to testPropertyClassLevelMapBack unit test. transforming String to Integer from HashMap
360
private Object JavaDoc mapOrRecurseObject(Object JavaDoc srcObj, Object JavaDoc sourceFieldValue, Class JavaDoc destFieldType, ClassMap classMap, FieldMap fieldMap,
361       Object JavaDoc destObj) throws InvocationTargetException JavaDoc, InstantiationException JavaDoc, IllegalAccessException JavaDoc,
362       NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
363     return mapOrRecurseObject(srcObj, sourceFieldValue, destFieldType, classMap, fieldMap, destObj, false);
364   }
365
366   private Object JavaDoc mapOrRecurseObject(Object JavaDoc srcObj, Object JavaDoc sourceFieldValue, Class JavaDoc destFieldType, ClassMap classMap, FieldMap fieldMap,
367       Object JavaDoc destObj, boolean ignoreClassMap) throws InvocationTargetException JavaDoc, InstantiationException JavaDoc,
368       IllegalAccessException JavaDoc, NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
369     Class JavaDoc sourceFieldClass = sourceFieldValue != null ? sourceFieldValue.getClass() : fieldMap.getSourceFieldType(srcObj.getClass());
370     CustomConverterContainer customConverters = classMap.getConfiguration().getCustomConverters();
371     Class JavaDoc converterClass = mappingUtils.determineCustomConverter(fieldMap, converterByDestTypeCache, customConverters, sourceFieldClass, destFieldType);
372
373     // 1-2007 mht: Invoke custom converter even if the src value is null. #1563795
374
if (converterClass != null) {
375       return mapUsingCustomConverter(converterClass, sourceFieldClass, sourceFieldValue, destFieldType, destObj,
376           fieldMap, false);
377     }
378
379     boolean isDestFieldTypeSupportedMap = mappingUtils.isSupportedMap(destFieldType);
380     if (sourceFieldValue == null && !isDestFieldTypeSupportedMap) {
381       return null;
382     }
383     
384     // this is so we don't null out the entire Map with a null source value
385
if (sourceFieldValue == null && isDestFieldTypeSupportedMap) {
386       return mapMapToProperty(srcObj, sourceFieldValue, null, fieldMap, destObj, destFieldType, classMap);
387     }
388     
389     //1596766 - Recursive object mapping issue. Prevent recursive mapping infinite loop
390
String JavaDoc key = mappingUtils.getMappedFieldKey(sourceFieldValue);
391     Object JavaDoc value = mappedFields.get(key);
392     if (value != null && value.getClass().equals(destFieldType)) {
393       // Source value has already been mapped to the required destFieldType.
394
return value;
395     }
396
397     if (fieldMap.getCopyByReference()) {
398       //just get the src and return it, no transformation.
399
return sourceFieldValue;
400     }
401     // if the mapId is not null then it means we are mapping a Class Level Map Backed Property
402
// in the future the mapId might be used for other things...
403
if (fieldMap.getMapId() != null && mappingUtils.validateMap(sourceFieldClass, destFieldType, fieldMap)) {
404       return mapCustomObject(fieldMap, destObj, destFieldType, sourceFieldValue);
405     }
406     if (fieldMap instanceof MapFieldMap && !ignoreClassMap) {
407       // we just take the source and set it on the Map - if we are mapping in reverse we need to get the value off of
408
// the map
409
return mapClassLevelMap(srcObj, fieldMap, sourceFieldValue, sourceFieldClass, classMap, destFieldType, destObj);
410     }
411     boolean isSourceFieldClassSupportedMap = mappingUtils.isSupportedMap(sourceFieldClass);
412     if (isSourceFieldClassSupportedMap && isDestFieldTypeSupportedMap) {
413       return mapMap(srcObj, sourceFieldValue, classMap, fieldMap, destObj, destFieldType);
414     }
415     if (isSourceFieldClassSupportedMap || isDestFieldTypeSupportedMap) {
416       return mapMapToProperty(srcObj, sourceFieldValue, sourceFieldClass, fieldMap, destObj, destFieldType, classMap);
417     }
418     if (mappingUtils.isCustomMapMethod(fieldMap)) {
419       return mapCustomMapToProperty(sourceFieldValue, sourceFieldClass, fieldMap, destObj, destFieldType);
420     }
421     if (mappingUtils.isPrimitiveOrWrapper(sourceFieldClass) || mappingUtils.isPrimitiveOrWrapper(destFieldType)) {
422       //Primitive or Wrapper conversion
423
if (fieldMap.getDestinationTypeHint() != null) {
424         destFieldType = fieldMap.getDestinationTypeHint().getHint();
425       }
426       return primitiveOrWrapperConverter.convert(sourceFieldValue, destFieldType, new DateFormatContainer(classMap, fieldMap));
427     }
428     if (mappingUtils.isSupportedCollection(sourceFieldClass)
429         && (mappingUtils.isSupportedCollection(destFieldType))) {
430       return mapCollection(srcObj, sourceFieldValue, classMap, fieldMap, destObj);
431     }
432
433     //Default: Map from one custom data object to another custom data object
434
return mapCustomObject(fieldMap, destObj, destFieldType, sourceFieldValue);
435   }
436
437   private Object JavaDoc mapClassLevelMap(Object JavaDoc srcObj, FieldMap fieldMap, Object JavaDoc sourceFieldValue, Class JavaDoc sourceFieldClass,
438       ClassMap classMap, Class JavaDoc destType, Object JavaDoc destObj) throws InvocationTargetException JavaDoc, IllegalAccessException JavaDoc,
439       NoSuchFieldException JavaDoc, InstantiationException JavaDoc, ClassNotFoundException JavaDoc, NoSuchMethodException JavaDoc {
440     // TODO This should be encapsulated in MapFieldMap?
441
if (!mappingUtils.isSupportedMap(sourceFieldClass) && !classMap.getSourceClass().isCustomMap()) {
442       return sourceFieldValue;
443     } else {
444       String JavaDoc key = null;
445       if (StringUtils.isEmpty(fieldMap.getDestField().getKey())) {
446         key = fieldMap.getDestField().getName();
447       } else {
448         key = fieldMap.getDestField().getKey();
449       }
450       Method JavaDoc resultMethod = reflectionUtils.getMethod(sourceFieldValue, fieldMap.getSourceField().getMapGetMethod());
451       Object JavaDoc result = resultMethod.invoke(sourceFieldValue, new Object JavaDoc[] { key });
452       return mapOrRecurseObject(srcObj, result, destType, classMap, fieldMap, destObj, true);
453     }
454   }
455
456   private Object JavaDoc mapCustomObject(FieldMap fieldMap, Object JavaDoc destObj, Class JavaDoc destFieldType, Object JavaDoc sourceFieldValue)
457       throws InvocationTargetException JavaDoc, IllegalAccessException JavaDoc, InstantiationException JavaDoc, NoSuchMethodException JavaDoc,
458       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
459     // Custom java bean. Need to make sure that the destination object is not already instantiated.
460
Object JavaDoc field = mappingValidator.validateField(fieldMap, destObj, destFieldType);
461     ClassMap classMap = null;
462     // if the field is not null than we don't want a new instance
463
if (field == null) {
464       // first check to see if this plain old field map has hints to the actual type.
465
if (fieldMap.getDestinationTypeHint() != null) {
466         Class JavaDoc destType = fieldMap.getDestinationTypeHint().getHint();
467         // if the destType is null this means that there was more than one hint. we must
468
// have already set the destType then.
469
if (destType != null) {
470           destFieldType = destType;
471         }
472       }
473       //Check to see if explicit map-id has been specified for the field mapping
474
String JavaDoc mapId = null;
475       if (fieldMap != null) {
476         mapId = fieldMap.getMapId();
477       }
478       classMap = getClassMap(sourceFieldValue, destFieldType, mapId, false);
479       field = destBeanCreator.create(sourceFieldValue, classMap, fieldMap, null);
480     }
481     
482     map(classMap, sourceFieldValue, field, null, fieldMap);
483
484     return field;
485   }
486
487   private Object JavaDoc mapCollection(Object JavaDoc srcObj, Object JavaDoc sourceCollectionValue, ClassMap classMap, FieldMap fieldMap, Object JavaDoc destObj)
488       throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc,
489       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
490
491     // if it is an iterator object turn it into a List
492
if (sourceCollectionValue instanceof Iterator JavaDoc) {
493       sourceCollectionValue = IteratorUtils.toList((Iterator JavaDoc) sourceCollectionValue);
494     }
495
496     Class JavaDoc destCollectionType = fieldMap.getDestFieldType(destObj.getClass());
497     Class JavaDoc sourceFieldType = sourceCollectionValue.getClass();
498     Object JavaDoc result = null;
499
500     // if they use a standard Collection we have to assume it is a List...better way to do this?
501
if (destCollectionType.getName().equals(Collection JavaDoc.class.getName())) {
502       destCollectionType = List JavaDoc.class;
503     }
504     // Array to Array
505
if (collectionUtils.isArray(sourceFieldType) && (collectionUtils.isArray(destCollectionType))) {
506       result = mapArrayToArray(srcObj, sourceCollectionValue, classMap, fieldMap, destObj);
507       // Array to List
508
} else if (collectionUtils.isArray(sourceFieldType) && (collectionUtils.isList(destCollectionType))) {
509       result = mapArrayToList(srcObj, sourceCollectionValue, classMap, fieldMap, destObj);
510     }
511     // List to Array
512
else if (collectionUtils.isList(sourceFieldType) && (collectionUtils.isArray(destCollectionType))) {
513       result = mapListToArray(srcObj, (List JavaDoc) sourceCollectionValue, classMap, fieldMap, destObj);
514       // List to List
515
} else if (collectionUtils.isList(sourceFieldType) && (collectionUtils.isList(destCollectionType))) {
516       result = mapListToList(srcObj, (List JavaDoc) sourceCollectionValue, classMap, fieldMap, destObj);
517     }
518     // Set to Set
519
else if (collectionUtils.isSet(sourceFieldType) && collectionUtils.isSet(destCollectionType)) {
520       result = mapSetToSet(srcObj, (Set JavaDoc) sourceCollectionValue, classMap, fieldMap, destObj, destCollectionType);
521     }
522     // Set to Array
523
else if (collectionUtils.isSet(sourceFieldType) && collectionUtils.isArray(destCollectionType)) {
524       result = mapSetToArray(srcObj, (Set JavaDoc) sourceCollectionValue, classMap, fieldMap, destObj);
525     }
526     // Array to Set
527
else if (collectionUtils.isArray(sourceFieldType) && collectionUtils.isSet(destCollectionType)) {
528       result = addToSet(srcObj, fieldMap, Arrays.asList((Object JavaDoc[]) sourceCollectionValue), classMap, destObj);
529     }
530     // Set to List
531
else if (collectionUtils.isSet(sourceFieldType) && collectionUtils.isList(destCollectionType)) {
532       result = mapListToList(srcObj, (Set JavaDoc) sourceCollectionValue, classMap, fieldMap, destObj);
533     }
534     // List to Set
535
else if (collectionUtils.isList(sourceFieldType) && collectionUtils.isSet(destCollectionType)) {
536       result = addToSet(srcObj, fieldMap, (List JavaDoc) sourceCollectionValue, classMap, destObj);
537     }
538     return result;
539   }
540
541   private Object JavaDoc mapMap(Object JavaDoc srcObj, Object JavaDoc sourceMapValue, ClassMap classMap, FieldMap fieldMap, Object JavaDoc destObj, Class JavaDoc destFieldType)
542       throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc,
543       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
544     Map JavaDoc result = null;
545     Object JavaDoc field = fieldMap.doesFieldExist(destObj, destFieldType);
546     if (field == null) {
547       // no destination map exists
548
result = (Map JavaDoc) sourceMapValue.getClass().newInstance();
549     } else {
550       result = (Map JavaDoc) field;
551     }
552     Map JavaDoc sourceMap = (Map JavaDoc) sourceMapValue;
553     Set JavaDoc sourceEntrySet = sourceMap.entrySet();
554     Iterator JavaDoc iter = sourceEntrySet.iterator();
555     while (iter.hasNext()) {
556       Map.Entry JavaDoc sourceEntry = (Map.Entry JavaDoc) iter.next();
557       Object JavaDoc sourceEntryValue = sourceEntry.getValue();
558       Object JavaDoc destEntryValue = mapOrRecurseObject(srcObj, sourceEntryValue, sourceEntryValue.getClass(), classMap, fieldMap,
559           destObj);
560       result.put(sourceEntry.getKey(), destEntryValue);
561     }
562     return result;
563   }
564
565   private Object JavaDoc mapMapToProperty(Object JavaDoc srcObj, Object JavaDoc sourceValue, Class JavaDoc sourceFieldClass, FieldMap fieldMap, Object JavaDoc destObj,
566       Class JavaDoc destType, ClassMap classMap) throws IllegalAccessException JavaDoc, InstantiationException JavaDoc,
567       InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
568     Object JavaDoc srcFieldValue = null;
569     String JavaDoc key = null;
570
571     // determine which field is the Map
572
if (mappingUtils.isSupportedMap(destType)) {
573       Object JavaDoc field = fieldMap.doesFieldExist(destObj, destType);
574       // make sure we don't null out the whole Map
575
if (sourceFieldClass == null) {
576         return field;
577       }
578       if (field == null) {
579         if (fieldMap.getDestinationTypeHint() != null) {
580           // if we have a hint we can instantiate correct object
581
destType = fieldMap.getDestinationTypeHint().getHint();
582         } else if (destType.isInterface()) {
583           // if there is no hint we assume it is a HashMap
584
destType = HashMap JavaDoc.class;
585         }
586         // destType could also be a concrete implementation
587
srcFieldValue = destType.newInstance();
588       } else {
589         srcFieldValue = field;
590       }
591       key = fieldMap.getDestKey();
592       ((Map JavaDoc) srcFieldValue).put(key, sourceValue);
593     } else {
594       key = fieldMap.getSourceKey();
595       srcFieldValue = ((Map JavaDoc) sourceValue).get(key);
596     }
597     return mapOrRecurseObject(srcObj, srcFieldValue, destType, classMap, fieldMap, destObj);
598   }
599
600   private Object JavaDoc mapCustomMapToProperty(Object JavaDoc sourceValue, Class JavaDoc sourceFieldClass, FieldMap fieldMap, Object JavaDoc destObj,
601       Class JavaDoc destType) throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc,
602       NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
603     Object JavaDoc result = null;
604     // determine which field is the Map
605
if (fieldMap.getDestField().getMapGetMethod() != null && fieldMap.getDestField().getMapSetMethod() != null) {
606       Object JavaDoc field = fieldMap.doesFieldExist(destObj, destType);
607       // make sure we don't null out the whole Map
608
if (sourceFieldClass == null) {
609         return field;
610       }
611       if (field == null) {
612         if (fieldMap.getDestinationTypeHint() != null) {
613           // if we have a hint we can instantiate correct object
614
destType = fieldMap.getDestinationTypeHint().getHint();
615         }
616         // destType could also be a concrete implementation
617
result = destType.newInstance();
618       } else {
619         result = field;
620       }
621       String JavaDoc key = fieldMap.getDestKey();
622       Method JavaDoc resultMethod = reflectionUtils.getMethod(result, fieldMap.getDestField().getMapSetMethod());
623       resultMethod.invoke(result, new Object JavaDoc[] { key, sourceValue });
624     } else {
625       String JavaDoc key = fieldMap.getSourceKey();
626       Method JavaDoc resultMethod = reflectionUtils.getMethod(sourceValue, fieldMap.getSourceField().getMapGetMethod());
627       result = resultMethod.invoke(sourceValue, new Object JavaDoc[] { key });
628     }
629     return result;
630   }
631
632   private Object JavaDoc mapArrayToArray(Object JavaDoc srcObj, Object JavaDoc sourceCollectionValue, ClassMap classMap, FieldMap fieldMap, Object JavaDoc destObj)
633       throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc,
634       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
635     Class JavaDoc destEntryType = fieldMap.getDestFieldType(destObj.getClass()).getComponentType();
636     int size = Array.getLength(sourceCollectionValue);
637     if (collectionUtils.isPrimitiveArray(sourceCollectionValue.getClass())) {
638       return addToPrimitiveArray(srcObj, fieldMap, size, sourceCollectionValue, classMap, destObj, destEntryType);
639     } else {
640       List JavaDoc list = Arrays.asList((Object JavaDoc[]) sourceCollectionValue);
641       List JavaDoc returnList = null;
642       if (!destEntryType.getName().equals("java.lang.Object")) {
643         returnList = addOrUpdateToList(srcObj, fieldMap, list, classMap, destObj, destEntryType);
644       } else {
645         returnList = addOrUpdateToList(srcObj, fieldMap, list, classMap, destObj, null);
646       }
647       return collectionUtils.convertListToArray(returnList, destEntryType);
648     }
649   }
650   
651   private void mapFromIterateMethodFieldMap(Object JavaDoc sourceObj, Object JavaDoc destObj, Object JavaDoc sourceFieldValue,
652       ClassMap classMap, FieldMap fieldMapping) throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc,
653       InvocationTargetException JavaDoc, InstantiationException JavaDoc, ClassNotFoundException JavaDoc, NoSuchMethodException JavaDoc,
654       NoSuchFieldException JavaDoc {
655     //Iterate over the destFieldValue - iterating is fine unless we are mapping in the other direction.
656
//Verify that it is truly a collection if it is an iterator object turn it into a List
657
if (sourceFieldValue instanceof Iterator JavaDoc) {
658       sourceFieldValue = IteratorUtils.toList((Iterator JavaDoc) sourceFieldValue);
659     }
660     if (sourceFieldValue != null) {
661       for (int i = 0; i < collectionUtils.getLengthOfCollection(sourceFieldValue); i++) {
662         Object JavaDoc value = collectionUtils.getValueFromCollection(sourceFieldValue, i);
663         // map this value
664
if (fieldMapping.getDestinationTypeHint() == null) {
665           throw new MappingException("<field type=\"iterate\"> must have a source or destination type hint");
666         }
667         // check for custom converters
668
CustomConverterContainer customConverters = classMap.getConfiguration().getCustomConverters();
669         Class JavaDoc converterClass = mappingUtils.findCustomConverter(converterByDestTypeCache, customConverters,
670             value.getClass(), Thread.currentThread().getContextClassLoader().loadClass(fieldMapping.getDestinationTypeHint().getHintName()));
671
672         if (converterClass != null) {
673           Class JavaDoc sourceFieldClass = sourceFieldValue != null ? sourceFieldValue.getClass() : fieldMapping.getSourceFieldType(sourceObj.getClass());
674           value = mapUsingCustomConverter(converterClass, sourceFieldClass, value, fieldMapping
675               .getDestinationTypeHint().getHint(), null, fieldMapping, false);
676         } else {
677           value = map(value, fieldMapping.getDestinationTypeHint().getHint());
678         }
679         if (value != null) {
680           writeDestinationValue(destObj, value, classMap, fieldMapping);
681         }
682       }
683     }
684     if (log.isDebugEnabled()) {
685       log.debug(logMsgFactory.createFieldMappingSuccessMsg(sourceObj.getClass(), destObj.getClass(), fieldMapping.getSourceField().getName(),
686           fieldMapping.getDestField().getName(), sourceFieldValue, null));
687     }
688   }
689
690   private Object JavaDoc addToPrimitiveArray(Object JavaDoc srcObj, FieldMap fieldMap, int size, Object JavaDoc sourceCollectionValue, ClassMap classMap,
691       Object JavaDoc destObj, Class JavaDoc destEntryType) throws IllegalAccessException JavaDoc, InstantiationException JavaDoc,
692       InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
693
694     Object JavaDoc result = null;
695     Object JavaDoc field = fieldMap.doesFieldExist(destObj, destEntryType);
696     int arraySize = 0;
697     if (field == null) {
698       result = Array.newInstance(destEntryType, size);
699     } else {
700       result = Array.newInstance(destEntryType, size + Array.getLength(field));
701       arraySize = Array.getLength(field);
702       for (int i = 0; i < Array.getLength(field); i++) {
703         Array.set(result, i, Array.get(field, i));
704       }
705     }
706     // primitive arrays are ALWAYS cumulative
707
for (int i = 0; i < size; i++) {
708       Object JavaDoc toValue = mapOrRecurseObject(srcObj, Array.get(sourceCollectionValue, i), destEntryType, classMap, fieldMap,
709           destObj);
710       Array.set(result, arraySize, toValue);
711       arraySize++;
712     }
713     return result;
714   }
715
716   private Object JavaDoc mapListToArray(Object JavaDoc srcObj, Collection JavaDoc sourceCollectionValue, ClassMap classMap, FieldMap fieldMap, Object JavaDoc destObj)
717       throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc,
718       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
719     List JavaDoc list = null;
720     Class JavaDoc destEntryType = fieldMap.getDestFieldType(destObj.getClass()).getComponentType();
721
722     if (!destEntryType.getName().equals("java.lang.Object")) {
723       list = addOrUpdateToList(srcObj, fieldMap, sourceCollectionValue, classMap, destObj, destEntryType);
724     } else {
725       list = addOrUpdateToList(srcObj, fieldMap, sourceCollectionValue, classMap, destObj);
726     }
727     return collectionUtils.convertListToArray(list, destEntryType);
728   }
729
730   private List JavaDoc mapListToList(Object JavaDoc srcObj, Collection JavaDoc sourceCollectionValue, ClassMap classMap, FieldMap fieldMap, Object JavaDoc destObj)
731       throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc,
732       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
733     return addOrUpdateToList(srcObj, fieldMap, sourceCollectionValue, classMap, destObj);
734   }
735
736   private Set JavaDoc addToSet(Object JavaDoc srcObj, FieldMap fieldMap, Collection JavaDoc sourceCollectionValue, ClassMap classMap, Object JavaDoc destObj)
737       throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc,
738       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
739     Class JavaDoc destEntryType = null;
740     ListOrderedSet result = new ListOrderedSet();
741     // don't want to create the set if it already exists.
742
Object JavaDoc field = fieldMap.doesFieldExist(destObj, null);
743     if (field != null) {
744       result.addAll((Collection JavaDoc) field);
745     }
746     Object JavaDoc destValue = null;
747     Iterator JavaDoc iter = sourceCollectionValue.iterator();
748     Object JavaDoc sourceValue = null;
749     while (iter.hasNext()) {
750       sourceValue = iter.next();
751       if (destEntryType == null
752           || (fieldMap.getDestinationTypeHint() != null && fieldMap.getDestinationTypeHint().hasMoreThanOneHint())) {
753         destEntryType = fieldMap.getDestHintType(sourceValue.getClass());
754       }
755       destValue = mapOrRecurseObject(srcObj, sourceValue, destEntryType, classMap, fieldMap, destObj);
756       if (fieldMap.isGenericFieldMap()) {
757         GenericFieldMap gfm = (GenericFieldMap) fieldMap;
758         if (gfm.getRelationshipType() == null
759             || gfm.getRelationshipType().equals(MapperConstants.RELATIONSHIP_CUMULATIVE)) {
760           result.add(destValue);
761         } else {
762           if (result.contains(destValue)) {
763             int index = result.indexOf(destValue);
764             // perform an update if complex type - can't map strings
765
Object JavaDoc obj = result.get(index);
766             // make sure it is not a String
767
if (!obj.getClass().isAssignableFrom(String JavaDoc.class)) {
768               map(null, obj, destValue, null, fieldMap);
769             }
770             result.add(destValue);
771           } else {
772             result.add(destValue);
773           }
774         }
775       } else {
776         result.add(destValue);
777       }
778     }
779     if (field == null) {
780       Class JavaDoc destSetType = fieldMap.getDestFieldType(destObj.getClass());
781       return collectionUtils.createNewSet(destSetType, result);
782     } else {
783       ((Set JavaDoc) field).addAll(result);
784       return (Set JavaDoc) field;
785     }
786   }
787
788   private List JavaDoc addOrUpdateToList(Object JavaDoc srcObj, FieldMap fieldMap, Collection JavaDoc sourceCollectionValue, ClassMap classMap,
789       Object JavaDoc destObj, Class JavaDoc destEntryType) throws IllegalAccessException JavaDoc, InstantiationException JavaDoc,
790       InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
791
792     List JavaDoc result = null;
793     // don't want to create the list if it already exists.
794
// these maps are special cases which do not fall under what we are
795
// looking for
796
Object JavaDoc field = fieldMap.doesFieldExist(destObj, destEntryType);
797     if (field == null) {
798       result = new ArrayList JavaDoc(sourceCollectionValue.size());
799     } else {
800       if (collectionUtils.isList(field.getClass())) {
801         result = (List JavaDoc) field;
802       } else if (collectionUtils.isArray(field.getClass())) {// must be array
803
result = new ArrayList JavaDoc(Arrays.asList((Object JavaDoc[]) field));
804       } else { // assume it is neither - safest way is to create new
805
// List
806
result = new ArrayList JavaDoc(sourceCollectionValue.size());
807       }
808     }
809     Object JavaDoc destValue = null;
810     Iterator JavaDoc iter = sourceCollectionValue.iterator();
811     Object JavaDoc sourceValue = null;
812     Class JavaDoc prevDestEntryType = null;
813     while (iter.hasNext()) {
814       sourceValue = iter.next();
815       if (destEntryType == null
816           || (fieldMap.getDestinationTypeHint() != null && fieldMap.getDestinationTypeHint().hasMoreThanOneHint())) {
817         if (sourceValue == null) {
818           destEntryType = prevDestEntryType;
819         } else {
820           destEntryType = fieldMap.getDestHintType(sourceValue.getClass());
821         }
822       }
823       destValue = mapOrRecurseObject(srcObj, sourceValue, destEntryType, classMap, fieldMap, destObj);
824       prevDestEntryType = destEntryType;
825       if (fieldMap.isGenericFieldMap()) {
826         GenericFieldMap gfm = (GenericFieldMap) fieldMap;
827         if (gfm.getRelationshipType() == null
828             || gfm.getRelationshipType().equals(MapperConstants.RELATIONSHIP_CUMULATIVE)) {
829           result.add(destValue);
830         } else {
831           if (result.contains(destValue)) {
832             int index = result.indexOf(destValue);
833             // perform an update if complex type - can't map strings
834
Object JavaDoc obj = result.get(index);
835             // make sure it is not a String
836
if (!obj.getClass().isAssignableFrom(String JavaDoc.class)) {
837               map(null, obj, destValue, null, fieldMap);
838             }
839             result.set(index, destValue);
840           } else {
841             result.add(destValue);
842           }
843         }
844       } else {
845         result.add(destValue);
846       }
847     }
848     return result;
849   }
850
851   private List JavaDoc addOrUpdateToList(Object JavaDoc srcObj, FieldMap fieldMap, Collection JavaDoc sourceCollectionValue, ClassMap classMap, Object JavaDoc destObj)
852       throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc,
853       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
854     return addOrUpdateToList(srcObj, fieldMap, sourceCollectionValue, classMap, destObj, null);
855   }
856
857   private Set JavaDoc mapSetToSet(Object JavaDoc srcObj, Set JavaDoc sourceCollectionValue, ClassMap classMap, FieldMap fieldMap, Object JavaDoc destObj,
858       Class JavaDoc destClass) throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc,
859       NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
860
861     Object JavaDoc field = fieldMap.doesFieldExist(destObj, destClass);
862     Set JavaDoc result = null;
863     // Sets can not contain the same equals() object - by definition as you
864
// add you might be updating at the same time
865
if (field == null) {
866       Class JavaDoc destFieldType = fieldMap.getDestFieldType(destObj.getClass());
867       result = collectionUtils.createNewSet(destFieldType);
868     } else {
869       result = (Set JavaDoc) field;
870     }
871     Iterator JavaDoc iter = sourceCollectionValue.iterator();
872     while (iter.hasNext()) {
873       Object JavaDoc obj = iter.next();
874       Class JavaDoc destEntryType = fieldMap.getDestHintType(obj.getClass());
875       Object JavaDoc destValue = mapOrRecurseObject(srcObj, obj, destEntryType, classMap, fieldMap, destObj);
876       result.add(destValue);
877     }
878     return result;
879   }
880
881   private Object JavaDoc mapSetToArray(Object JavaDoc srcObj, Collection JavaDoc sourceCollectionValue, ClassMap classMap, FieldMap fieldMap, Object JavaDoc destObj)
882       throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc,
883       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
884     return mapListToArray(srcObj, sourceCollectionValue, classMap, fieldMap, destObj);
885   }
886
887   private List JavaDoc mapArrayToList(Object JavaDoc srcObj, Object JavaDoc sourceCollectionValue, ClassMap classMap, FieldMap fieldMap, Object JavaDoc destObj)
888       throws IllegalAccessException JavaDoc, InstantiationException JavaDoc, InvocationTargetException JavaDoc, NoSuchMethodException JavaDoc,
889       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
890     Class JavaDoc destEntryType = null;
891     if (fieldMap.getDestinationTypeHint() != null) {
892       destEntryType = fieldMap.getDestinationTypeHint().getHint();
893     } else {
894       destEntryType = sourceCollectionValue.getClass().getComponentType();
895     }
896     List JavaDoc srcValueList = null;
897     if (collectionUtils.isPrimitiveArray(sourceCollectionValue.getClass())) {
898       srcValueList = collectionUtils.convertPrimitiveArrayToList(sourceCollectionValue);
899     } else {
900       srcValueList = Arrays.asList((Object JavaDoc[]) sourceCollectionValue);
901     }
902     return addOrUpdateToList(srcObj, fieldMap, srcValueList, classMap, destObj, destEntryType);
903   }
904
905   private void writeDestinationValue(Object JavaDoc destObj, Object JavaDoc destFieldValue, ClassMap classMap, FieldMap fieldMapping)
906       throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc, InstantiationException JavaDoc, NoSuchMethodException JavaDoc,
907       ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
908     boolean bypass = false;
909     // don't map null to dest field if map-null="false"
910
if (destFieldValue == null && !classMap.getDestClass().getMapNull().booleanValue()) {
911       bypass = true;
912     }
913
914     // don't map "" to dest field if map-empty-string="false"
915
if (destFieldValue != null && destFieldValue.getClass().equals(String JavaDoc.class) &&
916         StringUtils.isEmpty((String JavaDoc) destFieldValue) && !classMap.getDestClass().getMapEmptyString().booleanValue()) {
917         bypass = true;
918     }
919
920     if (!bypass) {
921       eventMgr.fireEvent(new DozerEvent(MapperConstants.MAPPING_PRE_WRITING_DEST_VALUE, classMap, fieldMapping, null, destObj, destFieldValue));
922       
923       fieldMapping.writeDestinationValue(destObj, destFieldValue, classMap);
924       
925       eventMgr.fireEvent(new DozerEvent(MapperConstants.MAPPING_POST_WRITING_DEST_VALUE, classMap, fieldMapping, null, destObj, destFieldValue));
926     }
927   }
928
929   private Object JavaDoc mapUsingCustomConverter(Class JavaDoc customConverterClass, Class JavaDoc srcFieldClass, Object JavaDoc srcFieldValue,
930       Class JavaDoc destFieldClass, Object JavaDoc destFieldValue, FieldMap fieldMap, boolean topLevel) throws IllegalAccessException JavaDoc,
931       InvocationTargetException JavaDoc, InstantiationException JavaDoc, NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc,
932       NoSuchFieldException JavaDoc {
933     Object JavaDoc converterInstance = null;
934     // search our injected customconverters for a match
935
if (customConverterObjects != null) {
936       for (int i = 0; i < customConverterObjects.size(); i++) {
937         Object JavaDoc customConverter = (Object JavaDoc) customConverterObjects.get(i);
938         if (customConverter.getClass().isAssignableFrom(customConverterClass)) {
939           // we have a match
940
converterInstance = customConverter;
941         }
942       }
943     }
944     //if converter object instances were not injected, then create new instance of the
945
//converter for each conversion
946
if (converterInstance == null) {
947       converterInstance = customConverterClass.newInstance();
948     }
949     if (!(converterInstance instanceof CustomConverter)) {
950       throw new MappingException("Custom Converter does not implement CustomConverter interface");
951     }
952     CustomConverter theConverter = (CustomConverter) converterInstance;
953     // if this is a top level mapping the destObj is the highest level mapping...not a recursive mapping
954
if (topLevel) {
955       return theConverter.convert(destFieldValue, srcFieldValue, destFieldClass, srcFieldClass);
956     }
957     Object JavaDoc field = mappingValidator.validateField(fieldMap, destFieldValue, destFieldClass);
958     return theConverter.convert(field, srcFieldValue, destFieldClass, srcFieldClass);
959   }
960
961   private List JavaDoc checkForSuperTypeMapping(Class JavaDoc sourceClass, Class JavaDoc destClass) {
962     // Check cache first
963
Object JavaDoc cacheKey = CacheKeyFactory.createKey(new Object JavaDoc[] { destClass, sourceClass });
964     CacheEntry cacheEntry = superTypeCache.get(cacheKey);
965     if (cacheEntry != null) {
966       return (List JavaDoc) cacheEntry.getValue();
967     }
968
969     // If no existing cache entry is found, determine super type mapping and store in cache
970
Class JavaDoc superSourceClass = sourceClass.getSuperclass();
971     Class JavaDoc superDestClass = destClass.getSuperclass();
972     List JavaDoc superClasses = new ArrayList JavaDoc();
973     boolean stillHasSuperClasses = true;
974     while (stillHasSuperClasses) {
975       if ((superSourceClass != null && !superSourceClass.getName().equals("java.lang.Object"))
976           || (superDestClass != null && !superDestClass.getName().equals("java.lang.Object"))) {
977         // see if the source super class is mapped to the dest class
978
ClassMap superClassMap = (ClassMap) customMappings.get(ClassMapKeyFactory.createKey(superSourceClass,
979             destClass));
980         if (superClassMap != null) {
981           superClasses.add(superClassMap);
982         }
983         // now walk up the dest classes super classes with our super
984
// source class and our source class
985
superDestClass = destClass.getSuperclass();
986         boolean stillHasDestSuperClasses = true;
987         while (stillHasDestSuperClasses) {
988           if (superDestClass != null && !superDestClass.getName().equals("java.lang.Object")) {
989             ClassMap superDestClassMap = (ClassMap) customMappings.get(ClassMapKeyFactory.createKey(
990                 superSourceClass, superDestClass));
991             if (superDestClassMap != null) {
992               superClasses.add(superDestClassMap);
993             }
994             ClassMap sourceClassMap = (ClassMap) customMappings.get(ClassMapKeyFactory.createKey(sourceClass,
995                 superDestClass));
996             if (sourceClassMap != null) {
997               superClasses.add(sourceClassMap);
998             }
999             superDestClass = superDestClass.getSuperclass();
1000          } else {
1001            break;
1002          }
1003        }
1004        superSourceClass = superSourceClass.getSuperclass();
1005      } else {
1006        break;
1007      }
1008    }// while
1009

1010    // multiple levels of custom mapping processed in wrong order - need to reverse
1011
Collections.reverse(superClasses);
1012    // Add to cache
1013
cacheEntry = new CacheEntry(cacheKey, (ArrayList JavaDoc) superClasses);
1014    superTypeCache.put(cacheEntry);
1015
1016    return superClasses;
1017  }
1018
1019  private List JavaDoc processSuperTypeMapping(List JavaDoc superClasses, Object JavaDoc sourceObj, Object JavaDoc destObj, Class JavaDoc sourceClass,
1020      FieldMap parentFieldMap) throws NoSuchMethodException JavaDoc, NoSuchFieldException JavaDoc, ClassNotFoundException JavaDoc,
1021      IllegalAccessException JavaDoc, InvocationTargetException JavaDoc, InstantiationException JavaDoc {
1022    List JavaDoc fieldNamesList = new ArrayList JavaDoc();
1023    Object JavaDoc[] superClassArray = superClasses.toArray();
1024    for (int a = 0; a < superClassArray.length; a++) {
1025      ClassMap map = (ClassMap) superClassArray[a];
1026      map(map, sourceObj, destObj, map, parentFieldMap);
1027      List JavaDoc fieldMaps = map.getFieldMaps();
1028      Class JavaDoc destClassToMap = destObj.getClass();
1029      Class JavaDoc srcClassToMap = sourceObj.getClass();
1030      for (int i = 0; i < fieldMaps.size(); i++) {
1031        FieldMap fieldMapping = (FieldMap) fieldMaps.get(i);
1032        if (!fieldMapping.isGenericFieldMap() && !(fieldMapping instanceof ExcludeFieldMap)) {
1033          // do nothing
1034
} else {
1035          String JavaDoc methodName = fieldMapping.getDestFieldReadMethodName(destClassToMap);
1036          String JavaDoc sourceMethodName = fieldMapping.getSourceFieldReadMethodName(srcClassToMap);
1037          String JavaDoc parentSourceField = null;
1038          if (parentFieldMap != null) {
1039            parentSourceField = parentFieldMap.getSourceField().getName();
1040          }
1041          String JavaDoc key = mappingUtils.getParentFieldNameKey(parentSourceField, sourceObj, sourceClass.getName(),
1042              sourceMethodName, methodName, fieldMapping.getSourceField().getName(), fieldMapping.getDestField().getName());
1043          if (fieldNamesList.contains(key)) {
1044            continue;
1045          } else {
1046            fieldNamesList.add(key);
1047          }
1048        }
1049      }
1050    }
1051    return fieldNamesList;
1052  }
1053
1054  private ClassMap getClassMap(Object JavaDoc sourceObj, Class JavaDoc destClass, String JavaDoc mapId, boolean isInstance) {
1055    ClassMap mapping = classMapFinder.findClassMap(this.customMappings, sourceObj, destClass, mapId, isInstance);
1056
1057    //If mapping not found in exsting custom mapping collection, create default as an explicit mapping must not exist.
1058
//The create default class map method will also add all default mappings that it can determine.
1059
if (mapping == null) {
1060      mapping = classMapBuilder.createDefaultClassMap(globalConfiguration, sourceObj.getClass(), destClass);
1061      customMappings.put(ClassMapKeyFactory.createKey(sourceObj.getClass(), destClass), mapping);
1062    }
1063
1064    return mapping;
1065  }
1066 
1067}
1068
Popular Tags