diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java index 24e160b9d..0ea4ecd19 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java @@ -399,15 +399,13 @@ public class BeanMappingMethod extends NormalTypeMappingMethod { "SubclassMapping for " + sourceType.getFullyQualifiedName() ); SelectionCriteria criteria = SelectionCriteria - .forMappingMethods( + .forSubclassMappingMethods( new SelectionParameters( Collections.emptyList(), Collections.emptyList(), subclassMappingOptions.getTarget(), ctx.getTypeUtils() ).withSourceRHS( rightHandSide ), - subclassMappingOptions.getMappingControl( ctx.getElementUtils() ), - null, - false ); + subclassMappingOptions.getMappingControl( ctx.getElementUtils() ) ); Assignment assignment = ctx .getMappingResolver() .getTargetAssignment( diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/selector/SelectionCriteria.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/selector/SelectionCriteria.java index 7e12bbd18..2d288dd56 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/selector/SelectionCriteria.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/selector/SelectionCriteria.java @@ -149,6 +149,10 @@ public class SelectionCriteria { return allow2Steps; } + public boolean isSelfAllowed() { + return type != Type.SELF_NOT_ALLOWED; + } + public static SelectionCriteria forMappingMethods(SelectionParameters selectionParameters, MappingControl mappingControl, String targetPropertyName, boolean preferUpdateMapping) { @@ -173,10 +177,16 @@ public class SelectionCriteria { return new SelectionCriteria( selectionParameters, null, null, Type.PRESENCE_CHECK ); } + public static SelectionCriteria forSubclassMappingMethods(SelectionParameters selectionParameters, + MappingControl mappingControl) { + return new SelectionCriteria( selectionParameters, mappingControl, null, Type.SELF_NOT_ALLOWED ); + } + public enum Type { PREFER_UPDATE_MAPPING, OBJECT_FACTORY, LIFECYCLE_CALLBACK, PRESENCE_CHECK, + SELF_NOT_ALLOWED, } } 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 5a2af176f..12b345d23 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 @@ -196,7 +196,6 @@ public class MappingResolverImpl implements MappingResolver { this.mappingMethod = mappingMethod; this.description = description; - this.methods = filterPossibleCandidateMethods( sourceModel, mappingMethod ); this.formattingParameters = formattingParameters == null ? FormattingParameters.EMPTY : formattingParameters; this.sourceRHS = sourceRHS; @@ -207,13 +206,14 @@ public class MappingResolverImpl implements MappingResolver { this.builtIns = builtIns; this.messager = messager; this.reportingLimitAmbiguous = verboseLogging ? Integer.MAX_VALUE : LIMIT_REPORTING_AMBIGUOUS; + this.methods = filterPossibleCandidateMethods( sourceModel, mappingMethod ); } // CHECKSTYLE:ON private List filterPossibleCandidateMethods(List candidateMethods, T mappingMethod) { List result = new ArrayList<>( candidateMethods.size() ); for ( T candidate : candidateMethods ) { - if ( isCandidateForMapping( candidate ) && !candidate.equals( mappingMethod )) { + if ( isCandidateForMapping( candidate ) && isNotSelfOrSelfAllowed( mappingMethod, candidate )) { result.add( candidate ); } } @@ -221,6 +221,10 @@ public class MappingResolverImpl implements MappingResolver { return result; } + private boolean isNotSelfOrSelfAllowed(T mappingMethod, T candidate) { + return selectionCriteria == null || selectionCriteria.isSelfAllowed() || !candidate.equals( mappingMethod ); + } + private Assignment getTargetAssignment(Type sourceType, Type targetType) { Assignment assignment; diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_3057/Issue3057Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_3057/Issue3057Mapper.java new file mode 100644 index 000000000..d8c444d8c --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_3057/Issue3057Mapper.java @@ -0,0 +1,55 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.bugs._3057; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * @author Ben Zegveld + */ +@Mapper +public interface Issue3057Mapper { + + Issue3057Mapper INSTANCE = Mappers.getMapper( Issue3057Mapper.class ); + + class Source { + private Source self; + + public Source getSelf() { + return self; + } + + public void setSelf(Source self) { + this.self = self; + } + } + + class Target { + private Target self; + private String value; + + public Target getSelf() { + return self; + } + + public void setSelf(Target self) { + this.self = self; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + } + + @Mapping( target = "value", constant = "constantValue" ) + Target map(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_3057/Issue3057MapperTest.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_3057/Issue3057MapperTest.java new file mode 100644 index 000000000..7e64f529f --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_3057/Issue3057MapperTest.java @@ -0,0 +1,34 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.bugs._3057; + +import org.mapstruct.ap.test.bugs._3057.Issue3057Mapper.Source; +import org.mapstruct.ap.test.bugs._3057.Issue3057Mapper.Target; +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.ProcessorTest; +import org.mapstruct.ap.testutil.WithClasses; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Ben Zegveld + */ +@WithClasses(Issue3057Mapper.class) +@IssueKey("3057") +class Issue3057MapperTest { + + @ProcessorTest + void mapsSelf() { + Source sourceOuter = new Issue3057Mapper.Source(); + Source sourceInner = new Issue3057Mapper.Source(); + sourceOuter.setSelf( sourceInner ); + + Target targetOuter = Issue3057Mapper.INSTANCE.map( sourceOuter ); + + assertThat( targetOuter.getValue() ).isEqualTo( "constantValue" ); + assertThat( targetOuter.getSelf().getValue() ).isEqualTo( "constantValue" ); + } +}