#3057: limit do not allow self to subclassmappings. (#3063)

* #3057: limit do not allow self to subclassmappings.
* #3057: determine method candidates after all other fields are set in the constructor.

Co-authored-by: Ben Zegveld <Ben.Zegveld@gmail.com>
Co-authored-by: Filip Hrisafov <filip.hrisafov@gmail.com>
This commit is contained in:
Zegveld 2022-11-04 14:21:05 +01:00 committed by Filip Hrisafov
parent 60026437e4
commit 429cc3f914
5 changed files with 107 additions and 6 deletions

View File

@ -398,15 +398,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(

View File

@ -141,6 +141,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) {
@ -165,10 +169,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,
}
}

View File

@ -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 <T extends Method> List<T> filterPossibleCandidateMethods(List<T> candidateMethods, T mappingMethod) {
List<T> 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 <T extends Method> boolean isNotSelfOrSelfAllowed(T mappingMethod, T candidate) {
return selectionCriteria == null || selectionCriteria.isSelfAllowed() || !candidate.equals( mappingMethod );
}
private Assignment getTargetAssignment(Type sourceType, Type targetType) {
Assignment assignment;

View File

@ -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);
}

View File

@ -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" );
}
}