#2156 ambiguous mapping message: location and limit # candidates (#2162)

This commit is contained in:
Sjaak Derksen 2020-07-19 15:40:30 +02:00 committed by GitHub
parent cb432fa61b
commit 36349c49e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 287 additions and 56 deletions

View File

@ -27,6 +27,8 @@ public abstract class AbstractMappingMethodBuilder<B extends AbstractMappingMeth
public abstract M build();
private ForgedMethodHistory description;
/**
* @return {@code true} if property names should be used for the creation of the {@link ForgedMethodHistory}.
*/
@ -44,7 +46,7 @@ public abstract class AbstractMappingMethodBuilder<B extends AbstractMappingMeth
history = ( (ForgedMethod) method ).getHistory();
}
ForgedMethodHistory forgedHistory = new ForgedMethodHistory(
description = new ForgedMethodHistory(
history,
Strings.stubPropertyName( sourceRHS.getSourceType().getName() ),
Strings.stubPropertyName( targetType.getName() ),
@ -53,7 +55,7 @@ public abstract class AbstractMappingMethodBuilder<B extends AbstractMappingMeth
shouldUsePropertyNamesInHistory(),
sourceRHS.getSourceErrorMessagePart() );
ForgedMethod forgedMethod = forElementMapping( name, sourceType, targetType, method, forgedHistory, true );
ForgedMethod forgedMethod = forElementMapping( name, sourceType, targetType, method, description, true );
BuilderGem builder = method.getOptions().getBeanMapping().getBuilder();
return createForgedAssignment(
@ -77,4 +79,9 @@ public abstract class AbstractMappingMethodBuilder<B extends AbstractMappingMeth
builder.append( type.getIdentification() );
return builder.toString();
}
public ForgedMethodHistory getDescription() {
return description;
}
}

View File

@ -62,7 +62,7 @@ import static org.mapstruct.ap.internal.util.Collections.first;
import static org.mapstruct.ap.internal.util.Message.BEANMAPPING_ABSTRACT;
import static org.mapstruct.ap.internal.util.Message.BEANMAPPING_NOT_ASSIGNABLE;
import static org.mapstruct.ap.internal.util.Message.GENERAL_ABSTRACT_RETURN_TYPE;
import static org.mapstruct.ap.internal.util.Message.GENERAL_AMBIGIOUS_CONSTRUCTORS;
import static org.mapstruct.ap.internal.util.Message.GENERAL_AMBIGUOUS_CONSTRUCTORS;
import static org.mapstruct.ap.internal.util.Message.GENERAL_CONSTRUCTOR_PROPERTIES_NOT_MATCHING_PARAMETERS;
/**
@ -569,7 +569,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
else {
ctx.getMessager().printMessage(
method.getExecutable(),
Message.GENERAL_AMBIGIOUS_FACTORY_METHOD,
Message.GENERAL_AMBIGUOUS_FACTORY_METHOD,
returnTypeImpl,
Strings.join( matchingFactoryMethods, ", " )
);
@ -665,7 +665,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
ctx.getMessager().printMessage(
method.getExecutable(),
GENERAL_AMBIGIOUS_CONSTRUCTORS,
GENERAL_AMBIGUOUS_CONSTRUCTORS,
type,
Strings.join( constructors, ", " )
);

View File

@ -83,6 +83,7 @@ public abstract class ContainerMappingMethodBuilder<B extends ContainerMappingMe
);
Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method,
getDescription(),
targetElementType,
formattingParameters,
criteria,

View File

@ -96,6 +96,7 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
Assignment keyAssignment = ctx.getMappingResolver().getTargetAssignment(
method,
getDescription(),
keyTargetType,
keyFormattingParameters,
keyCriteria,
@ -142,6 +143,7 @@ public class MapMappingMethod extends NormalTypeMappingMethod {
Assignment valueAssignment = ctx.getMappingResolver().getTargetAssignment(
method,
getDescription(),
valueTargetType,
valueFormattingParameters,
valueCriteria,

View File

@ -78,6 +78,7 @@ public class MappingBuilderContext {
* returns a parameter assignment
*
* @param mappingMethod target mapping method
* @param description
* @param targetType return type to match
* @param formattingParameters used for formatting dates and numbers
* @param criteria parameters criteria in the selection process
@ -92,7 +93,7 @@ public class MappingBuilderContext {
* <li>null, no assignment found</li>
* </ol>
*/
Assignment getTargetAssignment(Method mappingMethod, Type targetType,
Assignment getTargetAssignment(Method mappingMethod, ForgedMethodHistory description, Type targetType,
FormattingParameters formattingParameters,
SelectionCriteria criteria, SourceRHS sourceRHS,
AnnotationMirror positionHint,

View File

@ -81,7 +81,7 @@ public class ObjectFactoryMethodResolver {
if ( matchingFactoryMethods.size() > 1 ) {
ctx.getMessager().printMessage(
method.getExecutable(),
Message.GENERAL_AMBIGIOUS_FACTORY_METHOD,
Message.GENERAL_AMBIGUOUS_FACTORY_METHOD,
alternativeTarget,
Strings.join( matchingFactoryMethods, ", " ) );

View File

@ -242,6 +242,7 @@ public class PropertyMapping extends ModelElement {
if ( forgeMethodWithMappingReferences == null ) {
assignment = ctx.getMappingResolver().getTargetAssignment(
method,
getForgedMethodHistory( rightHandSide ),
targetType,
formattingParameters,
criteria,
@ -791,6 +792,7 @@ public class PropertyMapping extends ModelElement {
if ( !targetType.isEnumType() ) {
assignment = ctx.getMappingResolver().getTargetAssignment(
method,
null, // TODO description for constant
targetType,
formattingParameters,
criteria,

View File

@ -39,6 +39,7 @@ import org.mapstruct.ap.internal.conversion.ConversionProvider;
import org.mapstruct.ap.internal.conversion.Conversions;
import org.mapstruct.ap.internal.gem.ReportingPolicyGem;
import org.mapstruct.ap.internal.model.Field;
import org.mapstruct.ap.internal.model.ForgedMethodHistory;
import org.mapstruct.ap.internal.model.HelperMethod;
import org.mapstruct.ap.internal.model.MapperReference;
import org.mapstruct.ap.internal.model.MappingBuilderContext.MappingResolver;
@ -74,6 +75,8 @@ import org.mapstruct.ap.internal.util.Strings;
*/
public class MappingResolverImpl implements MappingResolver {
private static final int MAX_REPORTING_AMBIGUOUS = 5;
private final FormattingMessager messager;
private final Types typeUtils;
private final TypeFactory typeFactory;
@ -109,7 +112,7 @@ public class MappingResolverImpl implements MappingResolver {
}
@Override
public Assignment getTargetAssignment(Method mappingMethod, Type targetType,
public Assignment getTargetAssignment(Method mappingMethod, ForgedMethodHistory description, Type targetType,
FormattingParameters formattingParameters,
SelectionCriteria criteria, SourceRHS sourceRHS,
AnnotationMirror positionHint,
@ -118,6 +121,7 @@ public class MappingResolverImpl implements MappingResolver {
ResolvingAttempt attempt = new ResolvingAttempt(
sourceModel,
mappingMethod,
description,
formattingParameters,
sourceRHS,
criteria,
@ -149,6 +153,7 @@ public class MappingResolverImpl implements MappingResolver {
private class ResolvingAttempt {
private final Method mappingMethod;
private final ForgedMethodHistory description;
private final List<Method> methods;
private final SelectionCriteria selectionCriteria;
private final SourceRHS sourceRHS;
@ -163,7 +168,7 @@ public class MappingResolverImpl implements MappingResolver {
// so this set must be cleared.
private final Set<SupportingMappingMethod> supportingMethodCandidates;
private ResolvingAttempt(List<Method> sourceModel, Method mappingMethod,
private ResolvingAttempt(List<Method> sourceModel, Method mappingMethod, ForgedMethodHistory description,
FormattingParameters formattingParameters, SourceRHS sourceRHS,
SelectionCriteria criteria,
AnnotationMirror positionHint,
@ -172,6 +177,7 @@ public class MappingResolverImpl implements MappingResolver {
FormattingMessager messager) {
this.mappingMethod = mappingMethod;
this.description = description;
this.methods = filterPossibleCandidateMethods( sourceModel );
this.formattingParameters =
formattingParameters == null ? FormattingParameters.EMPTY : formattingParameters;
@ -202,7 +208,7 @@ public class MappingResolverImpl implements MappingResolver {
// first simple mapping method
if ( allowMappingMethod() ) {
List<SelectedMethod<Method>> matches = getBestMatch( methods, sourceType, targetType );
reportErrorWhenAmbigious( matches, targetType );
reportErrorWhenAmbiguous( matches, targetType );
if ( !matches.isEmpty() ) {
assignment = toMethodRef( first( matches ) );
assignment.setAssignment( sourceRHS );
@ -246,7 +252,7 @@ public class MappingResolverImpl implements MappingResolver {
// check for a built-in method
if ( !hasQualfiers() ) {
List<SelectedMethod<BuiltInMethod>> matches = getBestMatch( builtIns, sourceType, targetType );
reportErrorWhenAmbigious( matches, targetType );
reportErrorWhenAmbiguous( matches, targetType );
if ( !matches.isEmpty() ) {
assignment = toBuildInRef( first( matches ) );
assignment.setAssignment( sourceRHS );
@ -443,29 +449,37 @@ public class MappingResolverImpl implements MappingResolver {
);
}
private <T extends Method> void reportErrorWhenAmbigious(List<SelectedMethod<T>> candidates, Type target) {
private <T extends Method> void reportErrorWhenAmbiguous(List<SelectedMethod<T>> candidates, Type target) {
// raise an error if more than one mapping method is suitable to map the given source type
// into the target type
if ( candidates.size() > 1 ) {
String descriptionStr = "";
if ( description != null ) {
descriptionStr = description.createSourcePropertyErrorMessage();
}
else {
descriptionStr = sourceRHS.getSourceErrorMessagePart();
}
if ( sourceRHS.getSourceErrorMessagePart() != null ) {
messager.printMessage(
mappingMethod.getExecutable(),
positionHint,
Message.GENERAL_AMBIGIOUS_MAPPING_METHOD,
sourceRHS.getSourceErrorMessagePart(),
Message.GENERAL_AMBIGUOUS_MAPPING_METHOD,
descriptionStr,
target,
Strings.join( candidates, ", " )
join( candidates )
);
}
else {
messager.printMessage(
mappingMethod.getExecutable(),
positionHint,
Message.GENERAL_AMBIGIOUS_FACTORY_METHOD,
Message.GENERAL_AMBIGUOUS_FACTORY_METHOD,
target,
Strings.join( candidates, ", " )
join( candidates )
);
}
}
@ -578,6 +592,18 @@ public class MappingResolverImpl implements MappingResolver {
return false;
}
private <T extends Method> String join( List<SelectedMethod<T>> candidates ) {
String candidateStr = candidates.stream()
.limit( MAX_REPORTING_AMBIGUOUS )
.map( m -> m.getMethod().shortName() )
.collect( Collectors.joining( ", " ) );
if ( candidates.size() > MAX_REPORTING_AMBIGUOUS ) {
candidateStr += String.format( "... and %s more", candidates.size() - MAX_REPORTING_AMBIGUOUS );
}
return candidateStr;
}
}
private static class ConversionAssignment {
@ -762,28 +788,26 @@ public class MappingResolverImpl implements MappingResolver {
result = methodRefY;
}
else {
reportAmbigiousError( xCandidates, targetType );
reportAmbiguousError( xCandidates, targetType );
}
return this;
}
void reportAmbigiousError(Map<SelectedMethod<T1>, List<SelectedMethod<T2>>> xCandidates, Type target) {
void reportAmbiguousError(Map<SelectedMethod<T1>, List<SelectedMethod<T2>>> xCandidates, Type target) {
StringBuilder result = new StringBuilder();
xCandidates.entrySet()
.stream()
.limit( MAX_REPORTING_AMBIGUOUS )
.forEach( e -> result.append( "method(s)Y: " )
.append( e.getValue()
.stream()
.map( v -> v.getMethod().shortName() )
.collect( Collectors.joining( ", " ) ) )
.append( attempt.join( e.getValue() ) )
.append( ", methodX: " )
.append( e.getKey().getMethod().shortName() )
.append( "; " ) );
attempt.messager.printMessage(
attempt.mappingMethod.getExecutable(),
attempt.positionHint,
Message.GENERAL_AMBIGIOUS_MAPPING_METHODY_METHODX,
Message.GENERAL_AMBIGUOUS_MAPPING_METHODY_METHODX,
attempt.sourceRHS.getSourceType().getName() + " " + attempt.sourceRHS.getSourceParameterName(),
target.getName(),
result.toString() );
@ -878,28 +902,26 @@ public class MappingResolverImpl implements MappingResolver {
result = methodRefY;
}
else {
reportAmbigiousError( xRefCandidates, targetType );
reportAmbiguousError( xRefCandidates, targetType );
}
return this;
}
void reportAmbigiousError(Map<ConversionAssignment, List<SelectedMethod<T>>> xRefCandidates, Type target) {
void reportAmbiguousError(Map<ConversionAssignment, List<SelectedMethod<T>>> xRefCandidates, Type target) {
StringBuilder result = new StringBuilder();
xRefCandidates.entrySet()
.stream()
.limit( MAX_REPORTING_AMBIGUOUS )
.forEach( e -> result.append( "method(s)Y: " )
.append( e.getValue()
.stream()
.map( v -> v.getMethod().shortName() )
.collect( Collectors.joining( ", " ) ) )
.append( attempt.join( e.getValue() ) )
.append( ", conversionX: " )
.append( e.getKey().shortName() )
.append( "; " ) );
attempt.messager.printMessage(
attempt.mappingMethod.getExecutable(),
attempt.positionHint,
Message.GENERAL_AMBIGIOUS_MAPPING_METHODY_CONVERSIONX,
Message.GENERAL_AMBIGUOUS_MAPPING_METHODY_CONVERSIONX,
attempt.sourceRHS.getSourceType().getName() + " " + attempt.sourceRHS.getSourceParameterName(),
target.getName(),
result.toString() );
@ -997,28 +1019,26 @@ public class MappingResolverImpl implements MappingResolver {
result = conversionRefY.assignment;
}
else {
reportAmbigiousError( yRefCandidates, targetType );
reportAmbiguousError( yRefCandidates, targetType );
}
return this;
}
void reportAmbigiousError(Map<ConversionAssignment, List<SelectedMethod<T>>> yRefCandidates, Type target) {
void reportAmbiguousError(Map<ConversionAssignment, List<SelectedMethod<T>>> yRefCandidates, Type target) {
StringBuilder result = new StringBuilder();
yRefCandidates.entrySet()
.stream()
.limit( MAX_REPORTING_AMBIGUOUS )
.forEach( e -> result.append( "conversionY: " )
.append( e.getKey().shortName() )
.append( ", method(s)X: " )
.append( e.getValue()
.stream()
.map( v -> v.getMethod().shortName() )
.collect( Collectors.joining( ", " ) ) )
.append( attempt.join( e.getValue() ) )
.append( "; " ) );
attempt.messager.printMessage(
attempt.mappingMethod.getExecutable(),
attempt.positionHint,
Message.GENERAL_AMBIGIOUS_MAPPING_CONVERSIONY_METHODX,
Message.GENERAL_AMBIGUOUS_MAPPING_CONVERSIONY_METHODX,
attempt.sourceRHS.getSourceType().getName() + " " + attempt.sourceRHS.getSourceParameterName(),
target.getName(),
result.toString() );

View File

@ -7,6 +7,7 @@ package org.mapstruct.ap.internal.util;
import javax.tools.Diagnostic;
import static org.mapstruct.ap.internal.util.MessageConstants.FAQ_AMBIGUOUS_URL;
import static org.mapstruct.ap.internal.util.MessageConstants.FAQ_QUALIFIER_URL;
/**
@ -111,9 +112,9 @@ public enum Message {
GENERAL_NO_IMPLEMENTATION( "No implementation type is registered for return type %s." ),
GENERAL_ABSTRACT_RETURN_TYPE( "The return type %s is an abstract class or interface. Provide a non abstract / non interface result type or a factory method." ),
GENERAL_AMBIGIOUS_MAPPING_METHOD( "Ambiguous mapping methods found for mapping %s to %s: %s." ),
GENERAL_AMBIGIOUS_FACTORY_METHOD( "Ambiguous factory methods found for creating %s: %s." ),
GENERAL_AMBIGIOUS_CONSTRUCTORS( "Ambiguous constructors found for creating %s. Either declare parameterless constructor or annotate the default constructor with an annotation named @Default." ),
GENERAL_AMBIGUOUS_MAPPING_METHOD( "Ambiguous mapping methods found for mapping %s to %s: %s. See " + FAQ_AMBIGUOUS_URL + " for more info." ),
GENERAL_AMBIGUOUS_FACTORY_METHOD( "Ambiguous factory methods found for creating %s: %s. See " + FAQ_AMBIGUOUS_URL + " for more info." ),
GENERAL_AMBIGUOUS_CONSTRUCTORS( "Ambiguous constructors found for creating %s. Either declare parameterless constructor or annotate the default constructor with an annotation named @Default." ),
GENERAL_CONSTRUCTOR_PROPERTIES_NOT_MATCHING_PARAMETERS( "Incorrect @ConstructorProperties for %s. The size of the @ConstructorProperties does not match the number of constructor parameters" ),
GENERAL_UNSUPPORTED_DATE_FORMAT_CHECK( "No dateFormat check is supported for types %s, %s" ),
GENERAL_VALID_DATE( "Given date format \"%s\" is valid.", Diagnostic.Kind.NOTE ),
@ -125,9 +126,9 @@ public enum Message {
GENERAL_NO_QUALIFYING_METHOD_NAMED( "Qualifier error. No method found annotated with @Named#value: [ %s ]. See " + FAQ_QUALIFIER_URL + " for more info." ),
GENERAL_NO_QUALIFYING_METHOD_COMBINED( "Qualifier error. No method found annotated with @Named#value: [ %s ], annotated with [ %s ]. See " + FAQ_QUALIFIER_URL + " for more info." ),
GENERAL_AMBIGIOUS_MAPPING_METHODY_METHODX( "Ambiguous 2step methods found, mapping %s to %s. Found methodY( methodX ( parameter ) ): %s." ),
GENERAL_AMBIGIOUS_MAPPING_CONVERSIONY_METHODX( "Ambiguous 2step methods found, mapping %s to %s. Found conversionY( methodX ( parameter ) ): %s." ),
GENERAL_AMBIGIOUS_MAPPING_METHODY_CONVERSIONX( "Ambiguous 2step methods found, mapping %s to %s. Found methodY( conversionX ( parameter ) ): %s." ),
GENERAL_AMBIGUOUS_MAPPING_METHODY_METHODX( "Ambiguous 2step methods found, mapping %s to %s. Found methodY( methodX ( parameter ) ): %s." ),
GENERAL_AMBIGUOUS_MAPPING_CONVERSIONY_METHODX( "Ambiguous 2step methods found, mapping %s to %s. Found conversionY( methodX ( parameter ) ): %s." ),
GENERAL_AMBIGUOUS_MAPPING_METHODY_CONVERSIONX( "Ambiguous 2step methods found, mapping %s to %s. Found methodY( conversionX ( parameter ) ): %s." ),
BUILDER_MORE_THAN_ONE_BUILDER_CREATION_METHOD( "More than one builder creation method for \"%s\". Found methods: \"%s\". Builder will not be used. Consider implementing a custom BuilderProvider SPI.", Diagnostic.Kind.WARNING ),
BUILDER_NO_BUILD_METHOD_FOUND("No build method \"%s\" found in \"%s\" for \"%s\". Found methods: \"%s\".", Diagnostic.Kind.ERROR ),

View File

@ -9,6 +9,7 @@ public final class MessageConstants {
public static final String AND = " and ";
public static final String FAQ_QUALIFIER_URL = "https://mapstruct.org/faq/#qualifier";
public static final String FAQ_AMBIGUOUS_URL = "https://mapstruct.org/faq/#ambiguous";
private MessageConstants() {
}

View File

@ -65,7 +65,8 @@ public class Issue1242Test {
".lang.Class<org.mapstruct.ap.test.bugs._1242.TargetB> clazz), org.mapstruct.ap.test.bugs._1242" +
".TargetB org.mapstruct.ap.test.bugs._1242.TargetFactories.createTargetB(@TargetType java.lang" +
".Class<org.mapstruct.ap.test.bugs._1242.TargetB> clazz), org.mapstruct.ap.test.bugs._1242" +
".TargetB org.mapstruct.ap.test.bugs._1242.TargetFactories.createTargetB().")
".TargetB org.mapstruct.ap.test.bugs._1242.TargetFactories.createTargetB()." +
" See https://mapstruct.org/faq/#ambiguous for more info." )
})
public void ambiguousMethodErrorForTwoFactoryMethodsWithSourceParam() {
}

View File

@ -36,7 +36,8 @@ public class AmbiguousAnnotatedFactoryTest {
".ambiguousannotatedfactorymethod.Foo foo), org.mapstruct.ap.test.erroneous" +
".ambiguousannotatedfactorymethod.Bar org.mapstruct.ap.test.erroneous" +
".ambiguousannotatedfactorymethod.AmbiguousBarFactory.createBar(org.mapstruct.ap.test.erroneous" +
".ambiguousannotatedfactorymethod.Foo foo).")
".ambiguousannotatedfactorymethod.Foo foo)." +
" See https://mapstruct.org/faq/#ambiguous for more info.")
}
)

View File

@ -37,8 +37,8 @@ public class FactoryTest {
message = "Ambiguous factory methods found for creating org.mapstruct.ap.test.erroneous" +
".ambiguousfactorymethod.Bar: org.mapstruct.ap.test.erroneous.ambiguousfactorymethod.Bar " +
"createBar(), org.mapstruct.ap.test.erroneous.ambiguousfactorymethod.Bar org.mapstruct.ap.test" +
".erroneous.ambiguousfactorymethod.a.BarFactory.createBar().")
".erroneous.ambiguousfactorymethod.a.BarFactory.createBar()." +
" See https://mapstruct.org/faq/#ambiguous for more info.")
}
)
public void shouldUseTwoFactoryMethods() {

View File

@ -0,0 +1,67 @@
/*
* 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.erroneous.ambiguousmapping;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
@IssueKey("2156")
@RunWith(AnnotationProcessorTestRunner.class)
public class AmbigiousMapperTest {
@Test
@WithClasses( ErroneousWithAmbiguousMethodsMapper.class)
@ExpectedCompilationOutcome(
value = CompilationResult.FAILED,
diagnostics = {
@Diagnostic(type = ErroneousWithAmbiguousMethodsMapper.class,
kind = javax.tools.Diagnostic.Kind.ERROR,
line = 16,
message = "Ambiguous mapping methods found for mapping property "
+ "\"org.mapstruct.ap.test.erroneous.ambiguousmapping."
+ "ErroneousWithAmbiguousMethodsMapper.LeafDTO branch.leaf\" to "
+ "org.mapstruct.ap.test.erroneous.ambiguousmapping."
+ "ErroneousWithAmbiguousMethodsMapper.LeafEntity: "
+ "LeafEntity:map1(LeafDTO), LeafEntity:map2(LeafDTO). "
+ "See https://mapstruct.org/faq/#ambiguous for more info.")
}
)
public void testErrorMessageForAmbiguous() {
}
@Test
@WithClasses( ErroneousWithMoreThanFiveAmbiguousMethodsMapper.class)
@ExpectedCompilationOutcome(
value = CompilationResult.FAILED,
diagnostics = {
@Diagnostic(type = ErroneousWithMoreThanFiveAmbiguousMethodsMapper.class,
kind = javax.tools.Diagnostic.Kind.ERROR,
line = 17,
message = "Ambiguous mapping methods found for mapping property "
+ "\"org.mapstruct.ap.test.erroneous.ambiguousmapping."
+ "ErroneousWithMoreThanFiveAmbiguousMethodsMapper.LeafDTO branch.leaf\" to "
+ "org.mapstruct.ap.test.erroneous.ambiguousmapping."
+ "ErroneousWithMoreThanFiveAmbiguousMethodsMapper.LeafEntity: "
+ "LeafEntity:map1(LeafDTO), "
+ "LeafEntity:map2(LeafDTO), "
+ "LeafEntity:map3(LeafDTO), "
+ "LeafEntity:map4(LeafDTO), "
+ "LeafEntity:map5(LeafDTO)"
+ "... and 1 more. "
+ "See https://mapstruct.org/faq/#ambiguous for more info.")
}
)
public void testErrorMessageForManyAmbiguous() {
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.erroneous.ambiguousmapping;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface ErroneousWithAmbiguousMethodsMapper {
ErroneousWithAmbiguousMethodsMapper INSTANCE = Mappers.getMapper( ErroneousWithAmbiguousMethodsMapper.class );
TrunkEntity map(TrunkDTO dto);
default LeafEntity map1(LeafDTO dto) {
return new LeafEntity();
}
// duplicated method, triggering ambigious mapping method
default LeafEntity map2(LeafDTO dto) {
return new LeafEntity();
}
// CHECKSTYLE:OFF
class TrunkDTO {
public BranchDTO branch;
}
class BranchDTO {
public LeafDTO leaf;
}
class LeafDTO {
public int numberOfVeigns;
}
class TrunkEntity {
public BranchEntity branch;
}
class BranchEntity {
public LeafEntity leaf;
}
class LeafEntity {
public int numberOfVeigns;
}
// CHECKSTYLE ON
}

View File

@ -0,0 +1,74 @@
/*
* 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.erroneous.ambiguousmapping;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface ErroneousWithMoreThanFiveAmbiguousMethodsMapper {
ErroneousWithMoreThanFiveAmbiguousMethodsMapper
INSTANCE = Mappers.getMapper( ErroneousWithMoreThanFiveAmbiguousMethodsMapper.class );
TrunkEntity map(TrunkDTO dto);
default LeafEntity map1(LeafDTO dto) {
return new LeafEntity();
}
// duplicated method, triggering ambigious mapping method
default LeafEntity map2(LeafDTO dto) {
return new LeafEntity();
}
// duplicated method, triggering ambigious mapping method
default LeafEntity map3(LeafDTO dto) {
return new LeafEntity();
}
// duplicated method, triggering ambigious mapping method
default LeafEntity map4(LeafDTO dto) {
return new LeafEntity();
}
// duplicated method, triggering ambigious mapping method
default LeafEntity map5(LeafDTO dto) {
return new LeafEntity();
}
// duplicated method, triggering ambigious mapping method
default LeafEntity map6(LeafDTO dto) {
return new LeafEntity();
}
// CHECKSTYLE:OFF
class TrunkDTO {
public BranchDTO branch;
}
class BranchDTO {
public LeafDTO leaf;
}
class LeafDTO {
public int numberOfVeigns;
}
class TrunkEntity {
public BranchEntity branch;
}
class BranchEntity {
public LeafEntity leaf;
}
class LeafEntity {
public int numberOfVeigns;
}
// CHECKSTYLE ON
}

View File

@ -69,13 +69,12 @@ public class ComplexInheritanceTest {
kind = Kind.ERROR,
type = ErroneousSourceCompositeTargetCompositeMapper.class,
line = 19,
message = "Ambiguous mapping methods found for mapping property \"org.mapstruct.ap.test.inheritance" +
".complex.SourceExt prop1\" to org.mapstruct.ap.test.inheritance.complex.Reference: org.mapstruct.ap" +
".test.inheritance.complex.Reference org.mapstruct.ap.test.inheritance.complex" +
".AdditionalMappingHelper.asReference(org.mapstruct.ap.test.inheritance.complex.SourceBase source), " +
"org.mapstruct.ap.test.inheritance.complex.Reference org.mapstruct.ap.test.inheritance.complex" +
".AdditionalMappingHelper.asReference(org.mapstruct.ap.test.inheritance.complex.AdditionalFooSource " +
"source)."))
message = "Ambiguous mapping methods found for mapping property "
+ "\"org.mapstruct.ap.test.inheritance.complex.SourceExt prop1\" "
+ "to org.mapstruct.ap.test.inheritance.complex.Reference: "
+ "Reference:asReference(SourceBase), Reference:asReference(AdditionalFooSource). "
+ "See https://mapstruct.org/faq/#ambiguous for more info.")
)
public void ambiguousMappingMethodsReportError() {
}

View File

@ -48,7 +48,9 @@ public class InheritanceSelectionTest {
message = "Ambiguous factory methods found for creating org.mapstruct.ap.test.selection.resulttype" +
".Fruit: org.mapstruct.ap.test.selection.resulttype.Apple org.mapstruct.ap.test.selection" +
".resulttype.ConflictingFruitFactory.createApple(), org.mapstruct.ap.test.selection.resulttype" +
".Banana org.mapstruct.ap.test.selection.resulttype.ConflictingFruitFactory.createBanana().")
".Banana org.mapstruct.ap.test.selection.resulttype.ConflictingFruitFactory.createBanana()." +
" See https://mapstruct.org/faq/#ambiguous for more info."
)
}
)
public void testForkedInheritanceHierarchyShouldResultInAmbigousMappingMethod() {