From c69a56c138b54b8a7fd6a6c1ac53009f8c8a75f9 Mon Sep 17 00:00:00 2001
From: sjaakd
Date: Sat, 7 Feb 2015 20:03:01 +0100
Subject: [PATCH] #160 Using update method, basic behavior. Single mapping
methods on non collection / array properties.
---
.../java/org/mapstruct/ap/model/Direct.java | 6 +
.../ap/model/IterableMappingMethod.java | 3 +-
.../mapstruct/ap/model/MapMappingMethod.java | 6 +-
.../ap/model/MappingBuilderContext.java | 3 +-
.../mapstruct/ap/model/MethodReference.java | 8 +
.../mapstruct/ap/model/PropertyMapping.java | 52 ++++-
.../mapstruct/ap/model/TypeConversion.java | 6 +
.../ap/model/assignment/Assignment.java | 2 +
.../model/assignment/AssignmentWrapper.java | 5 +
.../ap/model/assignment/UpdateWrapper.java | 72 ++++++
.../selector/CreateOrUpdateSelector.java | 26 ++-
.../source/selector/SelectionCriteria.java | 14 +-
.../processor/MethodRetrievalProcessor.java | 30 ++-
.../creation/MappingResolverImpl.java | 14 +-
.../java/org/mapstruct/ap/util/Message.java | 2 +
...ruct.ap.model.assignment.UpdateWrapper.ftl | 44 ++++
.../ap/test/updatemethods/CompanyDto.java | 46 ++++
.../ap/test/updatemethods/CompanyEntity.java | 46 ++++
.../ap/test/updatemethods/CompanyMapper.java | 40 ++++
.../ap/test/updatemethods/DepartmentDto.java | 37 ++++
.../test/updatemethods/DepartmentEntity.java | 40 ++++
.../DepartmentEntityFactory.java | 32 +++
.../updatemethods/DepartmentInBetween.java | 37 ++++
.../ErroneousCompanyMapper1.java | 39 ++++
.../ErroneousOrganizationMapper1.java | 45 ++++
.../ErroneousOrganizationMapper2.java | 45 ++++
.../test/updatemethods/OrganizationDto.java | 37 ++++
.../updatemethods/OrganizationEntity.java | 55 +++++
.../updatemethods/OrganizationMapper.java | 51 +++++
.../updatemethods/OrganizationTypeEntity.java | 37 ++++
.../OrganizationTypeNrEntity.java | 37 ++++
...rganizationWithoutCompanyGetterEntity.java | 41 ++++
.../OrganizationWithoutTypeGetterEntity.java | 41 ++++
.../test/updatemethods/UpdateMethodsTest.java | 207 ++++++++++++++++++
.../selection/ExternalHandWrittenMapper.java | 38 ++++
.../selection/ExternalMapper.java | 38 ++++
.../selection/ExternalSelectionTest.java | 74 +++++++
.../selection/OrganizationMapper1.java | 39 ++++
.../selection/OrganizationMapper2.java | 39 ++++
39 files changed, 1410 insertions(+), 24 deletions(-)
create mode 100644 processor/src/main/java/org/mapstruct/ap/model/assignment/UpdateWrapper.java
create mode 100644 processor/src/main/resources/org.mapstruct.ap.model.assignment.UpdateWrapper.ftl
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyDto.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyEntity.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyMapper.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentDto.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentEntity.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentEntityFactory.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentInBetween.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousCompanyMapper1.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousOrganizationMapper1.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousOrganizationMapper2.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationDto.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationEntity.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationMapper.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationTypeEntity.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationTypeNrEntity.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationWithoutCompanyGetterEntity.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationWithoutTypeGetterEntity.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/UpdateMethodsTest.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalHandWrittenMapper.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalMapper.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalSelectionTest.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper1.java
create mode 100644 processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper2.java
diff --git a/processor/src/main/java/org/mapstruct/ap/model/Direct.java b/processor/src/main/java/org/mapstruct/ap/model/Direct.java
index dc19a10db..3b934b184 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/Direct.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/Direct.java
@@ -62,4 +62,10 @@ public class Direct extends ModelElement implements Assignment {
public AssignmentType getType() {
return AssignmentType.DIRECT;
}
+
+ @Override
+ public boolean isUpdateMethod() {
+ return false;
+ }
+
}
diff --git a/processor/src/main/java/org/mapstruct/ap/model/IterableMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/IterableMappingMethod.java
index a7af652b5..e836a5fd7 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/IterableMappingMethod.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/IterableMappingMethod.java
@@ -115,7 +115,8 @@ public class IterableMappingMethod extends MappingMethod {
dateFormat,
qualifiers,
qualifyingElementTargetType,
- loopVariableName
+ loopVariableName,
+ false
);
if ( assignment == null ) {
diff --git a/processor/src/main/java/org/mapstruct/ap/model/MapMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/MapMappingMethod.java
index de99183f9..494809c5d 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/MapMappingMethod.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/MapMappingMethod.java
@@ -125,7 +125,8 @@ public class MapMappingMethod extends MappingMethod {
keyDateFormat,
keyQualifiers,
keyQualifyingTargetType,
- "entry.getKey()"
+ "entry.getKey()",
+ false
);
if ( keyAssignment == null ) {
@@ -145,7 +146,8 @@ public class MapMappingMethod extends MappingMethod {
valueDateFormat,
valueQualifiers,
valueQualifyingTargetType,
- "entry.getValue()"
+ "entry.getValue()",
+ false
);
if ( valueAssignment == null ) {
diff --git a/processor/src/main/java/org/mapstruct/ap/model/MappingBuilderContext.java b/processor/src/main/java/org/mapstruct/ap/model/MappingBuilderContext.java
index cd9bf29af..61f424bc2 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/MappingBuilderContext.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/MappingBuilderContext.java
@@ -83,6 +83,7 @@ public class MappingBuilderContext {
* @param resultType used for further select the appropriate mapping method based on resultType (bean mapping)
* targetType (Iterable- and MapMapping)
* @param sourceReference call to source type as string
+ * @param preferUpdateMethods selection should prefer update methods when present.
*
* @return an assignment to a method parameter, which can either be:
*
@@ -94,7 +95,7 @@ public class MappingBuilderContext {
*/
Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type sourceType, Type targetType,
String targetPropertyName, String dateFormat, List qualifiers,
- TypeMirror resultType, String sourceReference);
+ TypeMirror resultType, String sourceReference, boolean preferUpdateMethods);
/**
* returns a no arg factory method
diff --git a/processor/src/main/java/org/mapstruct/ap/model/MethodReference.java b/processor/src/main/java/org/mapstruct/ap/model/MethodReference.java
index 6c1badbb4..3a72a100b 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/MethodReference.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/MethodReference.java
@@ -42,6 +42,7 @@ public class MethodReference extends MappingMethod implements Assignment {
private final MapperReference declaringMapper;
private final Set importTypes;
private final List exceptionTypes;
+ private final boolean isUpdateMethod;
/**
* In case this reference targets a built-in method, allows to pass specific context information to the invoked
@@ -78,6 +79,7 @@ public class MethodReference extends MappingMethod implements Assignment {
}
this.importTypes = Collections.unmodifiableSet( imported );
this.exceptionTypes = method.getThrownTypes();
+ this.isUpdateMethod = method.getMappingTargetParameter() != null;
}
public MethodReference(BuiltInMethod method, ConversionContext contextParam) {
@@ -86,6 +88,7 @@ public class MethodReference extends MappingMethod implements Assignment {
this.contextParam = method.getContextParameter( contextParam );
this.importTypes = Collections.emptySet();
this.exceptionTypes = Collections.emptyList();
+ this.isUpdateMethod = method.getMappingTargetParameter() != null;
}
public MapperReference getDeclaringMapper() {
@@ -159,4 +162,9 @@ public class MethodReference extends MappingMethod implements Assignment {
return null;
}
}
+
+ @Override
+ public boolean isUpdateMethod() {
+ return isUpdateMethod;
+ }
}
diff --git a/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java b/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java
index f1bd587e7..57ae69699 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java
@@ -35,6 +35,7 @@ import org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper;
import org.mapstruct.ap.model.assignment.NullCheckWrapper;
import org.mapstruct.ap.model.assignment.SetterWrapper;
import org.mapstruct.ap.model.assignment.SetterWrapperForCollectionsAndMaps;
+import org.mapstruct.ap.model.assignment.UpdateWrapper;
import org.mapstruct.ap.model.common.ModelElement;
import org.mapstruct.ap.model.common.Parameter;
import org.mapstruct.ap.model.common.Type;
@@ -163,6 +164,16 @@ public class PropertyMapping extends ModelElement {
sourceRefStr = getSourceRef();
}
+ // all the tricky cases will be excluded for the time being.
+ boolean preferUpdateMethods;
+ if ( targetType.isCollectionOrMapType() || targetType.isArrayType() ||
+ targetAccessorType == TargetWriteAccessorType.ADDER ) {
+ preferUpdateMethods = false;
+ }
+ else {
+ preferUpdateMethods = method.getMappingTargetParameter() != null;
+ }
+
Assignment assignment = ctx.getMappingResolver().getTargetAssignment(
method,
sourceElement,
@@ -172,7 +183,8 @@ public class PropertyMapping extends ModelElement {
dateFormat,
qualifiers,
resultType,
- sourceRefStr
+ sourceRefStr,
+ preferUpdateMethods
);
// No mapping found. Try to forge a mapping
@@ -198,6 +210,7 @@ public class PropertyMapping extends ModelElement {
else {
assignment = assignObject( sourceType, targetType, targetAccessorType, assignment );
}
+
}
else {
ctx.getMessager().printMessage(
@@ -228,8 +241,19 @@ public class PropertyMapping extends ModelElement {
Assignment result = rhs;
if ( targetAccessorType == TargetWriteAccessorType.SETTER ) {
-
- result = new SetterWrapper( result, method.getThrownTypes() );
+ if ( result.isUpdateMethod() ) {
+ if ( targetReadAccessor == null ) {
+ ctx.getMessager().printMessage( method.getExecutable(),
+ Message.PROPERTYMAPPING_NO_READ_ACCESSOR_FOR_TARGET_TYPE,
+ targetPropertyName );
+ }
+ Assignment factoryMethod =
+ ctx.getMappingResolver().getFactoryMethod( method, targetType, null, null );
+ result = new UpdateWrapper( result, method.getThrownTypes(), targetType, factoryMethod );
+ }
+ else {
+ result = new SetterWrapper( result, method.getThrownTypes() );
+ }
if ( !sourceType.isPrimitive()
&& !sourceReference.getPropertyEntries().isEmpty() /* parameter null taken care of by beanmapper */
&& ( result.getType() == TYPE_CONVERTED
@@ -575,17 +599,33 @@ public class PropertyMapping extends ModelElement {
dateFormat,
qualifiers,
resultType,
- constantExpression
+ constantExpression,
+ method.getMappingTargetParameter() != null
);
if ( assignment != null ) {
if ( Executables.isSetterMethod( targetWriteAccessor ) ) {
+
// target accessor is setter, so decorate assignment as setter
- assignment = new SetterWrapper( assignment, method.getThrownTypes() );
+ if ( assignment.isUpdateMethod() ) {
+ if ( targetReadAccessor == null ) {
+ ctx.getMessager().printMessage( method.getExecutable(),
+ Message.CONSTANTMAPPING_NO_READ_ACCESSOR_FOR_TARGET_TYPE,
+ targetPropertyName );
+ }
+ Assignment factoryMethod =
+ ctx.getMappingResolver().getFactoryMethod( method, targetType, null, null );
+ assignment =
+ new UpdateWrapper( assignment, method.getThrownTypes(), targetType, factoryMethod );
+ }
+ else {
+ assignment = new SetterWrapper( assignment, method.getThrownTypes() );
+ }
}
else {
- // wrap when dealing with getter only on target
+
+ // target accessor is getter, so getter map/ collection handling
assignment = new GetterWrapperForCollectionsAndMaps(
assignment,
method.getThrownTypes(),
diff --git a/processor/src/main/java/org/mapstruct/ap/model/TypeConversion.java b/processor/src/main/java/org/mapstruct/ap/model/TypeConversion.java
index cda8d4722..0132b7fd5 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/TypeConversion.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/TypeConversion.java
@@ -103,4 +103,10 @@ public class TypeConversion extends ModelElement implements Assignment {
return null;
}
}
+
+ @Override
+ public boolean isUpdateMethod() {
+ return false;
+ }
+
}
diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/Assignment.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/Assignment.java
index 1bc8a325d..00f43d2eb 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/assignment/Assignment.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/Assignment.java
@@ -83,4 +83,6 @@ public interface Assignment {
*/
AssignmentType getType();
+
+ boolean isUpdateMethod();
}
diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentWrapper.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentWrapper.java
index 520e3cc21..3470c419f 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentWrapper.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/AssignmentWrapper.java
@@ -64,4 +64,9 @@ public abstract class AssignmentWrapper extends ModelElement implements Assignme
public AssignmentType getType() {
return decoratedAssignment.getType();
}
+
+ @Override
+ public boolean isUpdateMethod() {
+ return decoratedAssignment.isUpdateMethod();
+ }
}
diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/UpdateWrapper.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/UpdateWrapper.java
new file mode 100644
index 000000000..a31e78a60
--- /dev/null
+++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/UpdateWrapper.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.model.assignment;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.mapstruct.ap.model.common.Type;
+
+/**
+ * Wraps the assignment in a target setter.
+ *
+ * @author Sjaak Derksen
+ */
+public class UpdateWrapper extends AssignmentWrapper {
+
+ private final List exceptionTypesToExclude;
+ private final Type targetType;
+ private final Assignment factoryMethod;
+
+ public UpdateWrapper(Assignment decoratedAssignment, List exceptionTypesToExclude, Type targetType,
+ Assignment factoryMethod ) {
+ super( decoratedAssignment );
+ this.exceptionTypesToExclude = exceptionTypesToExclude;
+ this.targetType = targetType;
+ this.factoryMethod = factoryMethod;
+ }
+
+ @Override
+ public List getExceptionTypes() {
+ List parentExceptionTypes = super.getExceptionTypes();
+ List result = new ArrayList( parentExceptionTypes );
+ for ( Type exceptionTypeToExclude : exceptionTypesToExclude ) {
+ for ( Type parentExceptionType : parentExceptionTypes ) {
+ if ( parentExceptionType.isAssignableTo( exceptionTypeToExclude ) ) {
+ result.remove( parentExceptionType );
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public Set getImportTypes() {
+ Set imported = new HashSet();
+ imported.addAll( super.getImportTypes() );
+ imported.add( targetType ); /* is a new target type */
+ return imported;
+ }
+
+ public Assignment getFactoryMethod() {
+ return factoryMethod;
+ }
+
+}
diff --git a/processor/src/main/java/org/mapstruct/ap/model/source/selector/CreateOrUpdateSelector.java b/processor/src/main/java/org/mapstruct/ap/model/source/selector/CreateOrUpdateSelector.java
index f9b08880f..fe7287922 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/source/selector/CreateOrUpdateSelector.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/source/selector/CreateOrUpdateSelector.java
@@ -23,12 +23,21 @@ import java.util.List;
import org.mapstruct.ap.model.common.Type;
import org.mapstruct.ap.model.source.Method;
-import org.mapstruct.ap.model.source.MethodMatcher;
/**
- * Selects only create method candidates (so methods not containing {@link @MappingTarget} )
- * {@link MethodMatcher}).
+ * Selection based on type of method (create - or update method).
*
+ *
+ * Prefers (when present):
+ *
+ * - create method candidates (methods not containing {@link @MappingTarget} ) when mapping method is
+ * a create method
+ * - update method candidates (methods containing {@link @MappingTarget} ) when mapping method is
+ * an update method
+ *
+ * When not present, the remaining (createCandidates when mapping method is update method, updateCandidates when mapping
+ * method is a create method) candidates are selected.
+ *
* @author Sjaak Derksen
*/
public class CreateOrUpdateSelector implements MethodSelector {
@@ -38,14 +47,23 @@ public class CreateOrUpdateSelector implements MethodSelector {
Type sourceType, Type targetType,
SelectionCriteria criteria) {
+ boolean isCreateMethod = mappingMethod.getMappingTargetParameter() == null;
List createCandidates = new ArrayList();
+ List updateCandidates = new ArrayList();
for ( T method : methods ) {
boolean isCreateCandidate = method.getMappingTargetParameter() == null;
if ( isCreateCandidate ) {
createCandidates.add( method );
}
+ else {
+ updateCandidates.add( method );
+ }
+ }
+ if ( criteria.isPreferUpdateMapping() ) {
+ if ( !updateCandidates.isEmpty() ) {
+ return updateCandidates;
+ }
}
return createCandidates;
-
}
}
diff --git a/processor/src/main/java/org/mapstruct/ap/model/source/selector/SelectionCriteria.java b/processor/src/main/java/org/mapstruct/ap/model/source/selector/SelectionCriteria.java
index 36330c4fb..588368f4c 100644
--- a/processor/src/main/java/org/mapstruct/ap/model/source/selector/SelectionCriteria.java
+++ b/processor/src/main/java/org/mapstruct/ap/model/source/selector/SelectionCriteria.java
@@ -31,11 +31,14 @@ public class SelectionCriteria {
private final List qualifiers;
private final String targetPropertyName;
private final TypeMirror qualifyingResultType;
+ private boolean preferUpdateMapping;
- public SelectionCriteria(List qualifiers, String targetPropertyName, TypeMirror qualifyingResultType) {
+ public SelectionCriteria(List qualifiers, String targetPropertyName, TypeMirror qualifyingResultType,
+ boolean preferUpdateMapping ) {
this.qualifiers = qualifiers;
this.targetPropertyName = targetPropertyName;
this.qualifyingResultType = qualifyingResultType;
+ this.preferUpdateMapping = preferUpdateMapping;
}
public List getQualifiers() {
@@ -49,4 +52,13 @@ public class SelectionCriteria {
public TypeMirror getQualifyingResultType() {
return qualifyingResultType;
}
+
+ public boolean isPreferUpdateMapping() {
+ return preferUpdateMapping;
+ }
+
+ public void setPreferUpdateMapping(boolean preferUpdateMapping) {
+ this.preferUpdateMapping = preferUpdateMapping;
+ }
+
}
diff --git a/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java
index f3cc86767..7ca9ebe80 100644
--- a/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java
+++ b/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java
@@ -272,14 +272,30 @@ public class MethodRetrievalProcessor implements ModelElementProcessor parameters) {
- return isValidReferencedOrFactoryMethod( 1, parameters );
+ int validSourceParameters = 0;
+ int targetParameters = 0;
+ int targetTypeParameters = 0;
+
+ for ( Parameter param : parameters ) {
+ if ( param.isMappingTarget() ) {
+ targetParameters++;
+ }
+
+ if ( param.isTargetType() ) {
+ targetTypeParameters++;
+ }
+
+ if ( !param.isMappingTarget() && !param.isTargetType() ) {
+ validSourceParameters++;
+ }
+ }
+ return validSourceParameters == 1
+ && targetParameters <= 1
+ && targetTypeParameters <= 1
+ && parameters.size() == validSourceParameters + targetParameters + targetTypeParameters;
}
private boolean isValidFactoryMethod(List parameters) {
- return isValidReferencedOrFactoryMethod( 0, parameters );
- }
-
- private boolean isValidReferencedOrFactoryMethod(int sourceParamCount, List parameters) {
int validSourceParameters = 0;
int targetParameters = 0;
int targetTypeParameters = 0;
@@ -297,7 +313,9 @@ public class MethodRetrievalProcessor implements ModelElementProcessor qualifiers,
- TypeMirror resultType, String sourceReference) {
+ TypeMirror resultType, String sourceReference, boolean preferUpdateMapping) {
- SelectionCriteria criteria = new SelectionCriteria(qualifiers, targetPropertyName, resultType );
+ SelectionCriteria criteria =
+ new SelectionCriteria(qualifiers, targetPropertyName, resultType, preferUpdateMapping );
ResolvingAttempt attempt = new ResolvingAttempt(
sourceModel,
@@ -122,7 +123,7 @@ public class MappingResolverImpl implements MappingResolver {
public MethodReference getFactoryMethod( Method mappingMethod, Type targetType, List qualifiers,
TypeMirror resultType ) {
- SelectionCriteria criteria = new SelectionCriteria(qualifiers, null, resultType );
+ SelectionCriteria criteria = new SelectionCriteria( qualifiers, null, resultType, false );
ResolvingAttempt attempt = new ResolvingAttempt(
sourceModel,
@@ -150,6 +151,7 @@ public class MappingResolverImpl implements MappingResolver {
private final String dateFormat;
private final SelectionCriteria selectionCriteria;
private final String sourceReference;
+ private final boolean savedPreferUpdateMapping;
// resolving via 2 steps creates the possibillity of wrong matches, first builtin method matches,
// second doesn't. In that case, the first builtin method should not lead to a virtual method
@@ -166,6 +168,7 @@ public class MappingResolverImpl implements MappingResolver {
this.sourceReference = sourceReference;
this.virtualMethodCandidates = new HashSet();
this.selectionCriteria = criteria;
+ this.savedPreferUpdateMapping = criteria.isPreferUpdateMapping();
}
private List filterPossibleCandidateMethods(List candidateMethods) {
@@ -223,6 +226,9 @@ public class MappingResolverImpl implements MappingResolver {
return referencedMethod;
}
+ // stop here when looking for update methods.
+ selectionCriteria.setPreferUpdateMapping( false );
+
// 2 step method, finally: conversion(method(source))
conversion = resolveViaMethodAndConversion( sourceType, targetType );
if ( conversion != null ) {
@@ -311,8 +317,10 @@ public class MappingResolverImpl implements MappingResolver {
resolveViaMethod( methodYCandidate.getSourceParameters().get( 0 ).getType(), targetType, true );
if ( methodRefY != null ) {
+ selectionCriteria.setPreferUpdateMapping( false );
Assignment methodRefX =
resolveViaMethod( sourceType, methodYCandidate.getSourceParameters().get( 0 ).getType(), true );
+ selectionCriteria.setPreferUpdateMapping( savedPreferUpdateMapping );
if ( methodRefX != null ) {
methodRefY.setAssignment( methodRefX );
methodRefX.setAssignment( AssignmentFactory.createDirect( sourceReference ) );
diff --git a/processor/src/main/java/org/mapstruct/ap/util/Message.java b/processor/src/main/java/org/mapstruct/ap/util/Message.java
index 1a9541c5c..715b454e2 100644
--- a/processor/src/main/java/org/mapstruct/ap/util/Message.java
+++ b/processor/src/main/java/org/mapstruct/ap/util/Message.java
@@ -49,8 +49,10 @@ public enum Message {
PROPERTYMAPPING_INVALID_PARAMETER_NAME( "Method has no parameter named \"%s\"." ),
PROPERTYMAPPING_NO_PROPERTY_IN_PARAMETER( "The type of parameter \"%s\" has no property named \"%s\"." ),
PROPERTYMAPPING_INVALID_PROPERTY_NAME( "No property named \"%s\" exists in source parameter(s)." ),
+ PROPERTYMAPPING_NO_READ_ACCESSOR_FOR_TARGET_TYPE( "No read accessor found for property \"%s\" in target type." ),
CONSTANTMAPPING_MAPPING_NOT_FOUND( "Can't map \"%s %s\" to \"%s %s\"." ),
+ CONSTANTMAPPING_NO_READ_ACCESSOR_FOR_TARGET_TYPE( "No read accessor found for property \"%s\" in target type." ),
MAPMAPPING_KEY_MAPPING_NOT_FOUND( "No implementation can be generated for this method. Found no method nor implicit conversion for mapping source key type to target key type." ),
MAPMAPPING_VALUE_MAPPING_NOT_FOUND( "No implementation can be generated for this method. Found no method nor implicit conversion for mapping source value type to target value type." ),
diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.UpdateWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.UpdateWrapper.ftl
new file mode 100644
index 000000000..be93df2b4
--- /dev/null
+++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.UpdateWrapper.ftl
@@ -0,0 +1,44 @@
+<#--
+
+ Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ and/or other contributors as indicated by the @authors tag. See the
+ copyright.txt file in the distribution for a full listing of all
+ contributors.
+
+ 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.
+
+-->
+<#if (exceptionTypes?size == 0) >
+ <@_assignment/>;
+<#else>
+ try {
+ <@_assignment/>;
+ }
+ <#list exceptionTypes as exceptionType>
+ catch ( <@includeModel object=exceptionType/> e ) {
+ throw new RuntimeException( e );
+ }
+ #list>
+#if>
+<#macro _assignment>
+ if ( ${ext.targetBeanName}.${ext.targetReadAccessorName}() == null ) {
+ ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <#if factoryMethod??><@includeModel object=factoryMethod targetType=ext.targetType raw=true/><#else>new <@includeModel object=ext.targetType/>()#if> );
+ }
+ <@includeModel object=assignment
+ targetBeanName=ext.targetBeanName
+ raw=ext.raw
+ existingInstanceMapping=ext.existingInstanceMapping
+ targetReadAccessorName=ext.targetReadAccessorName
+ targetWriteAccessorName=ext.targetWriteAccessorName
+ targetType=ext.targetType/>
+#macro>
\ No newline at end of file
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyDto.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyDto.java
new file mode 100644
index 000000000..f12fd58c8
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyDto.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class CompanyDto {
+
+ private String name;
+ private DepartmentDto department;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public DepartmentDto getDepartment() {
+ return department;
+ }
+
+ public void setDepartment(DepartmentDto department) {
+ this.department = department;
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyEntity.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyEntity.java
new file mode 100644
index 000000000..ad22c4fb8
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyEntity.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class CompanyEntity {
+
+ private String name;
+ private DepartmentEntity department;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public DepartmentEntity getDepartment() {
+ return department;
+ }
+
+ public void setDepartment(DepartmentEntity department) {
+ this.department = department;
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyMapper.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyMapper.java
new file mode 100644
index 000000000..69936bc9a
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/CompanyMapper.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.factory.Mappers;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+@Mapper( uses = DepartmentEntityFactory.class )
+public interface CompanyMapper {
+
+ CompanyMapper INSTANCE = Mappers.getMapper( CompanyMapper.class );
+
+ void toCompanyEntity(CompanyDto dto, @MappingTarget CompanyEntity entity);
+
+ DepartmentInBetween toInBetween(DepartmentDto dto);
+
+ void toDepartmentEntity(DepartmentInBetween dto, @MappingTarget DepartmentEntity entity);
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentDto.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentDto.java
new file mode 100644
index 000000000..193032ae2
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentDto.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class DepartmentDto {
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentEntity.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentEntity.java
new file mode 100644
index 000000000..b0b70b075
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentEntity.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class DepartmentEntity {
+
+ private String name;
+
+ public DepartmentEntity(Integer justAnArgToAvoidConstruction) {
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentEntityFactory.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentEntityFactory.java
new file mode 100644
index 000000000..ecd57ca08
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentEntityFactory.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class DepartmentEntityFactory {
+
+
+ public DepartmentEntity createDepartmentEntity() {
+ return new DepartmentEntity(5);
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentInBetween.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentInBetween.java
new file mode 100644
index 000000000..aa60da103
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/DepartmentInBetween.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class DepartmentInBetween {
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousCompanyMapper1.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousCompanyMapper1.java
new file mode 100644
index 000000000..375382a15
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousCompanyMapper1.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.factory.Mappers;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+@Mapper( uses = DepartmentEntityFactory.class )
+public interface ErroneousCompanyMapper1 {
+
+ ErroneousCompanyMapper1 INSTANCE = Mappers.getMapper( ErroneousCompanyMapper1.class );
+
+ void toCompanyEntity(CompanyDto dto, @MappingTarget CompanyEntity entity);
+
+ void toInBetween(DepartmentDto dto, @MappingTarget DepartmentInBetween entity);
+
+ void toDepartmentEntity(DepartmentInBetween dto, @MappingTarget DepartmentEntity entity);
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousOrganizationMapper1.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousOrganizationMapper1.java
new file mode 100644
index 000000000..cea30a75b
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousOrganizationMapper1.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.factory.Mappers;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+@Mapper( uses = DepartmentEntityFactory.class )
+public interface ErroneousOrganizationMapper1 {
+
+ ErroneousOrganizationMapper1 INSTANCE = Mappers.getMapper( ErroneousOrganizationMapper1.class );
+
+ @Mapping(target = "type", constant = "commercial")
+ void toOrganizationEntity(OrganizationDto dto, @MappingTarget OrganizationWithoutCompanyGetterEntity entity);
+
+ void toCompanyEntity(CompanyDto dto, @MappingTarget CompanyEntity entity);
+
+ @Mapping(source = "type", target = "type")
+ void toName(String type, @MappingTarget OrganizationTypeEntity entity);
+
+ DepartmentEntity toDepartmentEntity(DepartmentDto dto);
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousOrganizationMapper2.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousOrganizationMapper2.java
new file mode 100644
index 000000000..b9d7cce7a
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/ErroneousOrganizationMapper2.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.factory.Mappers;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+@Mapper
+public interface ErroneousOrganizationMapper2 {
+
+ ErroneousOrganizationMapper2 INSTANCE = Mappers.getMapper( ErroneousOrganizationMapper2.class );
+
+ @Mapping(target = "type", constant = "commercial")
+ void toOrganizationEntity(OrganizationDto dto, @MappingTarget OrganizationWithoutTypeGetterEntity entity);
+
+ void toCompanyEntity(CompanyDto dto, @MappingTarget CompanyEntity entity);
+
+ @Mapping(source = "type", target = "type")
+ void toName(String type, @MappingTarget OrganizationTypeEntity entity);
+
+ DepartmentEntity toDepartmentEntity(DepartmentDto dto);
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationDto.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationDto.java
new file mode 100644
index 000000000..0fb59bc4e
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationDto.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class OrganizationDto {
+
+ private CompanyDto company;
+
+ public CompanyDto getCompany() {
+ return company;
+ }
+
+ public void setCompany(CompanyDto company) {
+ this.company = company;
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationEntity.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationEntity.java
new file mode 100644
index 000000000..8b845e0ba
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationEntity.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class OrganizationEntity {
+
+ private CompanyEntity company;
+ private OrganizationTypeEntity type;
+ private OrganizationTypeNrEntity typeNr;
+
+ public CompanyEntity getCompany() {
+ return company;
+ }
+
+ public void setCompany(CompanyEntity company) {
+ this.company = company;
+ }
+
+ public OrganizationTypeEntity getType() {
+ return type;
+ }
+
+ public void setType(OrganizationTypeEntity type) {
+ this.type = type;
+ }
+
+ public OrganizationTypeNrEntity getTypeNr() {
+ return typeNr;
+ }
+
+ public void setTypeNr(OrganizationTypeNrEntity typeNr) {
+ this.typeNr = typeNr;
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationMapper.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationMapper.java
new file mode 100644
index 000000000..3ea35e82c
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationMapper.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.Mappings;
+import org.mapstruct.factory.Mappers;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+@Mapper( uses = DepartmentEntityFactory.class )
+public interface OrganizationMapper {
+
+ OrganizationMapper INSTANCE = Mappers.getMapper( OrganizationMapper.class );
+
+ @Mappings({
+ @Mapping(target = "type", constant = "commercial"),
+ @Mapping(target = "typeNr", constant = "5")
+ })
+ void toOrganizationEntity(OrganizationDto dto, @MappingTarget OrganizationEntity entity);
+
+ void toCompanyEntity(CompanyDto dto, @MappingTarget CompanyEntity entity);
+
+ DepartmentEntity toDepartmentEntity(DepartmentDto dto);
+
+ @Mapping(source = "type", target = "type")
+ void toName(String type, @MappingTarget OrganizationTypeEntity entity);
+
+ @Mapping(source = "number", target = "number")
+ void toNumber(Integer number, @MappingTarget OrganizationTypeNrEntity entity);
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationTypeEntity.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationTypeEntity.java
new file mode 100644
index 000000000..c3fa9d0c7
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationTypeEntity.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class OrganizationTypeEntity {
+
+ private String type;
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationTypeNrEntity.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationTypeNrEntity.java
new file mode 100644
index 000000000..30f8606a6
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationTypeNrEntity.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class OrganizationTypeNrEntity {
+
+ private Integer number;
+
+ public Integer getNumber() {
+ return number;
+ }
+
+ public void setNumber(Integer number) {
+ this.number = number;
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationWithoutCompanyGetterEntity.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationWithoutCompanyGetterEntity.java
new file mode 100644
index 000000000..500e4268a
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationWithoutCompanyGetterEntity.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class OrganizationWithoutCompanyGetterEntity {
+
+ private CompanyEntity company;
+ private OrganizationTypeEntity type;
+
+ public void setCompany(CompanyEntity company) {
+ this.company = company;
+ }
+
+ public OrganizationTypeEntity getType() {
+ return type;
+ }
+
+ public void setType(OrganizationTypeEntity type) {
+ this.type = type;
+ }
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationWithoutTypeGetterEntity.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationWithoutTypeGetterEntity.java
new file mode 100644
index 000000000..fe7cc4e81
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/OrganizationWithoutTypeGetterEntity.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class OrganizationWithoutTypeGetterEntity {
+
+ private CompanyEntity company;
+ private OrganizationTypeEntity type;
+
+ public CompanyEntity getCompany() {
+ return company;
+ }
+
+ public void setCompany(CompanyEntity company) {
+ this.company = company;
+ }
+
+ public void setType(OrganizationTypeEntity type) {
+ this.type = type;
+ }
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/UpdateMethodsTest.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/UpdateMethodsTest.java
new file mode 100644
index 000000000..68809ecaf
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/UpdateMethodsTest.java
@@ -0,0 +1,207 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+import org.mapstruct.ap.testutil.IssueKey;
+import org.mapstruct.ap.testutil.WithClasses;
+import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
+import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
+import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
+import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+@IssueKey("160")
+@RunWith(AnnotationProcessorTestRunner.class)
+public class UpdateMethodsTest {
+
+ @Test
+ @WithClasses( {
+ OrganizationMapper.class,
+ OrganizationDto.class,
+ OrganizationEntity.class,
+ CompanyDto.class,
+ CompanyEntity.class,
+ DepartmentDto.class,
+ DepartmentEntity.class,
+ DepartmentEntityFactory.class,
+ OrganizationTypeEntity.class,
+ OrganizationTypeNrEntity.class
+ } )
+ public void testPreferUpdateMethod() {
+
+ OrganizationEntity organizationEntity = new OrganizationEntity();
+ CompanyEntity companyEntity = new CompanyEntity();
+ organizationEntity.setCompany( companyEntity );
+ companyEntity.setName( "CocaCola" );
+
+ OrganizationDto organizationDto = new OrganizationDto();
+ CompanyDto companyDto = new CompanyDto();
+ organizationDto.setCompany( companyDto );
+ companyDto.setName( "PepsiCo" );
+ DepartmentDto departmentDto = new DepartmentDto();
+ departmentDto.setName( "finance" );
+ companyDto.setDepartment( departmentDto );
+
+ OrganizationMapper.INSTANCE.toOrganizationEntity( organizationDto, organizationEntity );
+
+ assertThat( organizationEntity.getCompany() ).isEqualTo( companyEntity );
+ assertThat( organizationEntity.getCompany().getName() ).isEqualTo( "PepsiCo" );
+ assertThat( organizationEntity.getType().getType() ).isEqualTo( "commercial" );
+ assertThat( organizationEntity.getTypeNr().getNumber()).isEqualTo( 5 );
+ assertThat( organizationEntity.getCompany().getDepartment().getName() ).isEqualTo( "finance" );
+ }
+
+ @Test
+ @WithClasses( {
+ OrganizationMapper.class,
+ OrganizationDto.class,
+ OrganizationEntity.class,
+ CompanyDto.class,
+ CompanyEntity.class,
+ DepartmentDto.class,
+ DepartmentEntity.class,
+ DepartmentEntityFactory.class,
+ OrganizationTypeEntity.class,
+ OrganizationTypeNrEntity.class
+ } )
+ public void testPreferUpdateMethodSourceObjectNotDefined() {
+
+ OrganizationEntity organizationEntity = new OrganizationEntity();
+
+ OrganizationDto organizationDto = new OrganizationDto();
+ CompanyDto companyDto = new CompanyDto();
+ organizationDto.setCompany( companyDto );
+ companyDto.setName( "PepsiCo" );
+ DepartmentDto departmentDto = new DepartmentDto();
+ departmentDto.setName( "finance" );
+ companyDto.setDepartment( departmentDto );
+
+ OrganizationMapper.INSTANCE.toOrganizationEntity( organizationDto, organizationEntity );
+
+ assertThat( organizationEntity.getCompany().getName() ).isEqualTo( "PepsiCo" );
+ assertThat( organizationEntity.getType().getType() ).isEqualTo( "commercial" );
+ assertThat( organizationEntity.getTypeNr().getNumber()).isEqualTo( 5 );
+ assertThat( organizationEntity.getCompany().getDepartment().getName() ).isEqualTo( "finance" );
+ }
+
+ @Test
+ @WithClasses( {
+ CompanyMapper.class,
+ CompanyDto.class,
+ CompanyEntity.class,
+ DepartmentDto.class,
+ DepartmentInBetween.class,
+ DepartmentEntity.class,
+ DepartmentEntityFactory.class,
+ OrganizationTypeEntity.class,
+ OrganizationTypeNrEntity.class
+ } )
+ public void testPreferUpdateMethodEncapsulatingCreateMethod() {
+
+ CompanyEntity companyEntity = new CompanyEntity();
+
+ CompanyDto companyDto = new CompanyDto();
+ DepartmentDto departmentDto = new DepartmentDto();
+ departmentDto.setName( "finance" );
+ companyDto.setDepartment( departmentDto );
+
+ CompanyMapper.INSTANCE.toCompanyEntity( companyDto, companyEntity );
+
+ assertThat( companyEntity.getDepartment().getName() ).isEqualTo( "finance" );
+
+ }
+
+ @Test
+ @WithClasses( {
+ ErroneousOrganizationMapper1.class,
+ OrganizationDto.class,
+ OrganizationWithoutCompanyGetterEntity.class,
+ CompanyDto.class,
+ CompanyEntity.class,
+ DepartmentDto.class,
+ DepartmentEntity.class,
+ DepartmentEntityFactory.class,
+ OrganizationTypeEntity.class
+ } )
+ @ExpectedCompilationOutcome(
+ value = CompilationResult.FAILED,
+ diagnostics = {
+ @Diagnostic(type = ErroneousOrganizationMapper1.class,
+ kind = javax.tools.Diagnostic.Kind.ERROR,
+ line = 36,
+ messageRegExp = "No read accessor found for property \"company\" in target type.")
+ }
+ )
+ public void testShouldFailOnPropertyMappingNoPropertyGetter() { }
+
+ @Test
+ @WithClasses( {
+ ErroneousOrganizationMapper2.class,
+ OrganizationDto.class,
+ OrganizationWithoutTypeGetterEntity.class,
+ CompanyDto.class,
+ CompanyEntity.class,
+ DepartmentDto.class,
+ DepartmentEntity.class,
+ DepartmentEntityFactory.class,
+ OrganizationTypeEntity.class
+ } )
+ @ExpectedCompilationOutcome(
+ value = CompilationResult.FAILED,
+ diagnostics = {
+ @Diagnostic(type = ErroneousOrganizationMapper2.class,
+ kind = javax.tools.Diagnostic.Kind.ERROR,
+ line = 36,
+ messageRegExp = "No read accessor found for property \"type\" in target type.")
+ }
+ )
+ public void testShouldFailOnConstantMappingNoPropertyGetter() { }
+
+ @Test
+ @WithClasses( {
+ ErroneousCompanyMapper1.class,
+ OrganizationDto.class,
+ OrganizationWithoutTypeGetterEntity.class,
+ CompanyDto.class,
+ CompanyEntity.class,
+ DepartmentDto.class,
+ DepartmentInBetween.class,
+ DepartmentEntity.class,
+ DepartmentEntityFactory.class,
+ OrganizationTypeEntity.class
+ } )
+ @ExpectedCompilationOutcome(
+ value = CompilationResult.FAILED,
+ diagnostics = {
+ @Diagnostic(type = ErroneousCompanyMapper1.class,
+ kind = javax.tools.Diagnostic.Kind.ERROR,
+ line = 34,
+ messageRegExp = "Can't map property \".*DepartmentDto department\" to \".*DepartmentEntity department.")
+ }
+ )
+ public void testShouldFailOnTwoNestedUpdateMethods() { }
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalHandWrittenMapper.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalHandWrittenMapper.java
new file mode 100644
index 000000000..44f38c561
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalHandWrittenMapper.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods.selection;
+
+import org.mapstruct.MappingTarget;
+import org.mapstruct.ap.test.updatemethods.DepartmentDto;
+import org.mapstruct.ap.test.updatemethods.DepartmentEntity;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+public class ExternalHandWrittenMapper {
+
+
+ public void toDepartmentEntity(DepartmentDto dto, @MappingTarget DepartmentEntity entity) {
+ if ( entity != null && dto != null ) {
+ entity.setName( dto.getName() );
+ }
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalMapper.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalMapper.java
new file mode 100644
index 000000000..cc66dc96f
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalMapper.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods.selection;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.ap.test.updatemethods.DepartmentDto;
+import org.mapstruct.ap.test.updatemethods.DepartmentEntity;
+import org.mapstruct.factory.Mappers;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+@Mapper
+public interface ExternalMapper {
+
+ ExternalMapper INSTANCE = Mappers.getMapper( ExternalMapper.class );
+
+ void toDepartmentEntity(DepartmentDto dto, @MappingTarget DepartmentEntity entity);
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalSelectionTest.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalSelectionTest.java
new file mode 100644
index 000000000..089189b88
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/ExternalSelectionTest.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods.selection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mapstruct.ap.test.updatemethods.CompanyDto;
+import org.mapstruct.ap.test.updatemethods.CompanyEntity;
+import org.mapstruct.ap.test.updatemethods.DepartmentDto;
+import org.mapstruct.ap.test.updatemethods.DepartmentEntity;
+import org.mapstruct.ap.test.updatemethods.DepartmentEntityFactory;
+import org.mapstruct.ap.testutil.IssueKey;
+import org.mapstruct.ap.testutil.WithClasses;
+import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+@IssueKey("160")
+@RunWith(AnnotationProcessorTestRunner.class)
+public class ExternalSelectionTest {
+
+ @Test
+ @WithClasses({
+ OrganizationMapper1.class,
+ ExternalMapper.class,
+ CompanyDto.class,
+ CompanyEntity.class,
+ DepartmentDto.class,
+ DepartmentEntityFactory.class,
+ DepartmentEntity.class
+ })
+ public void shouldSelectGeneratedExternalMapper() {
+
+ CompanyEntity entity = new CompanyEntity();
+ CompanyDto dto = new CompanyDto();
+ OrganizationMapper1.INSTANCE.toCompanyEntity( dto, entity );
+ }
+
+ @Test
+ @WithClasses({
+ OrganizationMapper2.class,
+ ExternalHandWrittenMapper.class,
+ CompanyDto.class,
+ CompanyEntity.class,
+ DepartmentDto.class,
+ DepartmentEntityFactory.class,
+ DepartmentEntity.class
+ })
+ public void shouldSelectGeneratedHandWrittenExternalMapper() {
+
+ CompanyEntity entity = new CompanyEntity();
+ CompanyDto dto = new CompanyDto();
+ OrganizationMapper2.INSTANCE.toCompanyEntity( dto, entity );
+ }
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper1.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper1.java
new file mode 100644
index 000000000..dbb61d9b9
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper1.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods.selection;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.ap.test.updatemethods.CompanyDto;
+import org.mapstruct.ap.test.updatemethods.CompanyEntity;
+import org.mapstruct.ap.test.updatemethods.DepartmentEntityFactory;
+import org.mapstruct.factory.Mappers;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+@Mapper(uses = { ExternalMapper.class, DepartmentEntityFactory.class } )
+public interface OrganizationMapper1 {
+
+ OrganizationMapper1 INSTANCE = Mappers.getMapper( OrganizationMapper1.class );
+
+ void toCompanyEntity(CompanyDto dto, @MappingTarget CompanyEntity entity);
+
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper2.java b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper2.java
new file mode 100644
index 000000000..d6ca5a00a
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/updatemethods/selection/OrganizationMapper2.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
+ * and/or other contributors as indicated by the @authors tag. See the
+ * copyright.txt file in the distribution for a full listing of all
+ * contributors.
+ *
+ * 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 org.mapstruct.ap.test.updatemethods.selection;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.ap.test.updatemethods.CompanyDto;
+import org.mapstruct.ap.test.updatemethods.CompanyEntity;
+import org.mapstruct.ap.test.updatemethods.DepartmentEntityFactory;
+import org.mapstruct.factory.Mappers;
+
+/**
+ *
+ * @author Sjaak Derksen
+ */
+@Mapper(uses = { ExternalHandWrittenMapper.class, DepartmentEntityFactory.class } )
+public interface OrganizationMapper2 {
+
+ OrganizationMapper2 INSTANCE = Mappers.getMapper( OrganizationMapper2.class );
+
+ void toCompanyEntity(CompanyDto dto, @MappingTarget CompanyEntity entity);
+
+}