*/
public <S, D> MappingStrategy resolveMappingStrategy(final S sourceObject, final java.lang.reflect.Type initialSourceType, final java.lang.reflect.Type initialDestinationType, boolean mapInPlace, final MappingContext context) {
MappingStrategyKey key = new MappingStrategyKey(sourceObject.getClass(), initialSourceType, initialDestinationType, mapInPlace);
MappingStrategy strategy = strategyCache.get(key);
if (strategy == null) {
@SuppressWarnings("unchecked")
Type<S> sourceType = (Type<S>) (initialSourceType != null ? TypeFactory.valueOf(initialSourceType) : TypeFactory.typeOf(sourceObject));
Type<D> destinationType = TypeFactory.valueOf(initialDestinationType);
MappingStrategyRecorder strategyRecorder = new MappingStrategyRecorder(key, unenhanceStrategy);
final Type<S> resolvedSourceType = normalizeSourceType(sourceObject, sourceType, destinationType);
final S resolvedSourceObject;
if (mapInPlace) {
resolvedSourceObject = sourceObject;
} else {
resolvedSourceObject = unenhanceStrategy.unenhanceObject(sourceObject, sourceType);
}
strategyRecorder.setResolvedSourceType(resolvedSourceType);
strategyRecorder.setResolvedDestinationType(destinationType);
if (sourceObject != resolvedSourceObject) {
strategyRecorder.setUnenhance(true);
}
if (!mapInPlace && canCopyByReference(destinationType, resolvedSourceType)) {
/*
* We can copy by reference when source and destination types
* are the same and immutable.
*/
strategyRecorder.setCopyByReference(true);
} else if (!mapInPlace && canConvert(resolvedSourceType, destinationType)) {
strategyRecorder.setResolvedConverter(mapperFactory.getConverterFactory().getConverter(resolvedSourceType,
destinationType));
} else {
Type<? extends D> resolvedDestinationType;
if (mapInPlace) {
resolvedDestinationType = destinationType;
} else {
strategyRecorder.setInstantiate(true);
resolvedDestinationType = mapperFactory.lookupConcreteDestinationType(resolvedSourceType, destinationType,
context);
if (resolvedDestinationType == null) {
if (!ClassUtil.isConcrete(destinationType)) {
MappingException e = new MappingException("No concrete class mapping defined for source class "
+ resolvedSourceType.getName());
e.setDestinationType(destinationType);
e.setSourceType(resolvedSourceType);
throw e;
} else {
resolvedDestinationType = destinationType;
}
}
}
strategyRecorder.setResolvedDestinationType(resolvedDestinationType);
strategyRecorder.setResolvedMapper(resolveMapper(resolvedSourceType, resolvedDestinationType));
if (!mapInPlace) {
strategyRecorder.setResolvedObjectFactory(mapperFactory.lookupObjectFactory(resolvedDestinationType));
}
}
strategy = strategyRecorder.playback();
if (log.isDebugEnabled()) {
log.debug(strategyRecorder.describeDetails());
}
strategyCache.put(key, strategy);
}
/*
* Set the resolved types on the current mapping context; this can be used
* by downstream Mappers to determine the originally resolved types
*/
context.setResolvedSourceType(strategy.getSoureType());
context.setResolvedDestinationType(strategy.getDestinationType());
return strategy;
}