Repository: orika-mapper/orika
Pull request #352 (2020-06-27 10:40:02)

BoundStrategyCache race condition fix
When several concurrent threads are trying to set `defaultStrategy` in `BoundStrategyCache` one of the threads may end up with wrong strategy. In that case the mapper will throw exception which will look something like this:

```
Caused by: ma.glasnost.orika.MappingException: While attempting the following mapping:
sourceClass = class ma.glasnost.orika.test.concurrency.model.NestedModel
sourceType = ma.glasnost.orika.test.concurrency.model.NestedModel
destinationType = ma.glasnost.orika.test.concurrency.model.NestedModel
resolvedStrategy = InstantiateAndUseCustomMapperStrategy<NestedModel, NestedModel> {customMapper: GeneratedMapper<NestedModel, NestedModel> {usedConverters: [], usedMappers: [], usedMapperFacades: [DefaultBoundMapperFacade<Object, Object>], usedTypes: [] }, unenhancer: ma.glasnost.orika.unenhance.BaseUnenhancer@101df177, objectFactory: ma.glasnost.orika.test.concurrency.model.NestedModel_NestedModel_ObjectFactory148371931701133148372477829116$2@166fa74d}
Error occurred: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
	at ma.glasnost.orika.impl.ExceptionUtility.newMappingException(ExceptionUtility.java:55)
	at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:264)
	at ma.glasnost.orika.impl.MapperFacadeImpl.mapElement(MapperFacadeImpl.java:799)
	at ma.glasnost.orika.impl.MapperFacadeImpl.mapAsCollection(MapperFacadeImpl.java:622)
	at ma.glasnost.orika.impl.MapperFacadeImpl.mapAsList(MapperFacadeImpl.java:428)
	at ma.glasnost.orika.generated.Orika_ModelWithNestedObjDest_ModelWithNestedObjSource_Mapper148372220603916$0.mapAtoB(Orika_ModelWithNestedObjDest_ModelWithNestedObjSource_Mapper148372220603916$0.java)
	at ma.glasnost.orika.impl.mapping.strategy.UseCustomMapperStrategy.map(UseCustomMapperStrategy.java:77)
	at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:672)
	at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:651)
	at ma.glasnost.orika.test.concurrency.DefaultBoundMapperFacadeConcurrentInitTestCase.lambda$1(DefaultBoundMapperFacadeConcurrentInitTestCase.java:70)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
	at ma.glasnost.orika.generated.Orika_Object_Integer_Mapper148372500018464$3.mapAtoB(Orika_Object_Integer_Mapper148372500018464$3.java)
	at ma.glasnost.orika.impl.mapping.strategy.UseCustomMapperStrategy.map(UseCustomMapperStrategy.java:77)
	at ma.glasnost.orika.impl.DefaultBoundMapperFacade.map(DefaultBoundMapperFacade.java:167)
	at ma.glasnost.orika.generated.Orika_NestedModel_NestedModel_Mapper148372460398666$1.mapAtoB(Orika_NestedModel_NestedModel_Mapper148372460398666$1.java)
	at ma.glasnost.orika.impl.mapping.strategy.UseCustomMapperStrategy.map(UseCustomMapperStrategy.java:77)
	at ma.glasnost.orika.impl.MapperFacadeImpl.map(MapperFacadeImpl.java:253)
	... 13 more
```


Patch:
diff --git a/.travis.yml b/.travis.yml
index bffedbed..53d199f8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,9 @@
 sudo: false
 language: java
 jdk:
-  - openjdk8
-  - openjdk9
-  - openjdk11
+  - oraclejdk8
+  - oraclejdk9
+  - oraclejdk11
 branches:
   only:
     - master
@@ -15,6 +15,3 @@ notifications:
   email:
     on_success: always
     on_failure: always
-cache:
-  directories:
-    - $HOME/.m2
diff --git a/core/src/main/java/ma/glasnost/orika/OrikaSystemProperties.java b/core/src/main/java/ma/glasnost/orika/OrikaSystemProperties.java
index b5740073..6c07aea1 100644
--- a/core/src/main/java/ma/glasnost/orika/OrikaSystemProperties.java
+++ b/core/src/main/java/ma/glasnost/orika/OrikaSystemProperties.java
@@ -171,10 +171,4 @@ public final class OrikaSystemProperties {
      * Default value is <code>false</code>
      */
     public static final String CAPTURE_FIELD_CONTEXT = "ma.glasnost.orika.captureFieldContext";
-
-    /**
-     * Specifies whether destination properies' values will be retrieved on mappings or not.
-     * default value is <code>true</code>
-     */
-    public static final String GET_DESTINATION_ON_MAPPING = "ma.glasnost.orika.getDestinationOnMapping";
 }
diff --git a/core/src/main/java/ma/glasnost/orika/Properties.java b/core/src/main/java/ma/glasnost/orika/Properties.java
index 841fdd93..52269397 100644
--- a/core/src/main/java/ma/glasnost/orika/Properties.java
+++ b/core/src/main/java/ma/glasnost/orika/Properties.java
@@ -30,6 +30,5 @@ public enum Properties {
     COMPILER_STRATEGY,
     UNENHANCE_STRATEGY,
     FILTERS,
-    CAPTURE_FIELD_CONTEXT,
-    SHOULD_GET_DESTINATION_ON_MAPPING
+    CAPTURE_FIELD_CONTEXT
 }
diff --git a/core/src/main/java/ma/glasnost/orika/constructor/SimpleConstructorResolverStrategy.java b/core/src/main/java/ma/glasnost/orika/constructor/SimpleConstructorResolverStrategy.java
index aedd4e76..5f79a8b7 100644
--- a/core/src/main/java/ma/glasnost/orika/constructor/SimpleConstructorResolverStrategy.java
+++ b/core/src/main/java/ma/glasnost/orika/constructor/SimpleConstructorResolverStrategy.java
@@ -237,6 +237,6 @@ public class SimpleConstructorResolverStrategy implements ConstructorResolverStr
                 .build();
         return new FieldMap(existing.getSource(), destProp, null,
                 null, MappingDirection.A_TO_B, false, existing.getConverterId(),
-                byDefault, null, null, null);
+                byDefault, null, null);
     }
 }
diff --git a/core/src/main/java/ma/glasnost/orika/impl/DefaultBoundMapperFacade.java b/core/src/main/java/ma/glasnost/orika/impl/DefaultBoundMapperFacade.java
index c7c29936..4ffad481 100644
--- a/core/src/main/java/ma/glasnost/orika/impl/DefaultBoundMapperFacade.java
+++ b/core/src/main/java/ma/glasnost/orika/impl/DefaultBoundMapperFacade.java
@@ -251,23 +251,20 @@ class DefaultBoundMapperFacade<A, B> implements BoundMapperFacade<A, B> {
         public MappingStrategy getStrategy(Object sourceObject, MappingContext context) {
             MappingStrategy strategy = null;
             Class<?> sourceClass = getClass(sourceObject);
-            if (defaultStrategy != null && sourceClass.equals(idClass)) {
-                strategy = defaultStrategy;
-            } else if (defaultStrategy == null) {
+            if (defaultStrategy == null) {
                 synchronized(this) {
                     if (defaultStrategy == null) {
                         defaultStrategy = mapperFacade.resolveMappingStrategy(sourceObject, aType, bType, inPlace, context);
                         idClass = sourceClass;
                         strategies.put(idClass, defaultStrategy);
                     }
-                }
+                } 
+            }
+            if (sourceClass.equals(idClass)) {
                 strategy = defaultStrategy;
             } else {
-                strategy = strategies.get(sourceClass);
-                if (strategy == null) {
-                    strategy = mapperFacade.resolveMappingStrategy(sourceObject, aType, bType, inPlace, context);
-                    strategies.put(sourceClass, strategy);
-                }
+                strategy = strategies.computeIfAbsent(sourceClass, 
+                        k -> mapperFacade.resolveMappingStrategy(sourceObject, aType, bType, inPlace, context));
             }
             
             /*
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 39d69f29..e66e7cbc 100644
--- a/core/src/main/java/ma/glasnost/orika/impl/DefaultMapperFactory.java
+++ b/core/src/main/java/ma/glasnost/orika/impl/DefaultMapperFactory.java
@@ -155,9 +155,7 @@ public class DefaultMapperFactory implements MapperFactory, Reportable {
         props.put(Properties.MAPPER_FACTORY, this);
         props.put(Properties.FILTERS, this.filtersRegistry);
         props.put(Properties.CAPTURE_FIELD_CONTEXT, builder.captureFieldContext);
-        props.put(Properties.SHOULD_GET_DESTINATION_ON_MAPPING, builder.getDestinationOnMapping);
-
-
+        
         /*
          * Register default concrete types for common collection types; these
          * can be overridden as needed by user code.
@@ -275,19 +273,7 @@ public class DefaultMapperFactory implements MapperFactory, Reportable {
          * But for Testing the MultipleMapperWrapper should be use in one TestSuite for all TestCase to test as much scenarios as possible.
          */
         protected boolean alwaysCreateMultipleMapperWrapper;
-        /**
-         * The configured value of whether or not to retrieve destination property value on mapping;
-         * if false, it will be assumed that the value of the destination property is always null;
-         * if true, the real value of the destination property will be used.
-         * <p>
-         * Sometimes it may be useful to set this value to false. For example, in case when you don't need to know
-         * current destination value and you want to map the value from source to distination regardless of the current
-         * destination value. Also, it may be useful if your logic to retrieve a destination value is too expensive or
-         * produces exceptions if the destination value isn't specified yet.
-         * <p>
-         */
-        protected Boolean getDestinationOnMapping;
-
+        
         /**
          * Instantiates a new MapperFactoryBuilder
          */
@@ -308,7 +294,6 @@ public class DefaultMapperFactory implements MapperFactory, Reportable {
             alwaysCreateMultipleMapperWrapper = valueOf(
                     getProperty("ma.glasnost.orika.alwaysCreateMultipleMapperWrapper", "false"));
             codeGenerationStrategy = new DefaultCodeGenerationStrategy();
-            getDestinationOnMapping = valueOf(getProperty(GET_DESTINATION_ON_MAPPING, "true"));
         }
         
         /**
@@ -471,7 +456,7 @@ public class DefaultMapperFactory implements MapperFactory, Reportable {
             this.mapNulls = mapNulls;
             return self();
         }
-
+        
         /**
          * Configure whether to dump the current state of the mapping
          * infrastructure objects upon occurrence of an exception while mapping.
@@ -547,18 +532,7 @@ public class DefaultMapperFactory implements MapperFactory, Reportable {
             this.codeGenerationStrategy  = codeGenerationStrategy ;
             return self();
         }
-
-        /**
-         * Configure whether to retrieve distination property value during mapping in generated mapper code
-         *
-         * @param getDestinationOnMapping
-         * @return a reference to <code>this</code> MapperFactoryBuilder
-         */
-        public B getDestinationOnMapping(boolean getDestinationOnMapping) {
-            this.getDestinationOnMapping = getDestinationOnMapping;
-            return self();
-        }
-
+        
         /**
          * @return a new instance of the Factory for which this builder is
          *         defined. The construction should be performed via the
diff --git a/core/src/main/java/ma/glasnost/orika/impl/generator/SourceCodeContext.java b/core/src/main/java/ma/glasnost/orika/impl/generator/SourceCodeContext.java
index d3486f79..02e17758 100644
--- a/core/src/main/java/ma/glasnost/orika/impl/generator/SourceCodeContext.java
+++ b/core/src/main/java/ma/glasnost/orika/impl/generator/SourceCodeContext.java
@@ -178,15 +178,11 @@ public class SourceCodeContext {
     List<String> getMethods() {
         return methods;
     }
-
+    
     public boolean shouldMapNulls() {
         return (Boolean) mappingContext.getProperty(Properties.SHOULD_MAP_NULLS);
     }
-
-    public boolean shouldGetDestinationOnMapping() {
-        return (Boolean) mappingContext.getProperty(Properties.SHOULD_GET_DESTINATION_ON_MAPPING);
-    }
-
+    
     public MappingContext getMappingContext() {
         return mappingContext;
     }
@@ -749,14 +745,12 @@ public class SourceCodeContext {
 
             Converter<Object, Object> converter = getConverter(fieldMap, fieldMap.getConverterId());
             source.setConverter(converter);
-
-            boolean getDestinationOnMapping = AbstractSpecification.shouldGetDestinationOnMapping(fieldMap, this);
-
+            
             if (shouldCaptureFieldContext) {
-                beginCaptureFieldContext(out, fieldMap, source, destination, getDestinationOnMapping);
+                beginCaptureFieldContext(out, fieldMap, source, destination);
             }
             StringBuilder filterClosing = new StringBuilder();
-            VariableRef[] filteredProperties = applyFilters(source, destination, out, filterClosing, getDestinationOnMapping);
+            VariableRef[] filteredProperties = applyFilters(source, destination, out, filterClosing);
             source = filteredProperties[0];
             destination = filteredProperties[1];
             
@@ -780,11 +774,11 @@ public class SourceCodeContext {
         }
         return out.toString();
     }
-
-    private void beginCaptureFieldContext(StringBuilder out, FieldMap fieldMap, VariableRef source, VariableRef dest, boolean getDestinationValueOnMapping) {
+    
+    private void beginCaptureFieldContext(StringBuilder out, FieldMap fieldMap, VariableRef source, VariableRef dest) {
         out.append(format("mappingContext.beginMappingField(\"%s\", %s, %s, \"%s\", %s, %s);\n" + "try{\n",
                 escapeQuotes(fieldMap.getSource().getExpression()), usedType(fieldMap.getAType()), source.asWrapper(),
-                escapeQuotes(fieldMap.getDestination().getExpression()), usedType(fieldMap.getBType()), (getDestinationValueOnMapping)?dest.asWrapper():"null"));
+                escapeQuotes(fieldMap.getDestination().getExpression()), usedType(fieldMap.getBType()), dest.asWrapper()));
     }
     
     private void endCaptureFieldContext(StringBuilder out) {
@@ -795,7 +789,7 @@ public class SourceCodeContext {
         return string.replaceAll("(?<!\\\\)\"", "\\\\\"");
     }
     
-    public VariableRef[] applyFilters(VariableRef sourceProperty, VariableRef destinationProperty, StringBuilder out, StringBuilder closing, boolean getDestinationOnMapping) {
+    public VariableRef[] applyFilters(VariableRef sourceProperty, VariableRef destinationProperty, StringBuilder out, StringBuilder closing) {
         /*
          * TODO: need code which collects all of the applicable filters and adds
          * them into an aggregate filter object
@@ -806,7 +800,7 @@ public class SourceCodeContext {
                 out.append("if (");
                 out.append(format("(%s && %s.shouldMap(%s, \"%s\", %s, %s, \"%s\", %s, mappingContext))", destinationProperty.pathNotNull(),
                     usedFilter(filter), usedType(sourceProperty.type()), varPath(sourceProperty), sourceProperty.asWrapper(),
-                    usedType(destinationProperty.type()), varPath(destinationProperty), (getDestinationOnMapping)?destinationProperty.asWrapper():"null"));
+                    usedType(destinationProperty.type()), varPath(destinationProperty), destinationProperty.asWrapper()));
 
                 out.append(" || ");
 
@@ -818,7 +812,7 @@ public class SourceCodeContext {
             } else {
                 out.append(format("if (%s.shouldMap(%s, \"%s\", %s, %s, \"%s\", %s, mappingContext)) {", usedFilter(filter),
                     usedType(sourceProperty.type()), varPath(sourceProperty), sourceProperty.asWrapper(),
-                    usedType(destinationProperty.type()), varPath(destinationProperty), (getDestinationOnMapping)?destinationProperty.asWrapper():"null"));
+                    usedType(destinationProperty.type()), varPath(destinationProperty), destinationProperty.asWrapper()));
             }
 
             sourceProperty = getSourceFilter(sourceProperty, destinationProperty, filter);
diff --git a/core/src/main/java/ma/glasnost/orika/impl/generator/specification/AbstractSpecification.java b/core/src/main/java/ma/glasnost/orika/impl/generator/specification/AbstractSpecification.java
index 51cafec7..d04ca587 100644
--- a/core/src/main/java/ma/glasnost/orika/impl/generator/specification/AbstractSpecification.java
+++ b/core/src/main/java/ma/glasnost/orika/impl/generator/specification/AbstractSpecification.java
@@ -53,22 +53,7 @@ public abstract class AbstractSpecification implements Specification {
         }
         return mapNull;
     }
-
-    /**
-     * Tests whether this fieldMap should get destination property value on mapping;
-     *
-     * @param fieldMap
-     * @param context
-     * @return true if destination should be retrieved, otherwise false.
-     */
-    public static boolean shouldGetDestinationOnMapping(FieldMap fieldMap, SourceCodeContext context) {
-        Boolean getDestinationOnMapping = fieldMap.isDestinationValueRetrievedOnMapping();
-        if (getDestinationOnMapping == null) {
-            getDestinationOnMapping = context.shouldGetDestinationOnMapping();
-        }
-        return getDestinationOnMapping;
-    }
-
+    
     public abstract boolean appliesTo(FieldMap fieldMap);
     
     public String generateEqualityTestCode(FieldMap fieldMap, VariableRef source, VariableRef destination, SourceCodeContext code) {
diff --git a/core/src/main/java/ma/glasnost/orika/impl/generator/specification/Convert.java b/core/src/main/java/ma/glasnost/orika/impl/generator/specification/Convert.java
index 0a07956a..9722eace 100644
--- a/core/src/main/java/ma/glasnost/orika/impl/generator/specification/Convert.java
+++ b/core/src/main/java/ma/glasnost/orika/impl/generator/specification/Convert.java
@@ -54,7 +54,7 @@ public class Convert extends AbstractSpecification {
             if (destination.type().isPrimitive() && source.type().isPrimitive()) {
                 return format("(%s == %s)", destination, source);
             } else if (destination.type().isPrimitive()) {
-                return format("(%s != null && %s == %s.%sValue())", source, destination, source, destination.type().getName());
+                return format("(%s != null && %s == %s.%sValue())", source, destination, source, source.type().getName());
             } else if (source.type().isPrimitive()) {
                 return format("(%s != null && %s.%sValue() == %s)", destination, destination, destination.type()
                         .getPrimitiveType()
diff --git a/core/src/main/java/ma/glasnost/orika/impl/generator/specification/MultiOccurrenceToMultiOccurrence.java b/core/src/main/java/ma/glasnost/orika/impl/generator/specification/MultiOccurrenceToMultiOccurrence.java
index c6225b7b..0df1bc72 100644
--- a/core/src/main/java/ma/glasnost/orika/impl/generator/specification/MultiOccurrenceToMultiOccurrence.java
+++ b/core/src/main/java/ma/glasnost/orika/impl/generator/specification/MultiOccurrenceToMultiOccurrence.java
@@ -260,16 +260,14 @@ public class MultiOccurrenceToMultiOccurrence implements AggregateSpecification
                 } else {
                     VariableRef s = makeVariable(srcNode.property, srcNode, "source");
                     VariableRef d = makeVariable(currentNode.property, currentNode, "destination");
-
-                    boolean getDestinationOnMapping = AbstractSpecification.shouldGetDestinationOnMapping(currentNode.getMap(), code);
-                    code.applyFilters(s, d, out, endWhiles, getDestinationOnMapping);
+                    code.applyFilters(s, d, out, endWhiles);
 
                     d = currentNode.isRoot() ? currentNode.newDestination : currentNode.multiOccurrenceVar;
                     out.append(format("\nmappingContext.beginMapping(%s, %s, %s, %s);\n",
                                 code.usedType(s.type()),
                                 s.asWrapper(),
                                 code.usedType(d.type()),
-                                (getDestinationOnMapping)?d.asWrapper():"null"));
+                                d.asWrapper()));
                     out.append("try {\n");
                     endWhiles.insert(0, "\n} finally {\n  mappingContext.endMapping();\n}\n");
                 }
diff --git a/core/src/main/java/ma/glasnost/orika/metadata/ClassMapBuilder.java b/core/src/main/java/ma/glasnost/orika/metadata/ClassMapBuilder.java
index f0708993..eac1526b 100644
--- a/core/src/main/java/ma/glasnost/orika/metadata/ClassMapBuilder.java
+++ b/core/src/main/java/ma/glasnost/orika/metadata/ClassMapBuilder.java
@@ -89,8 +89,7 @@ public class ClassMapBuilder<A, B> implements MappedTypePair<A, B> {
     private Boolean sourcesMappedOnNull;
     private Boolean destinationsMappedOnNull;
     private Boolean favorsExtension;
-    private Boolean destinationValueRetrievedOnMapping;
-
+    
     private static final Logger LOGGER = LoggerFactory.getLogger(ClassMapBuilder.class);
     
     /**
@@ -327,7 +326,7 @@ public class ClassMapBuilder<A, B> implements MappedTypePair<A, B> {
         
         try {
             final FieldMapBuilder<A, B> fieldMapBuilder = new FieldMapBuilder<A, B>(this, fieldNameA, fieldNameB, byDefault,
-                    sourcesMappedOnNull, destinationsMappedOnNull, destinationValueRetrievedOnMapping);
+                    sourcesMappedOnNull, destinationsMappedOnNull);
             
             return fieldMapBuilder;
         } catch (MappingException e) {
@@ -349,7 +348,7 @@ public class ClassMapBuilder<A, B> implements MappedTypePair<A, B> {
      * @return
      */
     public FieldMapBuilder<A, B> fieldMap(Property fieldA, Property fieldB, boolean byDefault) {
-        return new FieldMapBuilder<A, B>(this, fieldA, fieldB, byDefault, sourcesMappedOnNull, destinationsMappedOnNull, destinationValueRetrievedOnMapping);
+        return new FieldMapBuilder<A, B>(this, fieldA, fieldB, byDefault, sourcesMappedOnNull, destinationsMappedOnNull);
     }
     
     /**
@@ -362,7 +361,7 @@ public class ClassMapBuilder<A, B> implements MappedTypePair<A, B> {
      */
     public FieldMapBuilder<A, B> fieldMap(String fieldNameA, Property fieldB, boolean byDefault) {
         return new FieldMapBuilder<A, B>(this, resolvePropertyForA(fieldNameA), fieldB, byDefault, sourcesMappedOnNull,
-                destinationsMappedOnNull, destinationValueRetrievedOnMapping);
+                destinationsMappedOnNull);
     }
     
     /**
@@ -375,7 +374,7 @@ public class ClassMapBuilder<A, B> implements MappedTypePair<A, B> {
      */
     public FieldMapBuilder<A, B> fieldMap(Property fieldA, String fieldNameB, boolean byDefault) {
         return new FieldMapBuilder<A, B>(this, fieldA, resolvePropertyForB(fieldNameB), byDefault, sourcesMappedOnNull,
-                destinationsMappedOnNull, destinationValueRetrievedOnMapping);
+                destinationsMappedOnNull);
     }
     
     /**
@@ -388,7 +387,7 @@ public class ClassMapBuilder<A, B> implements MappedTypePair<A, B> {
      */
     public FieldMapBuilder<A, B> fieldMap(Property.Builder fieldA, Property.Builder fieldB, boolean byDefault) {
         return new FieldMapBuilder<A, B>(this, fieldA.build((PropertyResolver) propertyResolver),
-                fieldB.build((PropertyResolver) propertyResolver), byDefault, sourcesMappedOnNull, destinationsMappedOnNull, destinationValueRetrievedOnMapping);
+                fieldB.build((PropertyResolver) propertyResolver), byDefault, sourcesMappedOnNull, destinationsMappedOnNull);
     }
     
     /**
@@ -401,7 +400,7 @@ public class ClassMapBuilder<A, B> implements MappedTypePair<A, B> {
      */
     public FieldMapBuilder<A, B> fieldMap(String fieldNameA, Property.Builder fieldB, boolean byDefault) {
         return new FieldMapBuilder<A, B>(this, resolvePropertyForA(fieldNameA), fieldB.build((PropertyResolver) propertyResolver),
-                byDefault, sourcesMappedOnNull, destinationsMappedOnNull, destinationValueRetrievedOnMapping);
+                byDefault, sourcesMappedOnNull, destinationsMappedOnNull);
     }
     
     /**
@@ -414,7 +413,7 @@ public class ClassMapBuilder<A, B> implements MappedTypePair<A, B> {
      */
     public FieldMapBuilder<A, B> fieldMap(Property.Builder fieldA, String fieldNameB, boolean byDefault) {
         return new FieldMapBuilder<A, B>(this, fieldA.build((PropertyResolver) propertyResolver), resolvePropertyForB(fieldNameB),
-                byDefault, sourcesMappedOnNull, destinationsMappedOnNull, destinationValueRetrievedOnMapping);
+                byDefault, sourcesMappedOnNull, destinationsMappedOnNull);
     }
     
     /**
@@ -757,22 +756,7 @@ public class ClassMapBuilder<A, B> implements MappedTypePair<A, B> {
         
         return this;
     }
-
-    /**
-     * @param destinationValueRetrievedOnMapping
-     *            true|false to indicate whether the destination properties values of
-     *            this class map's fields should be retrieved on mapping (when mapping
-     *            in any direction). If false, it will be assumed that the  distination value
-     *            is always null. If true, a real destination value will be used.
-     *
-     * @return this FieldMapBuilder
-     */
-    public ClassMapBuilder<A, B> retrieveDestinationValueOnMapping(boolean destinationValueRetrievedOnMapping) {
-        this.destinationValueRetrievedOnMapping = destinationValueRetrievedOnMapping;
-
-        return this;
-    }
-
+    
     /**
      * Registers the ClassMap defined by this builder with it's initiating
      * MapperFactory
diff --git a/core/src/main/java/ma/glasnost/orika/metadata/FieldMap.java b/core/src/main/java/ma/glasnost/orika/metadata/FieldMap.java
index b54f78b1..4b66b298 100644
--- a/core/src/main/java/ma/glasnost/orika/metadata/FieldMap.java
+++ b/core/src/main/java/ma/glasnost/orika/metadata/FieldMap.java
@@ -35,10 +35,9 @@ public class FieldMap implements MappedTypePair<Object, Object> {
     private final String destinationExpression;
     private final Boolean sourceMappedOnNull;
     private final Boolean destinationMappedOnNull;
-    private final Boolean destinationValueRetrievedOnMapping;
     
     public FieldMap(Property a, Property b, Property aInverse, Property bInverse, MappingDirection mappingDirection, boolean excluded,
-            String converterId, boolean byDefault, Boolean sourceMappedOnNull, Boolean destinationMappedOnNull, Boolean destinationValueRetrievedOnMapping) {
+            String converterId, boolean byDefault, Boolean sourceMappedOnNull, Boolean destinationMappedOnNull) {
         this.source = a;
         this.destination = b;
         this.aInverse = aInverse;
@@ -49,7 +48,6 @@ public class FieldMap implements MappedTypePair<Object, Object> {
         this.byDefault = byDefault;
         this.sourceMappedOnNull = sourceMappedOnNull;
         this.destinationMappedOnNull = destinationMappedOnNull;
-        this.destinationValueRetrievedOnMapping = destinationValueRetrievedOnMapping;
         this.sourceExpression = this.source.getExpression();
         this.destinationExpression = this.destination.getExpression();
     }
@@ -57,7 +55,7 @@ public class FieldMap implements MappedTypePair<Object, Object> {
     public FieldMap copy() {
         
         return new FieldMap(copy(source), copy(destination), copy(aInverse), copy(bInverse), mappingDirection, excluded, converterId,
-                byDefault, sourceMappedOnNull, destinationMappedOnNull, destinationValueRetrievedOnMapping);
+                byDefault, sourceMappedOnNull, destinationMappedOnNull);
     }
     
     private Property copy(Property property) {
@@ -117,15 +115,7 @@ public class FieldMap implements MappedTypePair<Object, Object> {
     public Boolean isDestinationMappedOnNull() {
         return destinationMappedOnNull;
     }
-
-    /**
-     * @return destinationValueRetrievedOnMapping; can be null, which indicates no
-     *         preference and that the global value should be used.
-     */
-    public Boolean isDestinationValueRetrievedOnMapping() {
-        return destinationValueRetrievedOnMapping;
-    }
-
+    
     public Property getInverse() {
         return bInverse;
     }
@@ -136,7 +126,7 @@ public class FieldMap implements MappedTypePair<Object, Object> {
     
     public FieldMap flip() {
         return new FieldMap(destination, source, bInverse, aInverse, mappingDirection.flip(), excluded, converterId, byDefault,
-                destinationMappedOnNull, sourceMappedOnNull, destinationValueRetrievedOnMapping);
+                destinationMappedOnNull, sourceMappedOnNull);
     }
     
     public boolean is(Specification specification) {
diff --git a/core/src/main/java/ma/glasnost/orika/metadata/FieldMapBuilder.java b/core/src/main/java/ma/glasnost/orika/metadata/FieldMapBuilder.java
index d65d5b60..ec456674 100644
--- a/core/src/main/java/ma/glasnost/orika/metadata/FieldMapBuilder.java
+++ b/core/src/main/java/ma/glasnost/orika/metadata/FieldMapBuilder.java
@@ -54,14 +54,12 @@ public class FieldMapBuilder<A, B> {
     private Boolean sourceMappedOnNull;
     
     private Boolean destinationMappedOnNull;
-
-    private Boolean destinationValueRetrievedOnMapping;
     
     FieldMapBuilder(final ClassMapBuilder<A, B> classMapBuilder, final String a, final String b, final boolean byDefault,
-            final Boolean sourceMappedOnNull, final Boolean destinationMappedOnNull, final Boolean destinationValueRetrievedOnMapping) {
+            final Boolean sourceMappedOnNull, final Boolean destinationMappedOnNull) {
         
         this(classMapBuilder, a, b, classMapBuilder.getAType(), classMapBuilder.getBType(), byDefault, sourceMappedOnNull,
-                destinationMappedOnNull, destinationValueRetrievedOnMapping);
+                destinationMappedOnNull);
     }
     
     /**
@@ -75,10 +73,10 @@ public class FieldMapBuilder<A, B> {
      * @param bType
      */
     FieldMapBuilder(final ClassMapBuilder<A, B> classMapBuilder, final String a, final String b, final Type<?> aType, final Type<?> bType,
-            final boolean byDefault, final Boolean sourceMappedOnNull, final Boolean destinationMappedOnNull, final Boolean destinationValueRetrievedOnMapping) {
+            final boolean byDefault, final Boolean sourceMappedOnNull, final Boolean destinationMappedOnNull) {
         
         this(classMapBuilder, classMapBuilder.resolveProperty(aType, a), classMapBuilder.resolveProperty(bType, b), byDefault,
-                sourceMappedOnNull, destinationMappedOnNull, destinationValueRetrievedOnMapping);
+                sourceMappedOnNull, destinationMappedOnNull);
     }
     
     /**
@@ -94,14 +92,13 @@ public class FieldMapBuilder<A, B> {
      *            whether this FieldMapBuilder was generated by default or not
      */
     FieldMapBuilder(final ClassMapBuilder<A, B> classMapBuilder, final Property a, final Property b, final boolean byDefault,
-            final Boolean sourceMappedOnNull, final Boolean destinationMappedOnNull, final Boolean destinationValueRetrievedOnMapping) {
+            final Boolean sourceMappedOnNull, final Boolean destinationMappedOnNull) {
         this.classMapBuilder = classMapBuilder;
         this.byDefault = byDefault;
         this.aProperty = a;
         this.bProperty = b;
         this.sourceMappedOnNull = sourceMappedOnNull;
         this.destinationMappedOnNull = destinationMappedOnNull;
-        this.destinationValueRetrievedOnMapping = destinationValueRetrievedOnMapping;
     }
     
     /**
@@ -184,7 +181,7 @@ public class FieldMapBuilder<A, B> {
     
     private FieldMap toFieldMap() {
         return new FieldMap(aProperty, bProperty, aInverseProperty, bInverseProperty, mappingDirection, excluded, converterId, byDefault,
-                sourceMappedOnNull, destinationMappedOnNull, destinationValueRetrievedOnMapping);
+                sourceMappedOnNull, destinationMappedOnNull);
     }
     
     /**
@@ -312,7 +309,7 @@ public class FieldMapBuilder<A, B> {
         
         Property bProperty = aProperty.copy(bType);
         
-        return new FieldMap(aProperty, bProperty, null, null, MappingDirection.A_TO_B, false, null, false, null, null, null);
+        return new FieldMap(aProperty, bProperty, null, null, MappingDirection.A_TO_B, false, null, false, null, null);
     }
     
     /**
@@ -328,6 +325,6 @@ public class FieldMapBuilder<A, B> {
         
         Property bProperty = aProperty.copy(bType);
         
-        return new FieldMap(aProperty, bProperty, null, null, MappingDirection.A_TO_B, false, null, false, null, null, null);
+        return new FieldMap(aProperty, bProperty, null, null, MappingDirection.A_TO_B, false, null, false, null, null);
     }
 }
diff --git a/core/src/main/java/ma/glasnost/orika/metadata/TypeFactory.java b/core/src/main/java/ma/glasnost/orika/metadata/TypeFactory.java
index 9e60127f..a5b0da36 100644
--- a/core/src/main/java/ma/glasnost/orika/metadata/TypeFactory.java
+++ b/core/src/main/java/ma/glasnost/orika/metadata/TypeFactory.java
@@ -441,7 +441,7 @@ public abstract class TypeFactory {
         if (mapped != null) {
             typeResult = (Type<T>) mapped.get();
         }
-        if (mapped == null || typeResult == null) {
+        if (typeResult == null) {
             synchronized (rawType) {
                 mapped = typeCache.get(key);
                 if (mapped != null) {
diff --git a/eclipse-tools/pom.xml b/eclipse-tools/pom.xml
index 8a23375f..c9ea770a 100644
--- a/eclipse-tools/pom.xml
+++ b/eclipse-tools/pom.xml
@@ -42,12 +42,6 @@
 		    <groupId>org.eclipse.platform</groupId>
 		    <artifactId>org.eclipse.text</artifactId>
 		    <version>3.6.100</version>
-		    <exclusions>
-                        <exclusion>
-                            <groupId>org.eclipse.platform</groupId>
-                            <artifactId>org.eclipse.core.commands</artifactId>
-                        </exclusion>
-                    </exclusions>
 		</dependency>
 
 


Test patch:
diff --git a/tests/pom.xml b/tests/pom.xml
index 8ace10de..507f55fa 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -123,6 +123,11 @@
 			<artifactId>spring-orm</artifactId>
 			<scope>compile</scope>
 		</dependency>
+
+		<dependency>
+			<groupId>com.sun.xml.bind</groupId>
+			<artifactId>jaxb-impl</artifactId>
+		</dependency>
 		
 		<dependency>
 			<groupId>javax.xml.bind</groupId>
diff --git a/tests/src/main/java/ma/glasnost/orika/test/community/Issue322TestCase.java b/tests/src/main/java/ma/glasnost/orika/test/community/Issue322TestCase.java
deleted file mode 100644
index e02b26c3..00000000
--- a/tests/src/main/java/ma/glasnost/orika/test/community/Issue322TestCase.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package ma.glasnost.orika.test.community;
-
-import ma.glasnost.orika.MapperFactory;
-import ma.glasnost.orika.test.MappingUtil;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @see <a href="https://github.com/orika-mapper/orika/issues/322">https://github.com/orika-mapper/orika/issues/322</a>
- */
-public class Issue322TestCase {
-
-    @Test
-    public void compile_error_when_customized_list_element_mapping_int_to_integer() {
-        PersonList personList = new PersonList();
-        Person person = new Person();
-        person.age = 20;
-        personList.persons.add(person);
-
-        MapperFactory mapperFactory = MappingUtil.getMapperFactory();
-        mapperFactory.classMap(PersonList.class, PersonAgeListDto.class)
-                .field("persons{age}", "personAges{}")
-                .byDefault()
-                .register();
-
-        PersonAgeListDto dest = mapperFactory.getMapperFacade().map(personList, PersonAgeListDto.class);
-
-        assertEquals(1, dest.personAges.size());
-        assertEquals(Integer.valueOf(20), dest.personAges.get(0));
-    }
-
-    public static class Person {
-        public int age;
-    }
-
-    public static class PersonList {
-        public List<Person> persons = new ArrayList<>();
-    }
-
-    public static class PersonAgeListDto {
-        public List<Integer> personAges;
-    }
-}
diff --git a/tests/src/main/java/ma/glasnost/orika/test/concurrency/DefaultBoundMapperFacadeConcurrentInitTestCase.java b/tests/src/main/java/ma/glasnost/orika/test/concurrency/DefaultBoundMapperFacadeConcurrentInitTestCase.java
new file mode 100644
index 00000000..683c1336
--- /dev/null
+++ b/tests/src/main/java/ma/glasnost/orika/test/concurrency/DefaultBoundMapperFacadeConcurrentInitTestCase.java
@@ -0,0 +1,89 @@
+package ma.glasnost.orika.test.concurrency;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import com.google.common.collect.Lists;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import ma.glasnost.orika.MapperFacade;
+import ma.glasnost.orika.MapperFactory;
+import ma.glasnost.orika.test.MappingUtil;
+import ma.glasnost.orika.test.concurrency.model.ModelWithNestedObjDest;
+import ma.glasnost.orika.test.concurrency.model.ModelWithNestedObjSource;
+import ma.glasnost.orika.test.concurrency.model.NestedModel;
+
+/**
+ * Checks that instantiation and cache inside of <{@link ma.glasnost.orika.impl.DefaultBoundMapperFacade} is thread safe.
+ */
+public class DefaultBoundMapperFacadeConcurrentInitTestCase {
+
+    private MapperFacade mapper;
+
+    private int threads = 20;
+    private ExecutorService executor;
+
+    @Before
+    public void setup() {
+        MapperFactory factory = MappingUtil.getMapperFactory();
+        factory.classMap(ModelWithNestedObjSource.class, ModelWithNestedObjDest.class)
+            .byDefault()
+            .register();
+
+        mapper = factory.getMapperFacade();
+
+        executor = Executors.newFixedThreadPool(threads);
+    }
+
+    @After
+    public void cleanup() {
+        if (executor != null) {
+            executor.shutdownNow();
+        } 
+    }
+
+    @Test
+    public void testCase() {
+        CountDownLatch readyLatch = new CountDownLatch(threads);
+
+        List<Future<?>> futures = IntStream.range(0, threads).mapToObj(i -> 
+            executor.submit(() -> {
+                ModelWithNestedObjSource model = i % 2 == 0 
+                    ? new ModelWithNestedObjSource(Lists.newArrayList(new NestedModel("str")))
+                    : new ModelWithNestedObjSource(Lists.newArrayList(new NestedModel(1)));
+                
+                readyLatch.countDown();
+                try {
+                    if (readyLatch.await(1, TimeUnit.SECONDS)) {
+                        Assert.assertEquals(model.getValue(), mapper.map(model, ModelWithNestedObjDest.class).getValue());
+                    } else {
+                        throw new RuntimeException("Latch timeout");
+                    }
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            })
+        ).collect(Collectors.toList());
+
+        // check that no exception thrown inside futures
+        for (Future<?> future : futures) {
+            try {
+                future.get(1, TimeUnit.SECONDS);
+            } catch (InterruptedException | ExecutionException | TimeoutException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}
diff --git a/tests/src/main/java/ma/glasnost/orika/test/concurrency/model/ModelWithNestedObjDest.java b/tests/src/main/java/ma/glasnost/orika/test/concurrency/model/ModelWithNestedObjDest.java
new file mode 100644
index 00000000..7a9235ed
--- /dev/null
+++ b/tests/src/main/java/ma/glasnost/orika/test/concurrency/model/ModelWithNestedObjDest.java
@@ -0,0 +1,16 @@
+package ma.glasnost.orika.test.concurrency.model;
+
+import java.util.List;
+
+public class ModelWithNestedObjDest {
+
+    private List<NestedModel> value;
+
+    public List<NestedModel> getValue() {
+        return value;
+    }
+
+    public void setValue(List<NestedModel> value) {
+        this.value = value;
+    }
+}
diff --git a/tests/src/main/java/ma/glasnost/orika/test/concurrency/model/ModelWithNestedObjSource.java b/tests/src/main/java/ma/glasnost/orika/test/concurrency/model/ModelWithNestedObjSource.java
new file mode 100644
index 00000000..ba2dd671
--- /dev/null
+++ b/tests/src/main/java/ma/glasnost/orika/test/concurrency/model/ModelWithNestedObjSource.java
@@ -0,0 +1,20 @@
+package ma.glasnost.orika.test.concurrency.model;
+
+import java.util.List;
+
+public class ModelWithNestedObjSource {
+
+    private List<NestedModel> value;
+
+    public ModelWithNestedObjSource(List<NestedModel> value) {
+        this.value = value;
+    }
+
+    public List<NestedModel> getValue() {
+        return value;
+    }
+
+    public void setValue(List<NestedModel> value) {
+        this.value = value;
+    }
+}
diff --git a/tests/src/main/java/ma/glasnost/orika/test/concurrency/model/NestedModel.java b/tests/src/main/java/ma/glasnost/orika/test/concurrency/model/NestedModel.java
new file mode 100644
index 00000000..aab8a46f
--- /dev/null
+++ b/tests/src/main/java/ma/glasnost/orika/test/concurrency/model/NestedModel.java
@@ -0,0 +1,38 @@
+package ma.glasnost.orika.test.concurrency.model;
+
+import java.util.Objects;
+
+public class NestedModel {
+
+    private Object value;
+
+    public NestedModel(Object value) {
+        this.value = value;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(value);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        NestedModel other = (NestedModel) obj;
+        return Objects.equals(value, other.value);
+    }
+
+}
diff --git a/tests/src/main/java/ma/glasnost/orika/test/generator/RetrieveDestinationValueOnMappingTestCase.java b/tests/src/main/java/ma/glasnost/orika/test/generator/RetrieveDestinationValueOnMappingTestCase.java
deleted file mode 100644
index 5ef7ce82..00000000
--- a/tests/src/main/java/ma/glasnost/orika/test/generator/RetrieveDestinationValueOnMappingTestCase.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Orika - simpler, better and faster Java bean mapping
- *
- * Copyright (C) 2011-2019 Orika authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package ma.glasnost.orika.test.generator;
-
-import com.google.common.collect.ImmutableMap;
-import ma.glasnost.orika.MapperFactory;
-import ma.glasnost.orika.impl.DefaultMapperFactory;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-public class RetrieveDestinationValueOnMappingTestCase {
-
-    public static class Container1 {
-        private long longValue1;
-        private String stringValue1;
-        private List<String> listOfString1;
-        private String[] arrayOfString1;
-        private int[] arrayOfInt1;
-        private Map<String, Object> map1;
-        private MapNullsTestCase.Position enumValue1;
-
-        public long getLongValue() {
-            return longValue1;
-        }
-
-        public void setLongValue(long longValue) {
-            this.longValue1 = longValue;
-        }
-
-        public String getStringValue() {
-            return stringValue1;
-        }
-
-        public void setStringValue(String stringValue) {
-            this.stringValue1 = stringValue;
-        }
-
-        public List<String> getListOfString() {
-            return listOfString1;
-        }
-
-        public void setListOfString(List<String> listOfString) {
-            this.listOfString1 = listOfString;
-        }
-
-        public String[] getArrayOfString() {
-            return arrayOfString1;
-        }
-
-        public void setArrayOfString(String[] arrayOfString) {
-            this.arrayOfString1 = arrayOfString;
-        }
-
-        public int[] getArrayOfInt() {
-            return arrayOfInt1;
-        }
-
-        public void setArrayOfInt(int[] arrayOfInt) {
-            this.arrayOfInt1 = arrayOfInt;
-        }
-
-        public Map<String, Object> getMap() {
-            return map1;
-        }
-
-        public void setMap(Map<String, Object> map) {
-            this.map1 = map;
-        }
-
-        public MapNullsTestCase.Position getEnumValue() {
-            return enumValue1;
-        }
-
-        public void setEnumValue(MapNullsTestCase.Position enumValue) {
-            this.enumValue1 = enumValue;
-        }
-    }
-
-    public static class Container2 {
-        private long myLongValue;
-        private String myStringValue;
-        private List<String> myListOfString;
-        private String[] myArrayOfString;
-        private int[] myArrayOfInt;
-        private Map<String, Object> myMap;
-        private MapNullsTestCase.Position myEnumValue;
-        private Object myObject;
-
-        private boolean longSet, stringSet, listOfStringSet, arrayOfStringSet, arrayOfIntSet, mapSet, enumSet;
-
-        public long getLongValue() {
-            if(!longSet){
-                throw new RuntimeException();
-            }
-            return myLongValue;
-        }
-
-        public void setLongValue(long longValue) {
-            this.myLongValue = longValue;
-            longSet = true;
-        }
-
-        public String getStringValue() {
-            if(!stringSet){
-                throw new RuntimeException();
-            }
-            return myStringValue;
-        }
-
-        public void setStringValue(String stringValue) {
-            this.myStringValue = stringValue;
-            stringSet = true;
-        }
-
-        public List<String> getListOfString() {
-            if(!listOfStringSet){
-                throw new RuntimeException();
-            }
-            return myListOfString;
-        }
-
-        public void setListOfString(List<String> listOfString) {
-            this.myListOfString = listOfString;
-            listOfStringSet = true;
-        }
-
-        public String[] getArrayOfString() {
-            if(!arrayOfStringSet){
-                throw new RuntimeException();
-            }
-            return myArrayOfString;
-        }
-
-        public void setArrayOfString(String[] arrayOfString) {
-            this.myArrayOfString = arrayOfString;
-            arrayOfStringSet = true;
-        }
-
-        public int[] getArrayOfInt() {
-            if(!arrayOfIntSet){
-                throw new RuntimeException();
-            }
-            return myArrayOfInt;
-        }
-
-        public void setArrayOfInt(int[] arrayOfInt) {
-            this.myArrayOfInt = arrayOfInt;
-            arrayOfIntSet = true;
-        }
-
-        public Map<String, Object> getMap() {
-            if(!mapSet){
-                throw new RuntimeException();
-            }
-            return myMap;
-        }
-
-        public void setMap(Map<String, Object> map) {
-            this.myMap = map;
-            mapSet = true;
-        }
-
-        public MapNullsTestCase.Position getEnumValue() {
-            if(!enumSet){
-                throw new RuntimeException();
-            }
-            return myEnumValue;
-        }
-
-        public void setEnumValue(MapNullsTestCase.Position enumValue) {
-            this.myEnumValue = enumValue;
-            enumSet = true;
-        }
-
-        public Object getMyObject() {
-            return myObject;
-        }
-
-        public void setMyObject(Object myObject) {
-            this.myObject = myObject;
-        }
-    }
-
-    @Test
-    public void shouldMapWithDisabledRetrievalOfDestinationValueOnMapping(){
-
-        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().captureFieldContext(true)
-                .getDestinationOnMapping(false).build();
-        mapperFactory.classMap(Container1.class, Container2.class)
-                .mapNulls(true)
-                .mapNullsInReverse(true)
-                .byDefault()
-                .register();
-
-        Container1 container1 = buildContainer1();
-        Container2 container2 = new Container2();
-        Object myObject = new Object();
-        container2.setMyObject(myObject);
-        mapperFactory.getMapperFacade().map(container1, container2);
-
-        assertContainersEquals(container1, container2);
-        Assert.assertEquals(myObject, container2.getMyObject());
-    }
-
-    @Test(expected = RuntimeException.class)
-    public void shouldFailWithEnabledRetrievalOfDestinationValueOnMapping(){
-
-        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().captureFieldContext(true).build();
-        mapperFactory.classMap(Container1.class, Container2.class)
-                .mapNulls(true)
-                .mapNullsInReverse(true)
-                .byDefault()
-                .register();
-
-        Container1 container1 = buildContainer1();
-        Container2 container2 = new Container2();
-        Object myObject = new Object();
-        container2.setMyObject(myObject);
-
-        mapperFactory.getMapperFacade().map(container1, container2);
-    }
-
-    @Test
-    public void shouldMapWithEnabledRetrievalOfDestinationValueOnMapping(){
-
-        MapperFactory mapperFactory = new DefaultMapperFactory.Builder().captureFieldContext(true).build();
-        mapperFactory.classMap(Container1.class, Container2.class)
-                .mapNulls(true)
-                .mapNullsInReverse(true)
-                .byDefault()
-                .register();
-
-        Container1 container1 = buildContainer1();
-        Container2 container2 = buildContainer2();
-        Object myObject = new Object();
-        container2.setMyObject(myObject);
-
-        mapperFactory.getMapperFacade().map(container1, container2);
-
-        assertContainersEquals(container1, container2);
-        Assert.assertEquals(myObject, container2.getMyObject());
-    }
-
-    private void assertContainersEquals(Container1 container1, Container2 container2){
-
-        Assert.assertEquals(container1.getLongValue(), container2.getLongValue());
-        Assert.assertEquals(container1.getStringValue(), container2.getStringValue());
-        Assert.assertEquals(container1.getListOfString(), container2.getListOfString());
-        Assert.assertArrayEquals(container1.getArrayOfInt(), container2.getArrayOfInt());
-        Assert.assertArrayEquals(container1.getArrayOfString(), container2.getArrayOfString());
-        Assert.assertEquals(container1.getMap(), container2.getMap());
-        Assert.assertEquals(container1.getEnumValue(), container2.getEnumValue());
-    }
-
-    private Container1 buildContainer1(){
-
-        Container1 container1 = new Container1();
-
-        container1.longValue1 = 1L;
-        container1.stringValue1 = "TEST A";
-        container1.arrayOfString1 = new String[]{"a", "b", "c"};
-        container1.arrayOfInt1 = new int[] {1,2,3};
-        container1.listOfString1 = Arrays.asList("l1","l2");
-        container1.map1 = Collections.singletonMap("key1", "value1");
-        container1.enumValue1 = MapNullsTestCase.Position.FIRST;
-
-        return container1;
-    }
-
-    private Container2 buildContainer2(){
-
-        Container2 container2 = new Container2();
-
-        container2.setLongValue(0L);
-        container2.setStringValue("TEST B");
-        container2.setArrayOfString(new String[]{"d", "e"});
-        container2.setArrayOfInt(new int[] {4, 5});
-
-        container2.setListOfString(Arrays.asList("l3","l4","l5"));
-        container2.setMap(ImmutableMap.of("key2", "value2", "key3", 3));
-        container2.setEnumValue(MapNullsTestCase.Position.LAST);
-
-        return container2;
-    }
-}