diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java index 70cc7c07e..f2f20414d 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/IterableMappingMethod.java @@ -18,6 +18,7 @@ */ package org.mapstruct.ap.internal.model; +import java.util.HashSet; import static org.mapstruct.ap.internal.util.Collections.first; import java.util.List; @@ -105,12 +106,11 @@ public class IterableMappingMethod extends MappingMethod { Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method, "collection element", - sourceElementType, targetElementType, null, // there is no targetPropertyName formattingParameters, selectionParameters, - new SourceRHS( loopVariableName, sourceElementType ), + new SourceRHS( loopVariableName, sourceElementType, new HashSet() ), false ); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java index 67d5871c2..8bb475562 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/MapMappingMethod.java @@ -18,6 +18,7 @@ */ package org.mapstruct.ap.internal.model; +import java.util.HashSet; import static org.mapstruct.ap.internal.util.Collections.first; import java.util.List; @@ -108,12 +109,11 @@ public class MapMappingMethod extends MappingMethod { Assignment keyAssignment = ctx.getMappingResolver().getTargetAssignment( method, "map key", - keySourceType, keyTargetType, null, // there is no targetPropertyName keyFormattingParameters, keySelectionParameters, - new SourceRHS( "entry.getKey()", keySourceType ), + new SourceRHS( "entry.getKey()", keySourceType, new HashSet() ), false ); @@ -135,12 +135,11 @@ public class MapMappingMethod extends MappingMethod { Assignment valueAssignment = ctx.getMappingResolver().getTargetAssignment( method, "map value", - valueSourceType, valueTargetType, null, // there is no targetPropertyName valueFormattingParameters, valueSelectionParameters, - new SourceRHS( "entry.getValue()", valueSourceType ), + new SourceRHS( "entry.getValue()", valueSourceType, new HashSet() ), false ); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java b/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java index f340681b3..410c53b73 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java @@ -76,7 +76,6 @@ public class MappingBuilderContext { * * @param mappingMethod target mapping method * @param mappedElement used for error messages - * @param sourceType parameter to match * @param targetType return type to match * @param targetPropertyName name of the target property * @param formattingParameters used for formatting dates and numbers @@ -93,7 +92,7 @@ public class MappingBuilderContext { * */ @SuppressWarnings("checkstyle:parameternumber") - Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type sourceType, Type targetType, + Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type targetType, String targetPropertyName, FormattingParameters formattingParameters, SelectionParameters selectionParameters, SourceRHS sourceRHS, boolean preferUpdateMethods); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/MethodReference.java b/processor/src/main/java/org/mapstruct/ap/internal/model/MethodReference.java index 983f5e26b..019dc4c66 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/MethodReference.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/MethodReference.java @@ -133,6 +133,11 @@ public class MethodReference extends MappingMethod implements Assignment { return assignment.getSourceType(); } + @Override + public String createLocalVarName( String desiredName ) { + return assignment.createLocalVarName( desiredName ); + } + @Override public String getSourceLocalVarName() { return assignment.getSourceLocalVarName(); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java index fe01e70c3..cff1f0c92 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/PropertyMapping.java @@ -212,15 +212,11 @@ public class PropertyMapping extends ModelElement { // handle source String sourceElement = getSourceElement(); Type sourceType = getSourceType(); - SourceRHS sourceRHS; + SourceRHS sourceRHS = getSourceRHS(); if ( targetWriteAccessorType == TargetWriteAccessorType.ADDER && sourceType.isCollectionType() ) { // handle adder, if source is collection then use iterator element type as source type. - // sourceRef becomes a local variable in the itereation. sourceType = sourceType.getTypeParameters().get( 0 ); - sourceRHS = new SourceRHS( Executables.getElementNameForAdder( targetWriteAccessor ), sourceType ); - } - else { - sourceRHS = getSourceRHS(); + sourceRHS = new SourceRHS( sourceRHS.getSourceReference(), sourceType, existingVariableNames ); } // all the tricky cases will be excluded for the time being. @@ -235,7 +231,6 @@ public class PropertyMapping extends ModelElement { Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method, sourceElement, - sourceType, targetType, targetPropertyName, formattingParameters, @@ -320,7 +315,7 @@ public class PropertyMapping extends ModelElement { result = assignToPlainViaSetter( sourceType, targetType, rightHandSide ); } else { - result = assignToPlainViaAdder( sourceType, rightHandSide ); + result = assignToPlainViaAdder( rightHandSide ); } return result; @@ -391,18 +386,12 @@ public class PropertyMapping extends ModelElement { } } - private Assignment assignToPlainViaAdder(Type sourceType, Assignment rightHandSide) { + private Assignment assignToPlainViaAdder( Assignment rightHandSide) { Assignment result = rightHandSide; if ( getSourceType().isCollectionType() ) { - result = new AdderWrapper( - result, - method.getThrownTypes(), - getSourceRHS().getSourceReference(), - sourceType - ); - result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() ); + result = new AdderWrapper( result, method.getThrownTypes() ); } else { // Possibly adding null to a target collection. So should be surrounded by an null check. @@ -495,13 +484,13 @@ public class PropertyMapping extends ModelElement { // parameter reference if ( propertyEntries.isEmpty() ) { - return new SourceRHS( sourceParam.getName(), getSourceType() ); + return new SourceRHS( sourceParam.getName(), getSourceType(), existingVariableNames ); } // simple property else if ( propertyEntries.size() == 1 ) { PropertyEntry propertyEntry = propertyEntries.get( 0 ); - return new SourceRHS( sourceParam.getName() - + "." + propertyEntry.getReadAccessor().getSimpleName() + "()", propertyEntry.getType() ); + String sourceRef = sourceParam.getName() + "." + propertyEntry.getReadAccessor().getSimpleName() + "()"; + return new SourceRHS( sourceRef, propertyEntry.getType(), existingVariableNames ); } // nested property given as dot path else { @@ -532,7 +521,8 @@ public class PropertyMapping extends ModelElement { else { forgedName = ctx.getExistingMappingMethod( nestedPropertyMapping ).getName(); } - return new SourceRHS( forgedName + "( " + sourceParam.getName() + " )", getSourceType() ); + String sourceRef = forgedName + "( " + sourceParam.getName() + " )"; + return new SourceRHS( sourceRef, getSourceType(), existingVariableNames ); } } @@ -686,12 +676,11 @@ public class PropertyMapping extends ModelElement { assignment = ctx.getMappingResolver().getTargetAssignment( method, mappedElement, - sourceType, targetType, targetPropertyName, formattingParameters, selectionParameters, - new SourceRHS( constantExpression, sourceType ), + new SourceRHS( constantExpression, sourceType, existingVariableNames ), method.getMappingTargetParameter() != null ); } @@ -756,7 +745,7 @@ public class PropertyMapping extends ModelElement { // String String quotation marks. String enumExpression = constantExpression.substring( 1, constantExpression.length() - 1 ); if ( targetType.getEnumConstants().contains( enumExpression ) ) { - assignment = new SourceRHS( enumExpression, targetType ); + assignment = new SourceRHS( enumExpression, targetType, existingVariableNames ); assignment = new EnumConstantWrapper( assignment, targetType ); } else { @@ -782,7 +771,7 @@ public class PropertyMapping extends ModelElement { } public PropertyMapping build() { - Assignment assignment = new SourceRHS( javaExpression, null ); + Assignment assignment = new SourceRHS( javaExpression, null, existingVariableNames ); if ( Executables.isSetterMethod( targetWriteAccessor ) ) { // setter, so wrap in setter diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/SourceRHS.java b/processor/src/main/java/org/mapstruct/ap/internal/model/SourceRHS.java index c88b6c182..6321fe6a9 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/SourceRHS.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/SourceRHS.java @@ -25,6 +25,7 @@ import java.util.Set; import org.mapstruct.ap.internal.model.assignment.Assignment; import org.mapstruct.ap.internal.model.common.ModelElement; import org.mapstruct.ap.internal.model.common.Type; +import org.mapstruct.ap.internal.util.Strings; /** * SourceRHS Assignment. Right Hand Side (RHS), source part of the assignment. @@ -36,10 +37,12 @@ public class SourceRHS extends ModelElement implements Assignment { private final String sourceReference; private final Type sourceType; private String sourceLocalVarName; + private final Set existingVariableNames; - public SourceRHS(String sourceReference, Type sourceType ) { + public SourceRHS(String sourceReference, Type sourceType, Set existingVariableNames ) { this.sourceReference = sourceReference; this.sourceType = sourceType; + this.existingVariableNames = existingVariableNames; } @Override @@ -52,6 +55,11 @@ public class SourceRHS extends ModelElement implements Assignment { return sourceType; } + @Override + public String createLocalVarName(String desiredName) { + return Strings.getSaveVariableName( desiredName, existingVariableNames ); + } + @Override public String getSourceLocalVarName() { return sourceLocalVarName; diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/TypeConversion.java b/processor/src/main/java/org/mapstruct/ap/internal/model/TypeConversion.java index 0a58f3799..74c0f989a 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/TypeConversion.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/TypeConversion.java @@ -91,6 +91,11 @@ public class TypeConversion extends ModelElement implements Assignment { return assignment.getSourceType(); } + @Override + public String createLocalVarName( String desiredName ) { + return assignment.createLocalVarName( desiredName ); + } + @Override public String getSourceLocalVarName() { return assignment.getSourceLocalVarName(); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AdderWrapper.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AdderWrapper.java index d4fcf2b01..751bf8852 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AdderWrapper.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AdderWrapper.java @@ -33,18 +33,14 @@ import org.mapstruct.ap.internal.model.common.Type; public class AdderWrapper extends AssignmentWrapper { private final List thrownTypesToExclude; - private final String sourceReference; - private final Type sourceType; + private final String sourceIteratorName; - public AdderWrapper( - Assignment decoratedAssignment, - List thrownTypesToExclude, - String sourceReference, - Type sourceType) { + public AdderWrapper( Assignment decoratedAssignment, List thrownTypesToExclude ) { super( decoratedAssignment ); this.thrownTypesToExclude = thrownTypesToExclude; - this.sourceReference = sourceReference; - this.sourceType = sourceType; + this.sourceIteratorName = + decoratedAssignment.createLocalVarName( decoratedAssignment.getSourceType().getName() ); + decoratedAssignment.setSourceLocalVarName( sourceIteratorName ); } @Override @@ -61,25 +57,15 @@ public class AdderWrapper extends AssignmentWrapper { return result; } - public Type getSourceType() { - return sourceType; - } - - @Override - public String getSourceReference() { - return sourceReference; - } - @Override public Set getImportTypes() { Set imported = new HashSet(); imported.addAll( super.getImportTypes() ); - imported.add( sourceType ); + imported.add( getSourceType() ); return imported; } - public String getIteratorReference() { - return getAssignment().getSourceReference(); + public String getSourceIteratorName() { + return sourceIteratorName; } - } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/Assignment.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/Assignment.java index e883e7a49..7f3fd9ffa 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/Assignment.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/Assignment.java @@ -78,12 +78,20 @@ public interface Assignment { String getSourceReference(); /** - * the source type. + * the source type used in the matching process * * @return source type (can be null) */ Type getSourceType(); + /** + * safe (local) element variable name when dealing with collections. + * + * @param desiredName the desired name + * @return the desired name, made unique + */ + String createLocalVarName( String desiredName ); + /** * a local variable name for supporting a null check and avoiding executing a nested method forged method twice * diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AssignmentWrapper.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AssignmentWrapper.java index 58792c9ad..8160a4cf1 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AssignmentWrapper.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/AssignmentWrapper.java @@ -86,4 +86,9 @@ public abstract class AssignmentWrapper extends ModelElement implements Assignme return decoratedAssignment.isUpdateMethod(); } + @Override + public String createLocalVarName( String desiredName ) { + return decoratedAssignment.createLocalVarName( desiredName ); + } + } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/creation/MappingResolverImpl.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/creation/MappingResolverImpl.java index 029448707..53a60ac53 100755 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/creation/MappingResolverImpl.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/creation/MappingResolverImpl.java @@ -106,7 +106,7 @@ public class MappingResolverImpl implements MappingResolver { @Override @SuppressWarnings("checkstyle:parameternumber") - public Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type sourceType, + public Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type targetType, String targetPropertyName, FormattingParameters formattingParameters, SelectionParameters selectionParameters, SourceRHS sourceRHS, boolean preferUpdateMapping) { @@ -130,7 +130,7 @@ public class MappingResolverImpl implements MappingResolver { criteria ); - return attempt.getTargetAssignment( sourceType, targetType ); + return attempt.getTargetAssignment( sourceRHS.getSourceType(), targetType ); } @Override diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/AdderWrapper.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/AdderWrapper.ftl index 0f1ba87f8..ec7b888f3 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/AdderWrapper.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/AdderWrapper.ftl @@ -18,29 +18,11 @@ limitations under the License. --> -<#if (thrownTypes?size == 0) > - for ( <@includeModel object=sourceType/> ${iteratorReference} : ${sourceReference} ) { - ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@includeModel object=assignment - targetBeanName=ext.targetBeanName - existingInstanceMapping=ext.existingInstanceMapping - targetReadAccessorName=ext.targetReadAccessorName - targetWriteAccessorName=ext.targetWriteAccessorName - targetType=ext.targetType/> ); - } -<#else> - try { - for ( <@includeModel object=sourceType/> ${iteratorReference} : ${sourceReference} ) { - ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@includeModel object=assignment - targetBeanName=ext.targetBeanName - existingInstanceMapping=ext.existingInstanceMapping - targetReadAccessorName=ext.targetReadAccessorName - targetWriteAccessorName=ext.targetWriteAccessorName - targetType=ext.targetType/> ); - } - } - <#list thrownTypes as exceptionType> - catch ( <@includeModel object=exceptionType/> e ) { - throw new RuntimeException( e ); - } - - \ No newline at end of file +<#import "../macro/CommonMacros.ftl" as lib> +<@lib.handleExceptions> + if ( ${sourceReference} != null ) { + for ( <@includeModel object=sourceType/> ${sourceIteratorName} : ${sourceReference} ) { + ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@lib.handleAssignment/> ); + } + } + \ No newline at end of file