diff --git a/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java index 6e2640fa2..d8f342e56 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java @@ -90,7 +90,7 @@ public class BeanMappingMethod extends MappingMethod { public Builder souceMethod(SourceMethod sourceMethod) { this.method = sourceMethod; CollectionMappingStrategyPrism cms = sourceMethod.getMapperConfiguration().getCollectionMappingStrategy(); - Map accessors = method.getResultType().getTargetAccessors( cms ); + Map accessors = method.getResultType().getPropertyWriteAccessors( cms ); this.targetProperties = accessors.keySet(); this.unprocessedTargetProperties = new HashMap( accessors ); for ( Parameter sourceParameter : method.getSourceParameters() ) { @@ -237,8 +237,8 @@ public class BeanMappingMethod extends MappingMethod { PropertyMapping propertyMapping = null; // fetch the target property - ExecutableElement targetProperty = unprocessedTargetProperties.get( mapping.getTargetName() ); - if ( targetProperty == null ) { + ExecutableElement targetWriteAccessor = unprocessedTargetProperties.get( mapping.getTargetName() ); + if ( targetWriteAccessor == null ) { ctx.getMessager().printMessage( method.getExecutable(), mapping.getMirror(), @@ -277,14 +277,15 @@ public class BeanMappingMethod extends MappingMethod { SourceReference sourceRef = mapping.getSourceReference(); if ( sourceRef.isValid() ) { - if ( targetProperty != null ) { + if ( targetWriteAccessor != null ) { // targetProperty == null can occur: we arrived here because we want as many errors // as possible before we stop analysing propertyMapping = new PropertyMappingBuilder() .mappingContext( ctx ) .souceMethod( method ) - .targetAccessor( targetProperty ) + .targetWriteAccessor( targetWriteAccessor ) + .targetReadAccessor( getTargetPropertyReadAccessor( mapping.getTargetName() ) ) .targetPropertyName( mapping.getTargetName() ) .sourceReference( sourceRef ) .qualifiers( mapping.getQualifiers() ) @@ -303,13 +304,14 @@ public class BeanMappingMethod extends MappingMethod { } // its a constant - else if ( mapping.getConstant() != null && targetProperty != null ) { + else if ( mapping.getConstant() != null && targetWriteAccessor != null ) { propertyMapping = new ConstantMappingBuilder() .mappingContext( ctx ) .sourceMethod( method ) .constantExpression( "\"" + mapping.getConstant() + "\"" ) - .targetAccessor( targetProperty ) + .targetWriteAccessor( targetWriteAccessor ) + .targetReadAccessor( getTargetPropertyReadAccessor( mapping.getTargetName() ) ) .targetPropertyName( mapping.getTargetName() ) .dateFormat( mapping.getDateFormat() ) .qualifiers( mapping.getQualifiers() ) @@ -321,14 +323,15 @@ public class BeanMappingMethod extends MappingMethod { } // its an expression - else if ( mapping.getJavaExpression() != null && targetProperty != null ) { + else if ( mapping.getJavaExpression() != null && targetWriteAccessor != null ) { propertyMapping = new JavaExpressionMappingBuilder() .mappingContext( ctx ) .souceMethod( method ) .javaExpression( mapping.getJavaExpression() ) - .targetAccessor( targetProperty ) .existingVariableNames( existingVariableNames ) + .targetWriteAccessor( targetWriteAccessor ) + .targetReadAccessor( targetWriteAccessor ) .targetPropertyName( mapping.getTargetName() ) .dependsOn( mapping.getDependsOn() ) .build(); @@ -378,11 +381,13 @@ public class BeanMappingMethod extends MappingMethod { continue; } - for ( ExecutableElement sourceAccessor : sourceParameter.getType().getGetters() ) { - String sourcePropertyName = Executables.getPropertyName( sourceAccessor ); + Collection sourceReadAccessors = + sourceParameter.getType().getPropertyReadAccessors().values(); + for ( ExecutableElement sourceReadAccessor : sourceReadAccessors ) { + String sourcePropertyName = Executables.getPropertyName( sourceReadAccessor ); if ( sourcePropertyName.equals( targetProperty.getKey() ) ) { - candidates.add( sourceAccessor ); + candidates.add( sourceReadAccessor ); } } @@ -401,7 +406,8 @@ public class BeanMappingMethod extends MappingMethod { newPropertyMapping = new PropertyMappingBuilder() .mappingContext( ctx ) .souceMethod( method ) - .targetAccessor( targetProperty.getValue() ) + .targetWriteAccessor( targetProperty.getValue() ) + .targetReadAccessor( getTargetPropertyReadAccessor( targetProperty.getKey() ) ) .targetPropertyName( targetProperty.getKey() ) .sourceReference( sourceRef ) .qualifiers( mapping != null ? mapping.getQualifiers() : null ) @@ -464,7 +470,8 @@ public class BeanMappingMethod extends MappingMethod { PropertyMapping propertyMapping = new PropertyMappingBuilder() .mappingContext( ctx ) .souceMethod( method ) - .targetAccessor( targetProperty.getValue() ) + .targetWriteAccessor( targetProperty.getValue() ) + .targetReadAccessor( getTargetPropertyReadAccessor( targetProperty.getKey() ) ) .targetPropertyName( targetProperty.getKey() ) .sourceReference( sourceRef ) .qualifiers( mapping != null ? mapping.getQualifiers() : null ) @@ -510,6 +517,10 @@ public class BeanMappingMethod extends MappingMethod { } } + private ExecutableElement getTargetPropertyReadAccessor( String propertyName ) { + return method.getResultType().getPropertyReadAccessors().get( propertyName ); + } + /** * Returns the effective policy for reporting unmapped getReturnType properties. If explicitly set via * {@code Mapper}, this value will be returned. Otherwise the value from the corresponding processor option will 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 fee5b3857..f1bd587e7 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java +++ b/processor/src/main/java/org/mapstruct/ap/model/PropertyMapping.java @@ -61,7 +61,8 @@ public class PropertyMapping extends ModelElement { private final String name; private final String sourceBeanName; - private final String targetAccessorName; + private final String targetWriteAccessorName; + private final String targetReadAccessorName; private final Type targetType; private final Assignment assignment; private final List dependsOn; @@ -71,7 +72,8 @@ public class PropertyMapping extends ModelElement { // initial properties private MappingBuilderContext ctx; private SourceMethod method; - private ExecutableElement targetAccessor; + private ExecutableElement targetWriteAccessor; + private ExecutableElement targetReadAccessor; private String targetPropertyName; private String dateFormat; private List qualifiers; @@ -90,8 +92,13 @@ public class PropertyMapping extends ModelElement { return this; } - public PropertyMappingBuilder targetAccessor(ExecutableElement targetAccessor) { - this.targetAccessor = targetAccessor; + public PropertyMappingBuilder targetReadAccessor(ExecutableElement targetReadAccessor) { + this.targetReadAccessor = targetReadAccessor; + return this; + } + + public PropertyMappingBuilder targetWriteAccessor(ExecutableElement targetWriteAccessor) { + this.targetWriteAccessor = targetWriteAccessor; return this; } @@ -130,8 +137,7 @@ public class PropertyMapping extends ModelElement { return this; } - private enum TargetAccessorType { - + private enum TargetWriteAccessorType { GETTER, SETTER, ADDER @@ -140,18 +146,18 @@ public class PropertyMapping extends ModelElement { public PropertyMapping build() { // handle target - TargetAccessorType targetAccessorType = getTargetAcccessorType(); + TargetWriteAccessorType targetAccessorType = getTargetAcccessorType(); Type targetType = getTargetType( targetAccessorType ); // handle source String sourceElement = getSourceElement(); Type sourceType = getSourceType(); String sourceRefStr; - if ( targetAccessorType == TargetAccessorType.ADDER && sourceType.isCollectionType() ) { + if ( targetAccessorType == 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 ); - sourceRefStr = Executables.getElementNameForAdder( targetAccessor ); + sourceRefStr = Executables.getElementNameForAdder( targetWriteAccessor ); } else { sourceRefStr = getSourceRef(); @@ -208,19 +214,21 @@ public class PropertyMapping extends ModelElement { return new PropertyMapping( targetPropertyName, sourceReference.getParameter().getName(), - targetAccessor.getSimpleName().toString(), + targetWriteAccessor.getSimpleName().toString(), + targetReadAccessor != null ? targetReadAccessor.getSimpleName().toString() : null, targetType, assignment, dependsOn ); } - private Assignment assignObject(Type sourceType, Type targetType, TargetAccessorType targetAccessorType, + private Assignment assignObject(Type sourceType, Type targetType, TargetWriteAccessorType targetAccessorType, Assignment rhs) { Assignment result = rhs; - if ( targetAccessorType == TargetAccessorType.SETTER ) { + if ( targetAccessorType == TargetWriteAccessorType.SETTER ) { + result = new SetterWrapper( result, method.getThrownTypes() ); if ( !sourceType.isPrimitive() && !sourceReference.getPropertyEntries().isEmpty() /* parameter null taken care of by beanmapper */ @@ -252,12 +260,14 @@ public class PropertyMapping extends ModelElement { } - private Assignment assignCollection(Type targetType, TargetAccessorType targetAccessorType, Assignment rhs) { + private Assignment assignCollection(Type targetType, + TargetWriteAccessorType targetAccessorType, + Assignment rhs) { Assignment result = rhs; // wrap the setter in the collection / map initializers - if ( targetAccessorType == TargetAccessorType.SETTER ) { + if ( targetAccessorType == TargetWriteAccessorType.SETTER ) { // wrap the assignment in a new Map or Collection implementation if this is not done in a // mapping method. Note, typeconversons do not apply to collections or maps @@ -273,7 +283,7 @@ public class PropertyMapping extends ModelElement { // target accessor is setter, so wrap the setter in setter map/ collection handling result = new SetterWrapperForCollectionsAndMaps( result, - targetAccessor.getSimpleName().toString(), + targetWriteAccessor.getSimpleName().toString(), newCollectionOrMap ); } @@ -379,26 +389,26 @@ public class PropertyMapping extends ModelElement { } } - private TargetAccessorType getTargetAcccessorType() { - if ( Executables.isSetterMethod( targetAccessor ) ) { - return TargetAccessorType.SETTER; + private TargetWriteAccessorType getTargetAcccessorType() { + if ( Executables.isSetterMethod( targetWriteAccessor ) ) { + return TargetWriteAccessorType.SETTER; } - else if ( Executables.isAdderMethod( targetAccessor ) ) { - return TargetAccessorType.ADDER; + else if ( Executables.isAdderMethod( targetWriteAccessor ) ) { + return TargetWriteAccessorType.ADDER; } else { - return TargetAccessorType.GETTER; + return TargetWriteAccessorType.GETTER; } } - private Type getTargetType(TargetAccessorType targetAccessorType) { + private Type getTargetType(TargetWriteAccessorType targetAccessorType) { switch ( targetAccessorType ) { case ADDER: case SETTER: - return ctx.getTypeFactory().getSingleParameter( targetAccessor ).getType(); + return ctx.getTypeFactory().getSingleParameter( targetWriteAccessor ).getType(); case GETTER: default: - return ctx.getTypeFactory().getReturnType( targetAccessor ); + return ctx.getTypeFactory().getReturnType( targetWriteAccessor ); } } @@ -477,8 +487,9 @@ public class PropertyMapping extends ModelElement { private MappingBuilderContext ctx; private SourceMethod method; private String constantExpression; - private ExecutableElement targetAccessor; private String targetPropertyName; + private ExecutableElement targetWriteAccessor; + private ExecutableElement targetReadAccessor; private String dateFormat; private List qualifiers; private TypeMirror resultType; @@ -500,8 +511,13 @@ public class PropertyMapping extends ModelElement { return this; } - public ConstantMappingBuilder targetAccessor(ExecutableElement targetAccessor) { - this.targetAccessor = targetAccessor; + public ConstantMappingBuilder targetWriteAccessor(ExecutableElement targetAccessor) { + this.targetWriteAccessor = targetAccessor; + return this; + } + + public ConstantMappingBuilder targetReadAccessor(ExecutableElement targetReadAccessor) { + this.targetReadAccessor = targetReadAccessor; return this; } @@ -543,11 +559,11 @@ public class PropertyMapping extends ModelElement { // target Type targetType; - if ( Executables.isSetterMethod( targetAccessor ) ) { - targetType = ctx.getTypeFactory().getSingleParameter( targetAccessor ).getType(); + if ( Executables.isSetterMethod( targetWriteAccessor ) ) { + targetType = ctx.getTypeFactory().getSingleParameter( targetWriteAccessor ).getType(); } else { - targetType = ctx.getTypeFactory().getReturnType( targetAccessor ); + targetType = ctx.getTypeFactory().getReturnType( targetWriteAccessor ); } Assignment assignment = ctx.getMappingResolver().getTargetAssignment( @@ -564,7 +580,7 @@ public class PropertyMapping extends ModelElement { if ( assignment != null ) { - if ( Executables.isSetterMethod( targetAccessor ) ) { + if ( Executables.isSetterMethod( targetWriteAccessor ) ) { // target accessor is setter, so decorate assignment as setter assignment = new SetterWrapper( assignment, method.getThrownTypes() ); } @@ -591,7 +607,8 @@ public class PropertyMapping extends ModelElement { return new PropertyMapping( targetPropertyName, - targetAccessor.getSimpleName().toString(), + targetWriteAccessor.getSimpleName().toString(), + targetReadAccessor != null ? targetReadAccessor.getSimpleName().toString() : null, targetType, assignment, dependsOn @@ -604,10 +621,11 @@ public class PropertyMapping extends ModelElement { private MappingBuilderContext ctx; private SourceMethod method; private String javaExpression; - private ExecutableElement targetAccessor; private Collection existingVariableNames; private String targetPropertyName; private List dependsOn; + private ExecutableElement targetWriteAccessor; + private ExecutableElement targetReadAccessor; public JavaExpressionMappingBuilder mappingContext(MappingBuilderContext mappingContext) { this.ctx = mappingContext; @@ -624,8 +642,13 @@ public class PropertyMapping extends ModelElement { return this; } - public JavaExpressionMappingBuilder targetAccessor(ExecutableElement targetAccessor) { - this.targetAccessor = targetAccessor; + public JavaExpressionMappingBuilder targetWriteAccessor(ExecutableElement targetWriteAccessor) { + this.targetWriteAccessor = targetWriteAccessor; + return this; + } + + public JavaExpressionMappingBuilder targetReadAccessor(ExecutableElement targetReadAccessor) { + this.targetReadAccessor = targetReadAccessor; return this; } @@ -649,13 +672,13 @@ public class PropertyMapping extends ModelElement { Assignment assignment = AssignmentFactory.createDirect( javaExpression ); Type targetType; - if ( Executables.isSetterMethod( targetAccessor ) ) { + if ( Executables.isSetterMethod( targetWriteAccessor ) ) { // setter, so wrap in setter assignment = new SetterWrapper( assignment, method.getThrownTypes() ); - targetType = ctx.getTypeFactory().getSingleParameter( targetAccessor ).getType(); + targetType = ctx.getTypeFactory().getSingleParameter( targetWriteAccessor ).getType(); } else { - targetType = ctx.getTypeFactory().getReturnType( targetAccessor ); + targetType = ctx.getTypeFactory().getReturnType( targetWriteAccessor ); // target accessor is getter, so wrap the setter in getter map/ collection handling assignment = new GetterWrapperForCollectionsAndMaps( assignment, @@ -667,7 +690,8 @@ public class PropertyMapping extends ModelElement { return new PropertyMapping( targetPropertyName, - targetAccessor.getSimpleName().toString(), + targetWriteAccessor.getSimpleName().toString(), + targetReadAccessor != null ? targetReadAccessor.getSimpleName().toString() : null, targetType, assignment, dependsOn @@ -677,16 +701,18 @@ public class PropertyMapping extends ModelElement { } // Constructor for creating mappings of constant expressions. - private PropertyMapping(String name, String targetAccessorName, Type targetType, Assignment propertyAssignment, - List dependsOn) { - this( name, null, targetAccessorName, targetType, propertyAssignment, dependsOn ); + private PropertyMapping(String name, String targetWriteAccessorName, String targetReadAccessorName, Type targetType, + Assignment propertyAssignment, List dependsOn) { + this( name, null, targetWriteAccessorName, targetReadAccessorName, targetType, propertyAssignment, dependsOn ); } - private PropertyMapping(String name, String sourceBeanName, String targetAccessorName, Type targetType, - Assignment assignment, List dependsOn) { + private PropertyMapping(String name, String sourceBeanName, String targetWriteAccessorName, + String targetReadAccessorName, Type targetType, Assignment assignment, + List dependsOn) { this.name = name; this.sourceBeanName = sourceBeanName; - this.targetAccessorName = targetAccessorName; + this.targetWriteAccessorName = targetWriteAccessorName; + this.targetReadAccessorName = targetReadAccessorName; this.targetType = targetType; this.assignment = assignment; this.dependsOn = dependsOn != null ? dependsOn : Collections.emptyList(); @@ -703,8 +729,12 @@ public class PropertyMapping extends ModelElement { return sourceBeanName; } - public String getTargetAccessorName() { - return targetAccessorName; + public String getTargetWriteAccessorName() { + return targetWriteAccessorName; + } + + public String getTargetReadAccessorName() { + return targetReadAccessorName; } public Type getTargetType() { @@ -728,6 +758,8 @@ public class PropertyMapping extends ModelElement { public String toString() { return "PropertyMapping {" + "\n name='" + name + "\'," + + "\n targetWriteAccessorName='" + targetWriteAccessorName + "\'," + + "\n targetReadAccessorName='" + targetReadAccessorName + "\'," + "\n targetType=" + targetType + "," + "\n propertyAssignment=" + assignment + "," + "\n dependsOn=" + dependsOn 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 ef43f0baf..cda8d4722 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/TypeConversion.java +++ b/processor/src/main/java/org/mapstruct/ap/model/TypeConversion.java @@ -92,13 +92,13 @@ public class TypeConversion extends ModelElement implements Assignment { } @Override - public AssignmentType getType() { + public Assignment.AssignmentType getType() { switch ( assignment.getType() ) { case DIRECT: - return AssignmentType.TYPE_CONVERTED; + return Assignment.AssignmentType.TYPE_CONVERTED; case MAPPED: - return AssignmentType.MAPPED_TYPE_CONVERTED; + return Assignment.AssignmentType.MAPPED_TYPE_CONVERTED; default: return null; } diff --git a/processor/src/main/java/org/mapstruct/ap/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/model/common/Type.java index b4b680bab..5bb9da615 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/common/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/model/common/Type.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -81,8 +82,9 @@ public class Type extends ModelElement implements Comparable { private final List enumConstants; + private Map getters = null; + private List allExecutables = null; - private List getters = null; private List setters = null; private List adders = null; private List alternativeTargetAccessors = null; @@ -312,32 +314,38 @@ public class Type extends ModelElement implements Comparable { } /** - * getGetters + * getPropertyReadAccessors * - * @return an unmodifiable list of all getters (including 'is' for booleans). + * @return an unmodifiable map of all read accessors (including 'is' for booleans), indexed by property name */ - public List getGetters() { + public Map getPropertyReadAccessors() { if ( getters == null ) { - getters = Collections.unmodifiableList( Filters.getterMethodsIn( getAllExecutables() ) ); + List getterList = Filters.getterMethodsIn( getAllExecutables() ); + Map modifiableGetters = new LinkedHashMap(); + for (ExecutableElement getter : getterList) { + modifiableGetters.put( Executables.getPropertyName( getter ), getter ); + } + getters = Collections.unmodifiableMap( modifiableGetters ); } return getters; } /** - * getTargetAccessors returns a list of the target accessors according to the CollectionMappingStrategy. These - * accessors include: + * getPropertyWriteAccessors returns a map of the write accessors according to the CollectionMappingStrategy. + * + * These accessors include: *

*

    *
  • setters, the obvious candidate :-), {@link #getSetters() }
  • *
  • getters, for collections that do not have a setter, e.g. for JAXB generated collection attributes - * {@link #getGetters() }
  • + * {@link #getPropertyReadAccessors() } *
  • adders, typically for from table generated entities, {@link #getAdders() }
  • *
*

* @param cmStrategy - * @return an unmodifiable list of all getters (including 'is' for booleans). + * @return an unmodifiable map of all write accessors indexed by property name */ - public Map getTargetAccessors( CollectionMappingStrategyPrism cmStrategy ) { + public Map getPropertyWriteAccessors( CollectionMappingStrategyPrism cmStrategy ) { // collect all candidate target accessors List candidates = new ArrayList(); @@ -482,11 +490,12 @@ public class Type extends ModelElement implements Comparable { * @return an unmodifiable list of alternative target accessors. */ private List getAlternativeTargetAccessors() { + if ( alternativeTargetAccessors == null ) { List result = new ArrayList(); List setterMethods = getSetters(); - List getterMethods = getGetters(); + List getterMethods = new ArrayList( getPropertyReadAccessors().values() ); // there could be a getter method for a list/map that is not present as setter. // a getter could substitute the setter in that case and act as setter. diff --git a/processor/src/main/java/org/mapstruct/ap/model/source/Mapping.java b/processor/src/main/java/org/mapstruct/ap/model/source/Mapping.java index 493a5271f..7d81827b2 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/source/Mapping.java +++ b/processor/src/main/java/org/mapstruct/ap/model/source/Mapping.java @@ -266,7 +266,7 @@ public class Mapping { private boolean hasPropertyInReverseMethod(String name, SourceMethod method) { CollectionMappingStrategyPrism cms = method.getMapperConfiguration().getCollectionMappingStrategy(); - return method.getResultType().getTargetAccessors( cms ).containsKey( name ); + return method.getResultType().getPropertyWriteAccessors( cms ).containsKey( name ); } public Mapping reverse(SourceMethod method, FormattingMessager messager, TypeFactory typeFactory) { diff --git a/processor/src/main/java/org/mapstruct/ap/model/source/SourceReference.java b/processor/src/main/java/org/mapstruct/ap/model/source/SourceReference.java index 344c45f1b..2b1e91845 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/source/SourceReference.java +++ b/processor/src/main/java/org/mapstruct/ap/model/source/SourceReference.java @@ -21,13 +21,13 @@ package org.mapstruct.ap.model.source; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import javax.lang.model.element.ExecutableElement; import org.mapstruct.ap.model.common.Parameter; import org.mapstruct.ap.model.common.Type; import org.mapstruct.ap.model.common.TypeFactory; -import org.mapstruct.ap.util.Executables; import org.mapstruct.ap.util.FormattingMessager; import org.mapstruct.ap.util.Message; import org.mapstruct.ap.util.Strings; @@ -173,11 +173,11 @@ public class SourceReference { Type newType = type; for ( String entryName : entryNames ) { boolean matchFound = false; - List getters = newType.getGetters(); - for ( ExecutableElement getter : getters ) { - if ( Executables.getPropertyName( getter ).equals( entryName ) ) { - newType = typeFactory.getType( getter.getReturnType() ); - sourceEntries.add( new PropertyEntry( entryName, getter, newType ) ); + Map sourceReadAccessors = newType.getPropertyReadAccessors(); + for ( Map.Entry getter : sourceReadAccessors.entrySet() ) { + if ( getter.getKey().equals( entryName ) ) { + newType = typeFactory.getType( getter.getValue().getReturnType() ); + sourceEntries.add( new PropertyEntry( entryName, getter.getValue(), newType ) ); matchFound = true; break; } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl b/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl index 4f977789f..2777b97b8 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl @@ -57,7 +57,7 @@ break; } - <@includeModel object=elementAssignment targetAccessorName=resultName+"[${index1Name}]" targetType=resultElementType isTargetDefined=true/> + <@includeModel object=elementAssignment targetWriteAccessorName=resultName+"[${index1Name}]" targetType=resultElementType isTargetDefined=true/> ${index1Name}++; } <#else> @@ -69,7 +69,7 @@ for ( <@includeModel object=sourceElementType/> ${loopVariableName} : ${sourceParameter.name} ) { - <@includeModel object=elementAssignment targetBeanName=resultName targetAccessorName="add" targetType=resultElementType/> + <@includeModel object=elementAssignment targetBeanName=resultName targetWriteAccessorName="add" targetType=resultElementType/> } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl b/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl index 99869481c..56521af5f 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl @@ -43,11 +43,11 @@ for ( java.util.Map.Entry<<#list sourceParameter.type.typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, > ${entryVariableName} : ${sourceParameter.name}.entrySet() ) { <#-- key --> <@includeModel object=keyAssignment - targetAccessorName=keyVariableName + targetWriteAccessorName=keyVariableName targetType=resultType.typeParameters[0]/> <#-- value --> <@includeModel object=valueAssignment - targetAccessorName=valueVariableName + targetWriteAccessorName=valueVariableName targetType=resultType.typeParameters[1]/> ${resultName}.put( ${keyVariableName}, ${valueVariableName} ); } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.MethodReference.ftl b/processor/src/main/resources/org.mapstruct.ap.model.MethodReference.ftl index 99f42cb54..579b8367e 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.MethodReference.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.MethodReference.ftl @@ -26,12 +26,23 @@ <#if param.targetType> <#-- a class is passed on for casting, see @TargetType --> <@includeModel object=ext.targetType raw=true/>.class + <#elseif param.mappingTarget> + ${ext.targetBeanName}.${ext.targetReadAccessorName}() <#else> - <@includeModel object=assignment targetType=singleSourceParameterType raw=ext.raw/> + <@_assignment/> <#if param_has_next>, <#-- context parameter, e.g. for builtin methods concerning date conversion --> <#if contextParam??>, ${contextParam} + <#macro _assignment> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName=ext.targetWriteAccessorName + targetType=singleSourceParameterType/> + diff --git a/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl b/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl index 39f399c1d..60d98a0db 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.PropertyMapping.ftl @@ -22,5 +22,6 @@ targetBeanName=ext.targetBeanName raw=ext.raw existingInstanceMapping=ext.existingInstanceMapping - targetAccessorName=targetAccessorName + targetReadAccessorName=targetReadAccessorName + targetWriteAccessorName=targetWriteAccessorName targetType=targetType/> diff --git a/processor/src/main/resources/org.mapstruct.ap.model.TypeConversion.ftl b/processor/src/main/resources/org.mapstruct.ap.model.TypeConversion.ftl index 6f3cd260e..5a379c211 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.TypeConversion.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.TypeConversion.ftl @@ -18,4 +18,15 @@ limitations under the License. --> -${openExpression}<@includeModel object=assignment targetType=ext.targetType raw=ext.raw/>${closeExpression} \ No newline at end of file +<@compress single_line=true> +${openExpression}<@_assignment/>${closeExpression} +<#macro _assignment> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName=ext.targetWriteAccessorName + targetType=ext.targetType/> + + diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.AdderWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.AdderWrapper.ftl index 752628a4e..7eef49f5f 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.AdderWrapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.AdderWrapper.ftl @@ -20,21 +20,23 @@ --> <#if (exceptionTypes?size == 0) > for ( <@includeModel object=sourceType/> ${iteratorReference} : ${sourceReference} ) { - ${ext.targetBeanName}.${ext.targetAccessorName}( <@includeModel object=assignment + ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@includeModel object=assignment targetBeanName=ext.targetBeanName raw=ext.raw existingInstanceMapping=ext.existingInstanceMapping - targetAccessorName=ext.targetAccessorName + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName=ext.targetWriteAccessorName targetType=ext.targetType/> ); } <#else> try { for ( <@includeModel object=sourceType/> ${iteratorReference} : ${sourceReference} ) { - ${ext.targetBeanName}.${ext.targetAccessorName}( <@includeModel object=assignment + ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@includeModel object=assignment targetBeanName=ext.targetBeanName raw=ext.raw existingInstanceMapping=ext.existingInstanceMapping - targetAccessorName=ext.targetAccessorName + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName=ext.targetWriteAccessorName targetType=ext.targetType/> ); } } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.ArrayCopyWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.ArrayCopyWrapper.ftl index 12399b726..218f27a80 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.ArrayCopyWrapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.ArrayCopyWrapper.ftl @@ -20,11 +20,11 @@ --> <#if (exceptionTypes?size == 0) > <@includeModel object=ext.targetType/> ${localVarName} = <@_assignment/>; - ${ext.targetBeanName}.${ext.targetAccessorName}( Arrays.copyOf( ${localVarName}, ${localVarName}.length ) ); + ${ext.targetBeanName}.${ext.targetWriteAccessorName}( Arrays.copyOf( ${localVarName}, ${localVarName}.length ) ); <#else> try { <@includeModel object=ext.targetType/> ${localVarName} = <@_assignment/>; - ${ext.targetBeanName}.${ext.targetAccessorName}( Arrays.copyOf( ${localVarName}, ${localVarName}.length ) ); + ${ext.targetBeanName}.${ext.targetWriteAccessorName}( Arrays.copyOf( ${localVarName}, ${localVarName}.length ) ); } <#list exceptionTypes as exceptionType> catch ( <@includeModel object=exceptionType/> e ) { @@ -33,5 +33,11 @@ <#macro _assignment> - <@includeModel object=assignment raw=ext.raw targetType=ext.targetType/> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName=ext.targetWriteAccessorName + targetType=ext.targetType/> \ No newline at end of file diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.GetterWrapperForCollectionsAndMaps.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.GetterWrapperForCollectionsAndMaps.ftl index 807dd5ae7..16a866418 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.GetterWrapperForCollectionsAndMaps.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.GetterWrapperForCollectionsAndMaps.ftl @@ -18,9 +18,9 @@ limitations under the License. --> -if ( ${ext.targetBeanName}.${ext.targetAccessorName}() != null ) { +if ( ${ext.targetBeanName}.${ext.targetWriteAccessorName}() != null ) { <#if ext.existingInstanceMapping> - ${ext.targetBeanName}.${ext.targetAccessorName}().clear(); + ${ext.targetBeanName}.${ext.targetWriteAccessorName}().clear(); <#if (exceptionTypes?size == 0) > <@_assignmentLine/> @@ -38,7 +38,7 @@ if ( ${ext.targetBeanName}.${ext.targetAccessorName}() != null ) { <#macro _assignmentLine> <@includeModel object=ext.targetType/> ${localVarName} = <@_assignment/>; if ( ${localVarName} != null ) { - ${ext.targetBeanName}.${ext.targetAccessorName}().<#if ext.targetType.collectionType>addAll<#else>putAll( ${localVarName} ); + ${ext.targetBeanName}.${ext.targetWriteAccessorName}().<#if ext.targetType.collectionType>addAll<#else>putAll( ${localVarName} ); } <#macro _assignment> @@ -49,4 +49,4 @@ if ( ${ext.targetBeanName}.${ext.targetAccessorName}() != null ) { targetReadAccessorName=ext.targetReadAccessorName targetWriteAccessorName=ext.targetWriteAccessorName targetType=ext.targetType/> - \ No newline at end of file + diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.LocalVarWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.LocalVarWrapper.ftl index b853f824d..973519746 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.LocalVarWrapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.LocalVarWrapper.ftl @@ -19,11 +19,11 @@ --> <#if (exceptionTypes?size == 0) > - <#if !ext.isTargetDefined?? ><@includeModel object=ext.targetType/> ${ext.targetAccessorName} = <@includeModel object=assignment targetType=ext.targetType raw=ext.raw/>; + <#if !ext.isTargetDefined?? ><@includeModel object=ext.targetType/> ${ext.targetWriteAccessorName} = <@_assignment/>; <#else> - <#if !ext.isTargetDefined?? ><@includeModel object=ext.targetType/> ${ext.targetAccessorName}; + <#if !ext.isTargetDefined?? ><@includeModel object=ext.targetType/> ${ext.targetWriteAccessorName}; try { - ${ext.targetAccessorName} = <@includeModel object=assignment targetType=ext.targetType raw=ext.raw/>; + ${ext.targetWriteAccessorName} = <@_assignment/>; } <#list exceptionTypes as exceptionType> catch ( <@includeModel object=exceptionType/> e ) { @@ -31,3 +31,12 @@ } +<#macro _assignment> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName=ext.targetWriteAccessorName + targetType=ext.targetType/> + \ No newline at end of file diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper.ftl index f9009c3ec..1f87d64a0 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper.ftl @@ -24,5 +24,5 @@ new <#if ext.targetType.implementationType??> <#else> <@includeModel object=ext.targetType/> -( <@includeModel object=assignment targetBeanName=ext.targetBeanName targetAccessorName=ext.targetAccessorName targetType=ext.targetType raw=ext.raw/> ) +( <@includeModel object=assignment targetBeanName=ext.targetBeanName targetReadAccessorName=ext.targetReadAccessorName targetWriteAccessorName=ext.targetWriteAccessorName targetType=ext.targetType raw=ext.raw/> ) \ No newline at end of file diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.NullCheckWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.NullCheckWrapper.ftl index 780e2cf11..b98c50e65 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.NullCheckWrapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.NullCheckWrapper.ftl @@ -23,6 +23,7 @@ if ( ${sourceReference} != null ) { targetBeanName=ext.targetBeanName raw=ext.raw existingInstanceMapping=ext.existingInstanceMapping - targetAccessorName=ext.targetAccessorName + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName=ext.targetWriteAccessorName targetType=ext.targetType/> } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapper.ftl index e5f76c26e..53643df1b 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapper.ftl @@ -19,10 +19,10 @@ --> <#if (exceptionTypes?size == 0) > - ${ext.targetBeanName}.${ext.targetAccessorName}( <@_assignment/> ); + ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@_assignment/> ); <#else> try { - ${ext.targetBeanName}.${ext.targetAccessorName}( <@_assignment/> ); + ${ext.targetBeanName}.${ext.targetWriteAccessorName}( <@_assignment/> ); } <#list exceptionTypes as exceptionType> catch ( <@includeModel object=exceptionType/> e ) { @@ -31,5 +31,11 @@ <#macro _assignment> - <@includeModel object=assignment raw=ext.raw targetType=ext.targetType/> + <@includeModel object=assignment + targetBeanName=ext.targetBeanName + raw=ext.raw + existingInstanceMapping=ext.existingInstanceMapping + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName=ext.targetWriteAccessorName + targetType=ext.targetType/> \ No newline at end of file diff --git a/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapperForCollectionsAndMaps.ftl b/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapperForCollectionsAndMaps.ftl index 9e6769e06..920396ec5 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapperForCollectionsAndMaps.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.assignment.SetterWrapperForCollectionsAndMaps.ftl @@ -26,14 +26,16 @@ targetBeanName=ext.targetBeanName raw=ext.raw existingInstanceMapping=ext.existingInstanceMapping - targetAccessorName="${targetGetterName}().addAll" + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName="${targetGetterName}().addAll" targetType=ext.targetType/> <#else> <@includeModel object=assignment targetBeanName=ext.targetBeanName raw=ext.raw existingInstanceMapping=ext.existingInstanceMapping - targetAccessorName="${targetGetterName}().putAll" + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName="${targetGetterName}().putAll" targetType=ext.targetType/> } @@ -56,7 +58,8 @@ targetBeanName=ext.targetBeanName raw=ext.raw existingInstanceMapping=ext.existingInstanceMapping - targetAccessorName=ext.targetAccessorName + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName=ext.targetWriteAccessorName targetType=ext.targetType/> <#macro _newCollectionOrMapAssignment> @@ -64,6 +67,7 @@ targetBeanName=ext.targetBeanName raw=ext.raw existingInstanceMapping=ext.existingInstanceMapping - targetAccessorName=ext.targetAccessorName + targetReadAccessorName=ext.targetReadAccessorName + targetWriteAccessorName=ext.targetWriteAccessorName targetType=ext.targetType/> \ No newline at end of file