From 81a4cb360db164c8e8985e33e887db74e201e2af Mon Sep 17 00:00:00 2001 From: sjaakd Date: Sat, 3 Dec 2016 15:20:26 +0100 Subject: [PATCH] #981 Refactoring, move SourceRHS init to start of property build. --- .../internal/model/IterableMappingMethod.java | 3 +- .../ap/internal/model/MapMappingMethod.java | 6 +- .../internal/model/MappingBuilderContext.java | 6 +- .../ap/internal/model/MethodReference.java | 5 + .../ap/internal/model/PropertyMapping.java | 160 ++++++++---------- .../ap/internal/model/SourceRHS.java | 50 +++++- .../ap/internal/model/TypeConversion.java | 5 + .../model/assignment/AdderWrapper.java | 6 +- .../internal/model/assignment/Assignment.java | 7 + .../model/assignment/AssignmentWrapper.java | 5 + .../GetterWrapperForCollectionsAndMaps.java | 23 +-- .../model/assignment/NullCheckWrapper.java | 8 +- .../SetterWrapperForCollectionsAndMaps.java | 6 - .../assignment/UpdateNullCheckWrapper.java | 10 +- .../WrapperForCollectionsAndMaps.java | 7 - .../model/source/SourceReference.java | 21 +++ .../creation/MappingResolverImpl.java | 23 +-- .../model/assignment/AdderWrapper.ftl | 2 +- .../model/assignment/NullCheckWrapper.ftl | 2 +- .../SetterWrapperForCollectionsAndMaps.ftl | 4 +- .../assignment/UpdateNullCheckWrapper.ftl | 2 +- .../ap/internal/model/macro/CommonMacros.ftl | 4 +- 22 files changed, 187 insertions(+), 178 deletions(-) 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 81c4b9add..7700e1b31 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 @@ -105,12 +105,11 @@ public class IterableMappingMethod extends MappingMethod { Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method, - "collection element", targetElementType, null, // there is no targetPropertyName formattingParameters, selectionParameters, - new SourceRHS( loopVariableName, sourceElementType, new HashSet() ), + new SourceRHS( loopVariableName, sourceElementType, new HashSet(), "collection element" ), 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 35946f59d..bb43f2b84 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 @@ -108,12 +108,11 @@ public class MapMappingMethod extends MappingMethod { Assignment keyAssignment = ctx.getMappingResolver().getTargetAssignment( method, - "map key", keyTargetType, null, // there is no targetPropertyName keyFormattingParameters, keySelectionParameters, - new SourceRHS( "entry.getKey()", keySourceType, new HashSet() ), + new SourceRHS( "entry.getKey()", keySourceType, new HashSet(), "map key" ), false ); @@ -134,12 +133,11 @@ public class MapMappingMethod extends MappingMethod { Assignment valueAssignment = ctx.getMappingResolver().getTargetAssignment( method, - "map value", valueTargetType, null, // there is no targetPropertyName valueFormattingParameters, valueSelectionParameters, - new SourceRHS( "entry.getValue()", valueSourceType, new HashSet() ), + new SourceRHS( "entry.getValue()", valueSourceType, new HashSet(), "map value" ), 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 410c53b73..e137f3961 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 @@ -75,7 +75,6 @@ public class MappingBuilderContext { * returns a parameter assignment * * @param mappingMethod target mapping method - * @param mappedElement used for error messages * @param targetType return type to match * @param targetPropertyName name of the target property * @param formattingParameters used for formatting dates and numbers @@ -91,9 +90,8 @@ public class MappingBuilderContext { *
  • null, no assignment found
  • * */ - @SuppressWarnings("checkstyle:parameternumber") - Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type targetType, - String targetPropertyName, FormattingParameters formattingParameters, + Assignment getTargetAssignment(Method mappingMethod, 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 e3ee07951..58e6c1b6d 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 @@ -127,6 +127,11 @@ public class MethodReference extends MappingMethod implements Assignment { return assignment.getSourceReference(); } + @Override + public String getSourcePresenceCheckerReference() { + return assignment.getSourcePresenceCheckerReference(); + } + @Override public Type getSourceType() { return assignment.getSourceType(); 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 bbc66ba7b..052de7a3a 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 @@ -203,6 +203,7 @@ public class PropertyMapping extends ModelElement { // initial properties private String defaultValue; private SourceReference sourceReference; + private SourceRHS rightHandSide; private FormattingParameters formattingParameters; private SelectionParameters selectionParameters; @@ -228,14 +229,10 @@ public class PropertyMapping extends ModelElement { public PropertyMapping build() { // handle source - String sourceElement = getSourceElement(); - Type sourceType = getSourceType(); - SourceRHS sourceRHS = getSourceRHS(); - if ( targetWriteAccessorType == TargetWriteAccessorType.ADDER && sourceType.isCollectionType() ) { - // handle adder, if source is collection then use iterator element type as source type. - sourceType = sourceType.getTypeParameters().get( 0 ); - sourceRHS = new SourceRHS( sourceRHS.getSourceReference(), sourceType, existingVariableNames ); - } + this.rightHandSide = getSourceRHS( sourceReference ); + rightHandSide.setUseElementAsSourceTypeForMatching( + targetWriteAccessorType == TargetWriteAccessorType.ADDER ); + Type sourceType = rightHandSide.getSourceType(); // all the tricky cases will be excluded for the time being. boolean preferUpdateMethods; @@ -248,22 +245,21 @@ public class PropertyMapping extends ModelElement { Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method, - sourceElement, targetType, targetPropertyName, formattingParameters, selectionParameters, - sourceRHS, + rightHandSide, preferUpdateMethods ); // No mapping found. Try to forge a mapping if ( assignment == null ) { if ( (sourceType.isCollectionType() || sourceType.isArrayType()) && targetType.isIterableType() ) { - assignment = forgeIterableMapping( sourceType, targetType, sourceRHS, method.getExecutable() ); + assignment = forgeIterableMapping( sourceType, targetType, rightHandSide, method.getExecutable() ); } else if ( sourceType.isMapType() && targetType.isMapType() ) { - assignment = forgeMapMapping( sourceType, targetType, sourceRHS, method.getExecutable() ); + assignment = forgeMapMapping( sourceType, targetType, rightHandSide, method.getExecutable() ); } } @@ -282,30 +278,30 @@ public class PropertyMapping extends ModelElement { ctx.getMessager().printMessage( method.getExecutable(), Message.PROPERTYMAPPING_MAPPING_NOT_FOUND, - sourceElement, + rightHandSide.getSourceErrorMessagePart(), targetType, targetPropertyName, targetType, - getSourceType() /* original source type */ + rightHandSide.getSourceType() /* original source type */ ); } return new PropertyMapping( targetPropertyName, - sourceReference.getParameter().getName(), + rightHandSide.getSourceParameterName(), targetWriteAccessor.getSimpleName().toString(), ValueProvider.of( targetReadAccessor ), targetType, localTargetVarName, assignment, dependsOn, - getDefaultValueAssignment() + getDefaultValueAssignment( assignment ) ); } - private Assignment getDefaultValueAssignment() { + private Assignment getDefaultValueAssignment( Assignment rhs ) { if ( defaultValue != null - && ( !getSourceType().isPrimitive() || getSourcePresenceCheckerRef() != null) ) { + && ( !rhs.getSourceType().isPrimitive() || rhs.getSourcePresenceCheckerReference() != null) ) { // cannot check on null source if source is primitive unless it has a presenche checker PropertyMapping build = new ConstantMappingBuilder() .constantExpression( '"' + defaultValue + '"' ) @@ -340,23 +336,23 @@ public class PropertyMapping extends ModelElement { } - private Assignment assignToPlainViaSetter(Type sourceType, Type targetType, Assignment rightHandSide) { + private Assignment assignToPlainViaSetter(Type sourceType, Type targetType, Assignment rhs) { Assignment result; - if ( rightHandSide.isUpdateMethod() ) { + if ( rhs.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 ); - result = new UpdateWrapper( rightHandSide, method.getThrownTypes(), factoryMethod, + result = new UpdateWrapper( rhs, method.getThrownTypes(), factoryMethod, targetType, isFieldAssignment() ); } else { - result = new SetterWrapper( rightHandSide, method.getThrownTypes(), isFieldAssignment() ); + result = new SetterWrapper( rhs, method.getThrownTypes(), isFieldAssignment() ); } // if the sourceReference is the bean mapping method parameter itself, no null check is required @@ -367,20 +363,20 @@ public class PropertyMapping extends ModelElement { // add a null / presence checked when required if ( sourceType.isPrimitive() ) { - if ( getSourcePresenceCheckerRef() != null ) { - result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() ); + if ( rhs.getSourcePresenceCheckerReference() != null ) { + result = new NullCheckWrapper( result ); } } else { if ( result.isUpdateMethod() ) { - result = new UpdateNullCheckWrapper( result, getSourcePresenceCheckerRef(), isFieldAssignment() ); + result = new UpdateNullCheckWrapper( result, isFieldAssignment() ); } - else if ( getSourcePresenceCheckerRef() != null ) { - result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() ); + else if ( rhs.getSourcePresenceCheckerReference() != null ) { + result = new NullCheckWrapper( result ); } else if ( ALWAYS.equals( method.getMapperConfiguration().getNullValueCheckStrategy() ) ) { - result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() ); + result = new NullCheckWrapper( result ); useLocalVarWhenNested( result ); } else if ( result.getType() == TYPE_CONVERTED @@ -389,7 +385,7 @@ public class PropertyMapping extends ModelElement { || (result.getType() == DIRECT && targetType.isPrimitive() ) ) { // for primitive types null check is not possible at all, but a conversion needs // a null check. - result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() ); + result = new NullCheckWrapper( result ); useLocalVarWhenNested( result ); } } @@ -410,13 +406,13 @@ public class PropertyMapping extends ModelElement { Assignment result = rightHandSide; - if ( getSourceType().isCollectionType() ) { + if ( result.getSourceType().isCollectionType() ) { result = new AdderWrapper( result, method.getThrownTypes(), isFieldAssignment() ); } else { // Possibly adding null to a target collection. So should be surrounded by an null check. result = new SetterWrapper( result, method.getThrownTypes(), isFieldAssignment() ); - result = new NullCheckWrapper( result, getSourcePresenceCheckerRef() ); + result = new NullCheckWrapper( result ); } return result; } @@ -450,7 +446,6 @@ public class PropertyMapping extends ModelElement { result = new SetterWrapperForCollectionsAndMaps( result, method.getThrownTypes(), - getSourcePresenceCheckerRef(), existingVariableNames, targetType, ALWAYS == method.getMapperConfiguration().getNullValueCheckStrategy(), @@ -463,7 +458,6 @@ public class PropertyMapping extends ModelElement { // target accessor is getter, so wrap the setter in getter map/ collection handling result = new GetterWrapperForCollectionsAndMaps( result, method.getThrownTypes(), - getSourcePresenceCheckerRef(), existingVariableNames, targetType, isFieldAssignment() @@ -484,19 +478,34 @@ public class PropertyMapping extends ModelElement { existingVariableNames, isFieldAssignment() ); - return new NullCheckWrapper( assignment, getSourcePresenceCheckerRef() ); + return new NullCheckWrapper( assignment ); } - private Type getSourceType() { - + private SourceRHS getSourceRHS( SourceReference sourceReference ) { Parameter sourceParam = sourceReference.getParameter(); List propertyEntries = sourceReference.getPropertyEntries(); + + // parameter reference if ( propertyEntries.isEmpty() ) { - return sourceParam.getType(); + return new SourceRHS( sourceParam.getName(), + sourceParam.getType(), + existingVariableNames, + sourceReference.toString() + ); } + // simple property else if ( propertyEntries.size() == 1 ) { - return last( propertyEntries ).getType(); + PropertyEntry propertyEntry = propertyEntries.get( 0 ); + String sourceRef = sourceParam.getName() + "." + ValueProvider.of( propertyEntry.getReadAccessor() ); + return new SourceRHS( sourceParam.getName(), + sourceRef, + getSourcePresenceCheckerRef( sourceReference ), + propertyEntry.getType(), + existingVariableNames, + sourceReference.toString() + ); } + // nested property given as dot path else { Type sourceType = last( propertyEntries ).getType(); if ( sourceType.isPrimitive() && !targetType.isPrimitive() ) { @@ -505,39 +514,18 @@ public class PropertyMapping extends ModelElement { // type. The source type becomes the wrapped type in that case. sourceType = ctx.getTypeFactory().getWrappedType( sourceType ); } - return sourceType; - } - } - private SourceRHS getSourceRHS() { - Parameter sourceParam = sourceReference.getParameter(); - List propertyEntries = sourceReference.getPropertyEntries(); - - // parameter reference - if ( propertyEntries.isEmpty() ) { - return new SourceRHS( sourceParam.getName(), getSourceType(), existingVariableNames ); - } - // simple property - else if ( propertyEntries.size() == 1 ) { - PropertyEntry propertyEntry = propertyEntries.get( 0 ); - String sourceRef = sourceParam.getName() + "." + ValueProvider.of( propertyEntry.getReadAccessor() ); - return new SourceRHS( sourceRef, propertyEntry.getType(), existingVariableNames ); - } - // nested property given as dot path - else { // copy mapper configuration from the source method, its the same mapper MapperConfiguration config = method.getMapperConfiguration(); - // forge a method from the parameter type to the last entry type. String forgedName = Strings.joinAndCamelize( sourceReference.getElementNames() ); forgedName = Strings.getSaveVariableName( forgedName, ctx.getNamesOfMappingsToGenerate() ); - ForgedMethod methodRef = new ForgedMethod( - forgedName, - sourceReference.getParameter().getType(), - getSourceType(), - config, - method.getExecutable() + ForgedMethod methodRef = new ForgedMethod( forgedName, + sourceReference.getParameter().getType(), + sourceType, + config, + method.getExecutable() ); NestedPropertyMappingMethod.Builder builder = new NestedPropertyMappingMethod.Builder(); NestedPropertyMappingMethod nestedPropertyMapping = builder @@ -553,36 +541,24 @@ public class PropertyMapping extends ModelElement { forgedName = ctx.getExistingMappingMethod( nestedPropertyMapping ).getName(); } String sourceRef = forgedName + "( " + sourceParam.getName() + " )"; - return new SourceRHS( sourceRef, getSourceType(), existingVariableNames ); - - } - } - - private String getSourceElement() { - - Parameter sourceParam = sourceReference.getParameter(); - List propertyEntries = sourceReference.getPropertyEntries(); - if ( propertyEntries.isEmpty() ) { - return String.format( "parameter \"%s %s\"", sourceParam.getType(), sourceParam.getName() ); - } - else if ( propertyEntries.size() == 1 ) { - PropertyEntry propertyEntry = propertyEntries.get( 0 ); - return String.format( "property \"%s %s\"", propertyEntry.getType(), propertyEntry.getName() ); - } - else { - PropertyEntry lastPropertyEntry = propertyEntries.get( propertyEntries.size() - 1 ); - return String.format( - "property \"%s %s\"", - lastPropertyEntry.getType(), - Strings.join( sourceReference.getElementNames(), "." ) + SourceRHS sourceRhs = new SourceRHS( sourceParam.getName(), + sourceRef, + getSourcePresenceCheckerRef( sourceReference ), + sourceType, + existingVariableNames, + sourceReference.toString() ); + return sourceRhs; + } } - private String getSourcePresenceCheckerRef() { + private String getSourcePresenceCheckerRef( SourceReference sourceReference ) { String sourcePresenceChecker = null; if ( !sourceReference.getPropertyEntries().isEmpty() ) { Parameter sourceParam = sourceReference.getParameter(); + // TODO is first correct here?? shouldn't it be last since the remainer is checked + // in the forged method? PropertyEntry propertyEntry = first( sourceReference.getPropertyEntries() ); if ( propertyEntry.getPresenceChecker() != null ) { sourcePresenceChecker = sourceParam.getName() @@ -699,19 +675,18 @@ public class PropertyMapping extends ModelElement { public PropertyMapping build() { // source - String mappedElement = "constant '" + constantExpression + "'"; + String sourceErrorMessagePart = "constant '" + constantExpression + "'"; Type sourceType = ctx.getTypeFactory().getType( String.class ); Assignment assignment = null; if ( !targetType.isEnumType() ) { assignment = ctx.getMappingResolver().getTargetAssignment( method, - mappedElement, targetType, targetPropertyName, formattingParameters, selectionParameters, - new SourceRHS( constantExpression, sourceType, existingVariableNames ), + new SourceRHS( constantExpression, sourceType, existingVariableNames, sourceErrorMessagePart ), method.getMappingTargetParameter() != null ); } @@ -780,7 +755,8 @@ 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, existingVariableNames ); + String sourceErrorMessagePart = "constant '" + constantExpression + "'"; + assignment = new SourceRHS( enumExpression, targetType, existingVariableNames, sourceErrorMessagePart ); assignment = new EnumConstantWrapper( assignment, targetType ); } else { @@ -806,7 +782,7 @@ public class PropertyMapping extends ModelElement { } public PropertyMapping build() { - Assignment assignment = new SourceRHS( javaExpression, null, existingVariableNames ); + Assignment assignment = new SourceRHS( javaExpression, null, existingVariableNames, "" ); if ( Executables.isSetterMethod( targetWriteAccessor ) || Executables.isFieldAccessor( targetWriteAccessor ) ) { 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 6321fe6a9..58ef565fa 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 @@ -30,6 +30,8 @@ import org.mapstruct.ap.internal.util.Strings; /** * SourceRHS Assignment. Right Hand Side (RHS), source part of the assignment. * + * This class contains all information on the source side of an assignment needed for common use in the mapping. + * * @author Sjaak Derksen */ public class SourceRHS extends ModelElement implements Assignment { @@ -38,11 +40,24 @@ public class SourceRHS extends ModelElement implements Assignment { private final Type sourceType; private String sourceLocalVarName; private final Set existingVariableNames; + private final String sourceErrorMessagePart; + private final String sourcePresenceCheckerReference; + private boolean useElementAsSourceTypeForMatching = false; + private final String sourceParameterName; - public SourceRHS(String sourceReference, Type sourceType, Set existingVariableNames ) { + public SourceRHS(String sourceReference, Type sourceType, Set existingVariableNames, + String sourceErrorMessagePart ) { + this( null, sourceReference, null, sourceType, existingVariableNames, sourceErrorMessagePart ); + } + + public SourceRHS(String sourceParameterName, String sourceReference, String sourcePresenceCheckerReference, + Type sourceType, Set existingVariableNames, String sourceErrorMessagePart ) { this.sourceReference = sourceReference; this.sourceType = sourceType; this.existingVariableNames = existingVariableNames; + this.sourceErrorMessagePart = sourceErrorMessagePart; + this.sourcePresenceCheckerReference = sourcePresenceCheckerReference; + this.sourceParameterName = sourceParameterName; } @Override @@ -50,6 +65,11 @@ public class SourceRHS extends ModelElement implements Assignment { return sourceReference; } + @Override + public String getSourcePresenceCheckerReference() { + return sourcePresenceCheckerReference; + } + @Override public Type getSourceType() { return sourceType; @@ -99,4 +119,32 @@ public class SourceRHS extends ModelElement implements Assignment { public String toString() { return sourceReference; } + + public String getSourceErrorMessagePart() { + return sourceErrorMessagePart; + } + + /** + * The source type that is to be used when resolving the mapping from source to target. + * + * @return the source type to be used in the matching process. + */ + public Type getSourceTypeForMatching() { + return useElementAsSourceTypeForMatching && sourceType.isCollectionType() ? + sourceType.getTypeParameters().get( 0 ) : sourceType; + } + + /** + * For collection type, use element as source type to find a suitable mapping method. + * + * @param useElementAsSourceTypeForMatching + */ + public void setUseElementAsSourceTypeForMatching(boolean useElementAsSourceTypeForMatching) { + this.useElementAsSourceTypeForMatching = useElementAsSourceTypeForMatching; + } + + public String getSourceParameterName() { + return sourceParameterName; + } + } 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 74c0f989a..afd94fad5 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 @@ -86,6 +86,11 @@ public class TypeConversion extends ModelElement implements Assignment { return assignment.getSourceReference(); } + @Override + public String getSourcePresenceCheckerReference() { + return assignment.getSourcePresenceCheckerReference(); + } + @Override public Type getSourceType() { return assignment.getSourceType(); 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 770e48599..1843301c6 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 @@ -38,8 +38,8 @@ public class AdderWrapper extends AssignmentWrapper { public AdderWrapper( Assignment decoratedAssignment, List thrownTypesToExclude, boolean fieldAssignment ) { super( decoratedAssignment, fieldAssignment ); this.thrownTypesToExclude = thrownTypesToExclude; - this.sourceIteratorName = - decoratedAssignment.createLocalVarName( decoratedAssignment.getSourceType().getName() ); + String desiredName = decoratedAssignment.getSourceType().getTypeParameters().get( 0 ).getName(); + this.sourceIteratorName = decoratedAssignment.createLocalVarName( desiredName ); decoratedAssignment.setSourceLocalVarName( sourceIteratorName ); } @@ -61,7 +61,7 @@ public class AdderWrapper extends AssignmentWrapper { public Set getImportTypes() { Set imported = new HashSet(); imported.addAll( super.getImportTypes() ); - imported.add( getSourceType() ); + imported.add( getSourceType().getTypeParameters().get( 0 ) ); return imported; } 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 34f483224..d02b5410e 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 @@ -77,6 +77,13 @@ public interface Assignment { */ String getSourceReference(); + /** + * the source presence checker reference + * + * @return source reference + */ + String getSourcePresenceCheckerReference(); + /** * the source type used in the matching process * 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 7229b9d95..50d2058a4 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 @@ -63,6 +63,11 @@ public abstract class AssignmentWrapper extends ModelElement implements Assignme return decoratedAssignment.getSourceReference(); } + @Override + public String getSourcePresenceCheckerReference() { + return decoratedAssignment.getSourcePresenceCheckerReference(); + } + @Override public Type getSourceType() { return decoratedAssignment.getSourceType(); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/GetterWrapperForCollectionsAndMaps.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/GetterWrapperForCollectionsAndMaps.java index 58ad4d439..80bb060bf 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/GetterWrapperForCollectionsAndMaps.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/GetterWrapperForCollectionsAndMaps.java @@ -39,17 +39,14 @@ import org.mapstruct.ap.internal.model.common.Type; public class GetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAndMaps { /** - * constructor for property mapping - * * @param decoratedAssignment * @param thrownTypesToExclude - * @param sourcePresenceChecker * @param existingVariableNames * @param targetType + * @param fieldAssignment */ public GetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment, List thrownTypesToExclude, - String sourcePresenceChecker, Set existingVariableNames, Type targetType, boolean fieldAssignment) { @@ -57,28 +54,10 @@ public class GetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd super( decoratedAssignment, thrownTypesToExclude, - sourcePresenceChecker, existingVariableNames, targetType, fieldAssignment ); } - /** - * constructor for e.g. constants and expressions - * - * @param decoratedAssignment - * @param thrownTypesToExclude - * @param existingVariableNames - * @param targetType - */ - public GetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment, - List thrownTypesToExclude, - Set existingVariableNames, - Type targetType, - boolean fieldAssignment) { - - super( decoratedAssignment, thrownTypesToExclude, null, existingVariableNames, targetType, fieldAssignment ); - } - } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.java index 785810e9c..937465d99 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.java @@ -25,14 +25,8 @@ package org.mapstruct.ap.internal.model.assignment; */ public class NullCheckWrapper extends AssignmentWrapper { - private final String sourcePresenceChecker; - - public NullCheckWrapper( Assignment decoratedAssignment, String sourcePresenceChecker ) { + public NullCheckWrapper( Assignment decoratedAssignment ) { super( decoratedAssignment, false ); - this.sourcePresenceChecker = sourcePresenceChecker; } - public String getSourcePresenceChecker() { - return sourcePresenceChecker; - } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.java index fdc9b039f..a97490a57 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.java @@ -47,7 +47,6 @@ public class SetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd public SetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment, List thrownTypesToExclude, - String sourcePresenceChecker, Set existingVariableNames, Type targetType, boolean allwaysIncludeNullCheck, @@ -57,7 +56,6 @@ public class SetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd super( decoratedAssignment, thrownTypesToExclude, - sourcePresenceChecker, existingVariableNames, targetType, fieldAssignment @@ -97,8 +95,4 @@ public class SetterWrapperForCollectionsAndMaps extends WrapperForCollectionsAnd return "java.util.EnumSet".equals( targetType.getFullyQualifiedName() ); } - public boolean isFieldAssignment() { - return fieldAssignment; - } - } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.java index d94082f63..c769f3658 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.java @@ -26,16 +26,8 @@ package org.mapstruct.ap.internal.model.assignment; */ public class UpdateNullCheckWrapper extends AssignmentWrapper { - private final String sourcePresenceChecker; - - public UpdateNullCheckWrapper(Assignment decoratedAssignment, String sourcePresenceChecker, - boolean fieldAssignment) { + public UpdateNullCheckWrapper(Assignment decoratedAssignment, boolean fieldAssignment) { super( decoratedAssignment, fieldAssignment ); - this.sourcePresenceChecker = sourcePresenceChecker; - } - - public String getSourcePresenceChecker() { - return sourcePresenceChecker; } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/WrapperForCollectionsAndMaps.java b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/WrapperForCollectionsAndMaps.java index 111b49a1d..a00a585e6 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/WrapperForCollectionsAndMaps.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/assignment/WrapperForCollectionsAndMaps.java @@ -35,13 +35,11 @@ import org.mapstruct.ap.internal.util.Strings; public class WrapperForCollectionsAndMaps extends AssignmentWrapper { private final List thrownTypesToExclude; - private final String sourcePresenceChecker; private final String localVarName; private final Type localVarType; public WrapperForCollectionsAndMaps(Assignment decoratedAssignment, List thrownTypesToExclude, - String sourcePresenceChecker, Set existingVariableNames, Type targetType, boolean fieldAssignment) { @@ -49,7 +47,6 @@ public class WrapperForCollectionsAndMaps extends AssignmentWrapper { super( decoratedAssignment, fieldAssignment ); this.thrownTypesToExclude = thrownTypesToExclude; - this.sourcePresenceChecker = sourcePresenceChecker; if ( getType() == AssignmentType.DIRECT && getSourceType() != null ) { this.localVarType = getSourceType(); } @@ -83,10 +80,6 @@ public class WrapperForCollectionsAndMaps extends AssignmentWrapper { return imported; } - public String getSourcePresenceChecker() { - return sourcePresenceChecker; - } - public String getLocalVarName() { return localVarName; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java index c55a52f80..c1a9b4fa8 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/SourceReference.java @@ -296,4 +296,25 @@ public class SourceReference { return new SourceReference( replacement, propertyEntries, isValid ); } + + @Override + public String toString() { + + if ( propertyEntries.isEmpty() ) { + return String.format( "parameter \"%s %s\"", getParameter().getType(), getParameter().getName() ); + } + else if ( propertyEntries.size() == 1 ) { + PropertyEntry propertyEntry = propertyEntries.get( 0 ); + return String.format( "property \"%s %s\"", propertyEntry.getType(), propertyEntry.getName() ); + } + else { + PropertyEntry lastPropertyEntry = propertyEntries.get( propertyEntries.size() - 1 ); + return String.format( + "property \"%s %s\"", + lastPropertyEntry.getType(), + Strings.join( getElementNames(), "." ) + ); + } + } + } 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 919d10013..4d6fe508a 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 @@ -104,10 +104,9 @@ public class MappingResolverImpl implements MappingResolver { } @Override - @SuppressWarnings("checkstyle:parameternumber") - public Assignment getTargetAssignment(Method mappingMethod, String mappedElement, - Type targetType, String targetPropertyName, FormattingParameters formattingParameters, - SelectionParameters selectionParameters, SourceRHS sourceRHS, boolean preferUpdateMapping) { + public Assignment getTargetAssignment(Method mappingMethod, Type targetType, String targetPropertyName, + FormattingParameters formattingParameters, SelectionParameters selectionParameters, SourceRHS sourceRHS, + boolean preferUpdateMapping) { SelectionCriteria criteria = new SelectionCriteria( selectionParameters, targetPropertyName, preferUpdateMapping, false ); @@ -122,14 +121,13 @@ public class MappingResolverImpl implements MappingResolver { ResolvingAttempt attempt = new ResolvingAttempt( sourceModel, mappingMethod, - mappedElement, dateFormat, numberFormat, sourceRHS, criteria ); - return attempt.getTargetAssignment( sourceRHS.getSourceType(), targetType ); + return attempt.getTargetAssignment( sourceRHS.getSourceTypeForMatching(), targetType ); } @Override @@ -143,7 +141,7 @@ public class MappingResolverImpl implements MappingResolver { SelectionCriteria criteria = new SelectionCriteria( selectionParameters, null, false, true ); - ResolvingAttempt attempt = new ResolvingAttempt( sourceModel, mappingMethod, null, null, null, null, criteria ); + ResolvingAttempt attempt = new ResolvingAttempt( sourceModel, mappingMethod, null, null, null, criteria ); List matchingSourceMethods = attempt.getMatches( sourceModel, null, targetType ); @@ -199,7 +197,6 @@ public class MappingResolverImpl implements MappingResolver { private class ResolvingAttempt { private final Method mappingMethod; - private final String mappedElement; private final List methods; private final String dateFormat; private final String numberFormat; @@ -212,12 +209,10 @@ public class MappingResolverImpl implements MappingResolver { // so this set must be cleared. private final Set virtualMethodCandidates; - private ResolvingAttempt(List sourceModel, Method mappingMethod, String mappedElement, - String dateFormat, String numberFormat, SourceRHS sourceRHS, SelectionCriteria criteria) { - + private ResolvingAttempt(List sourceModel, Method mappingMethod, String dateFormat, + String numberFormat, SourceRHS sourceRHS, SelectionCriteria criteria) { this.mappingMethod = mappingMethod; - this.mappedElement = mappedElement; this.methods = filterPossibleCandidateMethods( sourceModel ); this.dateFormat = dateFormat; this.numberFormat = numberFormat; @@ -520,10 +515,10 @@ public class MappingResolverImpl implements MappingResolver { // into the target type if ( candidates.size() > 1 ) { - if ( mappedElement != null ) { + if ( sourceRHS.getSourceErrorMessagePart() != null ) { messager.printMessage( mappingMethod.getExecutable(), Message.GENERAL_AMBIGIOUS_MAPPING_METHOD, - mappedElement, + sourceRHS.getSourceErrorMessagePart(), returnType, Strings.join( candidates, ", " ) ); 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 6b85e4712..fa454e92f 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 @@ -21,7 +21,7 @@ <#import "../macro/CommonMacros.ftl" as lib> <@lib.handleExceptions> if ( ${sourceReference} != null ) { - for ( <@includeModel object=sourceType/> ${sourceIteratorName} : ${sourceReference} ) { + for ( <@includeModel object=sourceType.typeParameters[0]/> ${sourceIteratorName} : ${sourceReference} ) { ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><@lib.handleAssignment/>; } } diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.ftl index 93a0d48c1..1f0037942 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/NullCheckWrapper.ftl @@ -25,7 +25,7 @@ if ( ${sourceLocalVarName} != null ) { <@_assignment object=assignment defaultValue=ext.defaultValueAssignment/> } <#else> -if ( <#if sourcePresenceChecker?? >${sourcePresenceChecker}<#else>${sourceReference} != null ) { +if ( <#if sourcePresenceCheckerReference?? >${sourcePresenceCheckerReference}<#else>${sourceReference} != null ) { <@_assignment object=assignment defaultValue=ext.defaultValueAssignment/> } diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.ftl index 5ce689042..f9bbbfe31 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/SetterWrapperForCollectionsAndMaps.ftl @@ -26,7 +26,7 @@ ${ext.targetBeanName}.${ext.targetReadAccessorName}.clear(); ${ext.targetBeanName}.${ext.targetReadAccessorName}.<#if ext.targetType.collectionType>addAll<#else>putAll( ${localVarName} ); - <#if !ext.defaultValueAssignment?? && !sourcePresenceChecker?? && !allwaysIncludeNullCheck>else {<#-- the opposite (defaultValueAssignment) case is handeld inside lib.handleNullCheck --> + <#if !ext.defaultValueAssignment?? && !sourcePresenceCheckerReference?? && !allwaysIncludeNullCheck>else {<#-- the opposite (defaultValueAssignment) case is handeld inside lib.handleNullCheck --> ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite>null; } @@ -55,4 +55,4 @@ <#else> new <#if ext.targetType.implementationType??><@includeModel object=ext.targetType.implementationType/><#else><@includeModel object=ext.targetType/>( ${localVarName} ) - + \ No newline at end of file diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.ftl index 0c7134bc4..1e87e687a 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/assignment/UpdateNullCheckWrapper.ftl @@ -19,7 +19,7 @@ --> <#import '../macro/CommonMacros.ftl' as lib> -if ( <#if sourcePresenceChecker?? >${sourcePresenceChecker}<#else>${sourceReference} != null ) { +if ( <#if sourcePresenceCheckerReference?? >${sourcePresenceCheckerReference}<#else>${sourceReference} != null ) { <@includeModel object=assignment targetBeanName=ext.targetBeanName existingInstanceMapping=ext.existingInstanceMapping diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl index 7501e0c15..060fcb513 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/macro/CommonMacros.ftl @@ -28,8 +28,8 @@ present. --> <#macro handleNullCheck> - <#if sourcePresenceChecker??> - if ( ${sourcePresenceChecker} ) { + <#if sourcePresenceCheckerReference??> + if ( ${sourcePresenceCheckerReference} ) { <@includeModel object=localVarType/> ${localVarName} = <@lib.handleAssignment/>; <#nested> }