diff --git a/core/src/main/java/ma/glasnost/orika/MapperFactory.java b/core/src/main/java/ma/glasnost/orika/MapperFactory.java index c6fd103c..5391ea81 100644 --- a/core/src/main/java/ma/glasnost/orika/MapperFactory.java +++ b/core/src/main/java/ma/glasnost/orika/MapperFactory.java @@ -18,6 +18,7 @@ package ma.glasnost.orika; +import java.util.List; import java.util.Set; import ma.glasnost.orika.converter.ConverterFactory; @@ -408,6 +409,11 @@ Type lookupConcreteDestinationType(Type sourceType, Type< * @return the {@link UnenhanceStrategy} associated with this MapperFactory. */ UnenhanceStrategy getUserUnenhanceStrategy(); + + /** + * @return the list of factories used to generate {@link MappingStrategy} + */ + List getMappingStrategyFactories(); /** diff --git a/core/src/main/java/ma/glasnost/orika/MappingStrategyFactory.java b/core/src/main/java/ma/glasnost/orika/MappingStrategyFactory.java new file mode 100644 index 00000000..5c2578dc --- /dev/null +++ b/core/src/main/java/ma/glasnost/orika/MappingStrategyFactory.java @@ -0,0 +1,15 @@ +package ma.glasnost.orika; + +import ma.glasnost.orika.impl.mapping.strategy.MappingStrategyRecorder; + +public interface MappingStrategyFactory { + /** + * Identifies if a mapping strategy can be applied to a scenario with the given context. + */ + boolean isApplicable(MappingStrategyRecorder data); + + /** + * Builds the mapping strategy to be applied to the given context. + */ + MappingStrategy build(MappingStrategyRecorder data); +} diff --git a/core/src/main/java/ma/glasnost/orika/impl/DefaultMapperFactory.java b/core/src/main/java/ma/glasnost/orika/impl/DefaultMapperFactory.java index 5b20c509..2d13a9de 100644 --- a/core/src/main/java/ma/glasnost/orika/impl/DefaultMapperFactory.java +++ b/core/src/main/java/ma/glasnost/orika/impl/DefaultMapperFactory.java @@ -46,20 +46,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; -import ma.glasnost.orika.BoundMapperFacade; -import ma.glasnost.orika.Converter; -import ma.glasnost.orika.DefaultFieldMapper; -import ma.glasnost.orika.Filter; -import ma.glasnost.orika.MapEntry; -import ma.glasnost.orika.MappedTypePair; -import ma.glasnost.orika.Mapper; -import ma.glasnost.orika.MapperFacade; -import ma.glasnost.orika.MapperFactory; -import ma.glasnost.orika.MappingContext; -import ma.glasnost.orika.MappingContextFactory; -import ma.glasnost.orika.MappingException; -import ma.glasnost.orika.ObjectFactory; -import ma.glasnost.orika.Properties; +import com.google.common.collect.ImmutableList; +import ma.glasnost.orika.*; import ma.glasnost.orika.StateReporter.Reportable; import ma.glasnost.orika.constructor.ConstructorResolverStrategy; import ma.glasnost.orika.converter.ConverterFactory; @@ -69,6 +57,10 @@ import ma.glasnost.orika.impl.generator.CompilerStrategy.SourceCodeGenerationException; import ma.glasnost.orika.impl.generator.MapperGenerator; import ma.glasnost.orika.impl.generator.ObjectFactoryGenerator; +import ma.glasnost.orika.impl.mapping.strategy.CopyByReferenceStrategy.CopyByReferenceStrategyFactory; +import ma.glasnost.orika.impl.mapping.strategy.InstantiateAndUseCustomMapperStrategy.InstantiateAndUseCustomMapperStrategyFactory; +import ma.glasnost.orika.impl.mapping.strategy.MapExistingAndUseCustomMapperStrategy.MapExistingAndUseCustomMapperStrategyFactory; +import ma.glasnost.orika.impl.mapping.strategy.UseConverterStrategy.UseConverterStrategyFactory; import ma.glasnost.orika.impl.util.ClassUtil; import ma.glasnost.orika.inheritance.DefaultSuperTypeResolverStrategy; import ma.glasnost.orika.inheritance.SuperTypeResolverStrategy; @@ -126,6 +118,7 @@ public class DefaultMapperFactory implements MapperFactory, Reportable { protected final ClassMapBuilderFactory classMapBuilderFactory; protected ClassMapBuilderFactory chainClassMapBuilderFactory; protected final Map>> usedMapperMetadataRegistry; + protected final List mappingStrategyFactories; protected final boolean useAutoMapping; protected final boolean useBuiltinConverters; @@ -157,6 +150,7 @@ protected DefaultMapperFactory(MapperFactoryBuilder builder) { this.contextFactory = builder.mappingContextFactory; this.nonCyclicContextFactory = new NonCyclicMappingContext.Factory(this.contextFactory.getGlobalProperties()); this.exceptionUtil = new ExceptionUtility(this, builder.dumpStateOnException); + this.mappingStrategyFactories = buildMappingStrategyFactories(builder.mappingStrategyFactories); this.mapperFacade = buildMapperFacade(contextFactory, unenhanceStrategy); this.concreteTypeRegistry = new ConcurrentHashMap>(); @@ -191,7 +185,7 @@ protected DefaultMapperFactory(MapperFactoryBuilder builder) { props.put(Properties.MAPPER_FACTORY, this); props.put(Properties.FILTERS, this.filtersRegistry); props.put(Properties.CAPTURE_FIELD_CONTEXT, builder.captureFieldContext); - + /* * Register default concrete types for common collection types; these * can be overridden as needed by user code. @@ -300,6 +294,11 @@ public static abstract class MapperFactoryBuilder mappingStrategyFactories; /** * Instantiates a new MapperFactoryBuilder @@ -319,6 +318,7 @@ public MapperFactoryBuilder() { favorExtension = valueOf(getProperty(FAVOR_EXTENSION, "false")); captureFieldContext = valueOf(getProperty(CAPTURE_FIELD_CONTEXT, "false")); codeGenerationStrategy = new DefaultCodeGenerationStrategy(); + mappingStrategyFactories = new ArrayList(); } /** @@ -557,6 +557,11 @@ public B codeGenerationStrategy(CodeGenerationStrategy codeGenerationStrategy) { this.codeGenerationStrategy = codeGenerationStrategy ; return self(); } + + public B registerMappingStrategy(MappingStrategyFactory factory) { + this.mappingStrategyFactories.add(factory); + return self(); + } /** * @return a new instance of the Factory for which this builder is @@ -678,6 +683,21 @@ public boolean isAcceptable(Type type) { return unenhancer; } + + protected List buildMappingStrategyFactories(List userFactories) { + ImmutableList.Builder mappingStrategyFactories = ImmutableList.builder(); + + // Order is important here. The first factory in the list that can build a strategy is the one we will get. + // Add the user defined ones first so that they override the defaults. + mappingStrategyFactories.addAll(userFactories); + // The default factories. + mappingStrategyFactories.add(new CopyByReferenceStrategyFactory()); + mappingStrategyFactories.add(new UseConverterStrategyFactory()); + mappingStrategyFactories.add(new InstantiateAndUseCustomMapperStrategyFactory()); + mappingStrategyFactories.add(new MapExistingAndUseCustomMapperStrategyFactory()); + + return mappingStrategyFactories.build(); + } /** * Builds the MapperFacade for this factory. Subclasses can override this @@ -1535,6 +1555,15 @@ public BoundMapperFacade getMapperFacade(Class aType, Class b public UnenhanceStrategy getUserUnenhanceStrategy() { return userUnenahanceStrategy; } + + /* + * (non-Javadoc) + * + * @see ma.glasnost.orika.MapperFactory#getMappingStrategyFactories() + */ + public List getMappingStrategyFactories() { + return mappingStrategyFactories; + } /* * (non-Javadoc) diff --git a/core/src/main/java/ma/glasnost/orika/impl/MapperFacadeImpl.java b/core/src/main/java/ma/glasnost/orika/impl/MapperFacadeImpl.java index 2aa2fb89..1ab261cc 100644 --- a/core/src/main/java/ma/glasnost/orika/impl/MapperFacadeImpl.java +++ b/core/src/main/java/ma/glasnost/orika/impl/MapperFacadeImpl.java @@ -32,17 +32,8 @@ import java.util.Map.Entry; import java.util.Set; -import ma.glasnost.orika.Converter; -import ma.glasnost.orika.MapEntry; -import ma.glasnost.orika.Mapper; -import ma.glasnost.orika.MapperFacade; -import ma.glasnost.orika.MapperFactory; -import ma.glasnost.orika.MappingContext; -import ma.glasnost.orika.MappingContextFactory; -import ma.glasnost.orika.MappingException; -import ma.glasnost.orika.MappingStrategy; +import ma.glasnost.orika.*; import ma.glasnost.orika.MappingStrategy.Key; -import ma.glasnost.orika.ObjectFactory; import ma.glasnost.orika.StateReporter.Reportable; import ma.glasnost.orika.converter.ConverterFactory; import ma.glasnost.orika.impl.mapping.strategy.MappingStrategyRecorder; @@ -78,7 +69,7 @@ public class MapperFacadeImpl implements MapperFacade, Reportable { * @param unenhanceStrategy */ public MapperFacadeImpl(final MapperFactory mapperFactory, final MappingContextFactory contextFactory, - final UnenhanceStrategy unenhanceStrategy, final ExceptionUtility exceptionUtil) { + final UnenhanceStrategy unenhanceStrategy, final ExceptionUtility exceptionUtil) { this.mapperFactory = mapperFactory; this.exceptionUtil = exceptionUtil; this.unenhanceStrategy = unenhanceStrategy; @@ -164,60 +155,14 @@ protected Class getClass(final Object object) { * @return a MappingStrategy suitable to map the source and destination * object */ - public MappingStrategy resolveMappingStrategy(final S sourceObject, final java.lang.reflect.Type initialSourceType, + public MappingStrategy resolveMappingStrategy(final S sourceObject, final java.lang.reflect.Type initialSourceType, final java.lang.reflect.Type initialDestinationType, final boolean mapInPlace, final MappingContext context) { Key key = new Key(getClass(sourceObject), initialSourceType, initialDestinationType, mapInPlace); MappingStrategy strategy = strategyCache.get(key); - if (strategy == null) { - - @SuppressWarnings("unchecked") - Type sourceType = (Type) (initialSourceType != null ? TypeFactory.valueOf(initialSourceType) - : TypeFactory.typeOf(sourceObject)); - Type destinationType = TypeFactory.valueOf(initialDestinationType); - - MappingStrategyRecorder strategyRecorder = new MappingStrategyRecorder(key, unenhanceStrategy); - - final Type resolvedSourceType = normalizeSourceType(sourceObject, sourceType, destinationType); - - strategyRecorder.setResolvedSourceType(resolvedSourceType); - strategyRecorder.setResolvedDestinationType(destinationType); - - if (!mapInPlace && canCopyByReference(destinationType, resolvedSourceType)) { - /* - * We can copy by reference when destination is assignable from - * source and the source is immutable - */ - strategyRecorder.setCopyByReference(true); - } else if (!mapInPlace && canConvert(resolvedSourceType, destinationType)) { - strategyRecorder.setResolvedConverter(mapperFactory.getConverterFactory().getConverter(resolvedSourceType, destinationType)); - - } else { - strategyRecorder.setInstantiate(true); - Type 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 exceptionUtil.decorate(e); - } else { - resolvedDestinationType = destinationType; - } - } - - strategyRecorder.setResolvedDestinationType(resolvedDestinationType); - strategyRecorder.setResolvedMapper(resolveMapper(resolvedSourceType, resolvedDestinationType)); - if (!mapInPlace) { - strategyRecorder.setResolvedObjectFactory(mapperFactory.lookupObjectFactory(resolvedDestinationType, resolvedSourceType)); - } - } - strategy = strategyRecorder.playback(); - if (log.isDebugEnabled()) { - log.debug(strategyRecorder.describeDetails()); - } + strategy = buildMappingStrategy(sourceObject, initialSourceType, initialDestinationType, + mapInPlace, context, key); MappingStrategy existing = strategyCache.putIfAbsent(key, strategy); if (existing != null) { strategy = existing; @@ -234,7 +179,73 @@ public MappingStrategy resolveMappingStrategy(final S sourceObject, final return strategy; } - + + private MappingStrategy buildMappingStrategy(S sourceObject, + java.lang.reflect.Type initialSourceType, + java.lang.reflect.Type initialDestinationType, + boolean mapInPlace, + MappingContext context, + Key key) { + @SuppressWarnings("unchecked") + Type sourceType = (Type) (initialSourceType != null ? TypeFactory.valueOf(initialSourceType) + : TypeFactory.typeOf(sourceObject)); + Type destinationType = TypeFactory.valueOf(initialDestinationType); + + MappingStrategyRecorder strategyRecorder = new MappingStrategyRecorder(key, unenhanceStrategy); + + final Type resolvedSourceType = normalizeSourceType(sourceObject, sourceType, destinationType); + + strategyRecorder.setResolvedSourceType(resolvedSourceType); + strategyRecorder.setResolvedDestinationType(destinationType); + + if (!mapInPlace && canCopyByReference(destinationType, resolvedSourceType)) { + /* + * We can copy by reference when destination is assignable from + * source and the source is immutable + */ + strategyRecorder.setCopyByReference(true); + } else if (!mapInPlace && canConvert(resolvedSourceType, destinationType)) { + strategyRecorder.setResolvedConverter(mapperFactory.getConverterFactory().getConverter(resolvedSourceType, destinationType)); + + } else { + strategyRecorder.setInstantiate(true); + Type 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 exceptionUtil.decorate(e); + } else { + resolvedDestinationType = destinationType; + } + } + + strategyRecorder.setResolvedDestinationType(resolvedDestinationType); + strategyRecorder.setResolvedMapper(resolveMapper(resolvedSourceType, resolvedDestinationType)); + if (!mapInPlace) { + strategyRecorder.setResolvedObjectFactory( + mapperFactory.lookupObjectFactory(resolvedDestinationType, resolvedSourceType)); + } + } + for(MappingStrategyFactory strategyFactory : mapperFactory.getMappingStrategyFactories()) { + if(strategyFactory.isApplicable(strategyRecorder)) { + MappingStrategy resolvedStrategy = strategyFactory.build(strategyRecorder); + if (log.isDebugEnabled()) { + log.debug(strategyRecorder.describeDetails(resolvedStrategy)); + } + return resolvedStrategy; + } + } + if (log.isDebugEnabled()) { + log.debug(strategyRecorder.describeDetails(null)); + } + throw new MappingException("No mapping strategy found to satisfy requirements."); + } + public D map(final S sourceObject, final Type sourceType, final Type destinationType, final MappingContext context) { return map(sourceObject, sourceType, destinationType, context, null); } diff --git a/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/CopyByReferenceStrategy.java b/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/CopyByReferenceStrategy.java index 850a410a..c1c0bee5 100644 --- a/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/CopyByReferenceStrategy.java +++ b/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/CopyByReferenceStrategy.java @@ -20,6 +20,7 @@ import ma.glasnost.orika.MappingContext; import ma.glasnost.orika.MappingStrategy; +import ma.glasnost.orika.MappingStrategyFactory; import ma.glasnost.orika.metadata.Type; /** @@ -69,4 +70,15 @@ public Type getAType() { public Type getBType() { return null; } + + public static class CopyByReferenceStrategyFactory implements MappingStrategyFactory { + + public boolean isApplicable(MappingStrategyRecorder data) { + return data.isCopyByReference(); + } + + public MappingStrategy build(MappingStrategyRecorder data) { + return CopyByReferenceStrategy.getInstance(); + } + } } diff --git a/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/InstantiateAndUseCustomMapperStrategy.java b/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/InstantiateAndUseCustomMapperStrategy.java index 115c5b37..036c7586 100644 --- a/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/InstantiateAndUseCustomMapperStrategy.java +++ b/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/InstantiateAndUseCustomMapperStrategy.java @@ -20,9 +20,8 @@ import java.util.Map; -import ma.glasnost.orika.Mapper; -import ma.glasnost.orika.MappingContext; -import ma.glasnost.orika.ObjectFactory; +import ma.glasnost.orika.*; +import ma.glasnost.orika.impl.ReversedMapper; import ma.glasnost.orika.metadata.Type; import ma.glasnost.orika.unenhance.UnenhanceStrategy; @@ -60,4 +59,23 @@ protected void describeMembers(Map members) { super.describeMembers(members); members.put("objectFactory", objectFactory); } + + public static class InstantiateAndUseCustomMapperStrategyFactory implements MappingStrategyFactory { + + public boolean isApplicable(MappingStrategyRecorder data) { + return data.getResolvedObjectFactory() != null; + } + + public MappingStrategy build(MappingStrategyRecorder data) { + Mapper resolvedMapper = data.getResolvedMapper(); + if(data.isMapReverse()) { + resolvedMapper = ReversedMapper.reverse(resolvedMapper); + } + return new InstantiateAndUseCustomMapperStrategy((Type) data.getResolvedSourceType(), + (Type) data.getResolvedDestinationType(), + resolvedMapper, + data.getResolvedObjectFactory(), + data.getUnenhanceStrategy()); + } + } } diff --git a/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/MapExistingAndUseCustomMapperStrategy.java b/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/MapExistingAndUseCustomMapperStrategy.java index fd2ec383..8a1d4f0c 100644 --- a/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/MapExistingAndUseCustomMapperStrategy.java +++ b/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/MapExistingAndUseCustomMapperStrategy.java @@ -20,6 +20,9 @@ import ma.glasnost.orika.Mapper; import ma.glasnost.orika.MappingContext; +import ma.glasnost.orika.MappingStrategy; +import ma.glasnost.orika.MappingStrategyFactory; +import ma.glasnost.orika.impl.ReversedMapper; import ma.glasnost.orika.metadata.Type; import ma.glasnost.orika.unenhance.UnenhanceStrategy; @@ -44,4 +47,22 @@ public MapExistingAndUseCustomMapperStrategy(Type sourceType, Type resolvedMapper = data.getResolvedMapper(); + if(data.isMapReverse()) { + resolvedMapper = ReversedMapper.reverse(resolvedMapper); + } + return new MapExistingAndUseCustomMapperStrategy((Type) data.getResolvedSourceType(), + (Type) data.getResolvedDestinationType(), + data.getResolvedMapper(), + data.getUnenhanceStrategy()); + } + } } diff --git a/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/MappingStrategyRecorder.java b/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/MappingStrategyRecorder.java index ca81ea35..1483358c 100644 --- a/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/MappingStrategyRecorder.java +++ b/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/MappingStrategyRecorder.java @@ -48,7 +48,6 @@ public class MappingStrategyRecorder { private Converter resolvedConverter; private Type resolvedSourceType; private Type resolvedDestinationType; - private MappingStrategy resolvedStrategy; private final UnenhanceStrategy unenhanceStrategy; private final Key key; @@ -192,35 +191,12 @@ public ObjectFactory getResolvedObjectFactory() { public void setResolvedObjectFactory(final ObjectFactory resolvedObjectFactory) { this.resolvedObjectFactory = (ObjectFactory) resolvedObjectFactory; } - - /** - * @return a new instance of the MappingStrategy which can "playback" the - * route taken to map a given set of inputs. - */ - public synchronized MappingStrategy playback() { - - UnenhanceStrategy unenhanceStrategy; - unenhanceStrategy = this.unenhanceStrategy; - - if (copyByReference) { - resolvedStrategy = CopyByReferenceStrategy.getInstance(); - } else if (resolvedConverter != null) { - resolvedStrategy = new UseConverterStrategy(resolvedSourceType, resolvedDestinationType, resolvedConverter, unenhanceStrategy); - } else { - - if (mapReverse) { - resolvedMapper = ReversedMapper.reverse(resolvedMapper); - } - if (resolvedObjectFactory != null) { - resolvedStrategy = new InstantiateAndUseCustomMapperStrategy(resolvedSourceType, resolvedDestinationType, resolvedMapper, - resolvedObjectFactory, unenhanceStrategy); - } else { - resolvedStrategy = new MapExistingAndUseCustomMapperStrategy(resolvedSourceType, resolvedDestinationType, resolvedMapper, - unenhanceStrategy); - } - - } - return resolvedStrategy; + + /** + * @return The unenhance strategy to use for the mapper strategy + */ + public UnenhanceStrategy getUnenhanceStrategy() { + return unenhanceStrategy; } /** @@ -229,16 +205,13 @@ public synchronized MappingStrategy playback() { * * @return a String description of this strategy suitable for logging */ - public String describeDetails() { - if (resolvedStrategy == null) { - throw new IllegalStateException("Strategy recording not complete"); - } + public String describeDetails(MappingStrategy resolvedStrategy) { StringBuilder details = new StringBuilder(); details.append("MappingStrategy resolved and cached:") .append("\n\tInputs:[ sourceClass: " + key.getRawSourceType().getCanonicalName()) .append(", sourceType: " + key.getSourceType()) .append(", destinationType: " + key.getDestinationType()) - .append("]\n\tResolved:[ strategy: " + resolvedStrategy.getClass().getSimpleName()) + .append("]\n\tResolved:[ strategy: " + getStrategyName(resolvedStrategy)) .append(", sourceType: " + getResolvedSourceType()) .append(", destinationType: " + getResolvedDestinationType()); if (isCopyByReference()) { @@ -257,6 +230,13 @@ public String describeDetails() { return details.toString(); } + + private String getStrategyName(MappingStrategy strategy) { + if(strategy == null) { + return "NONE"; + } + return strategy.getClass().getSimpleName(); + } static class NoOpUnenhancer implements UnenhanceStrategy { diff --git a/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/UseConverterStrategy.java b/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/UseConverterStrategy.java index 3437acf1..15ab97a9 100644 --- a/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/UseConverterStrategy.java +++ b/core/src/main/java/ma/glasnost/orika/impl/mapping/strategy/UseConverterStrategy.java @@ -22,6 +22,8 @@ import ma.glasnost.orika.Converter; import ma.glasnost.orika.MappingContext; +import ma.glasnost.orika.MappingStrategy; +import ma.glasnost.orika.MappingStrategyFactory; import ma.glasnost.orika.metadata.Type; import ma.glasnost.orika.unenhance.UnenhanceStrategy; @@ -64,4 +66,18 @@ protected void describeMembers(Map members) { members.put("converter", converter); members.put("unenhancer", unenhancer); } + + public static class UseConverterStrategyFactory implements MappingStrategyFactory { + + public boolean isApplicable(MappingStrategyRecorder data) { + return data.getResolvedConverter() != null; + } + + public MappingStrategy build(MappingStrategyRecorder data) { + return new UseConverterStrategy((Type) data.getResolvedSourceType(), + (Type) data.getResolvedDestinationType(), + data.getResolvedConverter(), + data.getUnenhanceStrategy()); + } + } }