diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractMappingMethodBuilder.java b/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractMappingMethodBuilder.java index 04c64d606..759f22ca7 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractMappingMethodBuilder.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/AbstractMappingMethodBuilder.java @@ -37,7 +37,7 @@ public abstract class AbstractMappingMethodBuilder(), errorMessagePart ); + + SelectionCriteria criteria = SelectionCriteria.forMappingMethods( selectionParameters, + callingContextTargetPropertyName, + false + ); + Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method, targetElementType, - callingContextTargetPropertyName, formattingParameters, - selectionParameters, + criteria, sourceRHS, - false, null ); - if ( assignment == null ) { + if ( assignment == null && !criteria.hasQualfiers() ) { assignment = forgeMapping( sourceRHS, sourceElementType, targetElementType ); if ( assignment != null ) { ctx.getMessager().note( 2, Message.ITERABLEMAPPING_CREATE_ELEMENT_NOTE, assignment ); 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 72a6da85f..b08fea577 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 @@ -5,8 +5,6 @@ */ package org.mapstruct.ap.internal.model; -import static org.mapstruct.ap.internal.util.Collections.first; - import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -22,10 +20,13 @@ import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.source.ForgedMethod; import org.mapstruct.ap.internal.model.source.Method; import org.mapstruct.ap.internal.model.source.SelectionParameters; +import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria; import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism; import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Strings; +import static org.mapstruct.ap.internal.util.Collections.first; + /** * A {@link MappingMethod} implemented by a {@link Mapper} class which maps one {@code Map} type to another. Keys and * values are mapped either by a {@link TypeConversion} or another mapping method if required. @@ -86,18 +87,20 @@ public class MapMappingMethod extends NormalTypeMappingMethod { Type keyTargetType = resultTypeParams.get( 0 ).getTypeBound(); SourceRHS keySourceRHS = new SourceRHS( "entry.getKey()", keySourceType, new HashSet<>(), "map key" ); + + SelectionCriteria keyCriteria = + SelectionCriteria.forMappingMethods( keySelectionParameters, null, false ); + Assignment keyAssignment = ctx.getMappingResolver().getTargetAssignment( method, keyTargetType, - null, // there is no targetPropertyName keyFormattingParameters, - keySelectionParameters, + keyCriteria, keySourceRHS, - false, null ); - if ( keyAssignment == null ) { + if ( keyAssignment == null && !keyCriteria.hasQualfiers( ) ) { keyAssignment = forgeMapping( keySourceRHS, keySourceType, keyTargetType ); if ( keyAssignment != null ) { ctx.getMessager().note( 2, Message.MAPMAPPING_CREATE_KEY_NOTE, keyAssignment ); @@ -133,14 +136,16 @@ public class MapMappingMethod extends NormalTypeMappingMethod { SourceRHS valueSourceRHS = new SourceRHS( "entry.getValue()", valueSourceType, new HashSet<>(), "map value" ); + + SelectionCriteria valueCriteria = + SelectionCriteria.forMappingMethods( valueSelectionParameters, null, false ); + Assignment valueAssignment = ctx.getMappingResolver().getTargetAssignment( method, valueTargetType, - null, // there is no targetPropertyName valueFormattingParameters, - valueSelectionParameters, + valueCriteria, valueSourceRHS, - false, null ); @@ -154,7 +159,7 @@ public class MapMappingMethod extends NormalTypeMappingMethod { } } - if ( valueAssignment == null ) { + if ( valueAssignment == null && !valueCriteria.hasQualfiers( ) ) { valueAssignment = forgeMapping( valueSourceRHS, valueSourceType, valueTargetType ); if ( valueAssignment != null ) { ctx.getMessager().note( 2, Message.MAPMAPPING_CREATE_VALUE_NOTE, valueAssignment ); @@ -221,6 +226,7 @@ public class MapMappingMethod extends NormalTypeMappingMethod { protected boolean shouldUsePropertyNamesInHistory() { return true; } + } private MapMappingMethod(Method method, Collection existingVariableNames, Assignment keyAssignment, 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 3ce85d127..bbbf69dbd 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 @@ -7,6 +7,7 @@ package org.mapstruct.ap.internal.model; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -23,8 +24,8 @@ import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.TypeFactory; import org.mapstruct.ap.internal.model.source.ForgedMethod; import org.mapstruct.ap.internal.model.source.Method; -import org.mapstruct.ap.internal.model.source.SelectionParameters; import org.mapstruct.ap.internal.model.source.SourceMethod; +import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria; import org.mapstruct.ap.internal.option.Options; import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.FormattingMessager; @@ -76,11 +77,10 @@ public class MappingBuilderContext { * * @param mappingMethod target mapping method * @param targetType return type to match - * @param targetPropertyName name of the target property * @param formattingParameters used for formatting dates and numbers - * @param selectionParameters parameters used in the selection process + * @param criteria parameters criteria in the selection process * @param sourceRHS source information - * @param preferUpdateMethods selection should prefer update methods when present. + * @param positionHint the mirror for reporting problems * * @return an assignment to a method parameter, which can either be: *
    @@ -90,10 +90,10 @@ public class MappingBuilderContext { *
  1. null, no assignment found
  2. *
*/ - Assignment getTargetAssignment(Method mappingMethod, Type targetType, String targetPropertyName, + Assignment getTargetAssignment(Method mappingMethod, Type targetType, FormattingParameters formattingParameters, - SelectionParameters selectionParameters, SourceRHS sourceRHS, - boolean preferUpdateMethods, AnnotationMirror mirror); + SelectionCriteria criteria, SourceRHS sourceRHS, + AnnotationMirror positionHint); Set getUsedSupportedMappings(); } @@ -191,12 +191,18 @@ public class MappingBuilderContext { return mappingsToGenerate; } - public List getNamesOfMappingsToGenerate() { - List nameList = new ArrayList<>(); + public List getReservedNames() { + Set nameSet = new HashSet<>(); for ( MappingMethod method : mappingsToGenerate ) { - nameList.add( method.getName() ); + nameSet.add( method.getName() ); } - return nameList; + // add existing names + for ( SourceMethod method : sourceModel) { + if ( method.isAbstract() ) { + nameSet.add( method.getName() ); + } + } + return new ArrayList<>( nameSet ); } public MappingMethod getExistingMappingMethod(MappingMethod newMappingMethod) { 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 423b5f4b4..2f892e6b5 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 @@ -36,6 +36,7 @@ import org.mapstruct.ap.internal.model.source.ParameterProvidedMethods; import org.mapstruct.ap.internal.model.source.PropertyEntry; import org.mapstruct.ap.internal.model.source.SelectionParameters; import org.mapstruct.ap.internal.model.source.SourceReference; +import org.mapstruct.ap.internal.model.source.selector.SelectionCriteria; import org.mapstruct.ap.internal.prism.NullValueCheckStrategyPrism; import org.mapstruct.ap.internal.prism.NullValueMappingStrategyPrism; import org.mapstruct.ap.internal.prism.NullValuePropertyMappingStrategyPrism; @@ -310,24 +311,27 @@ public class PropertyMapping extends ModelElement { preferUpdateMethods = method.getMappingTargetParameter() != null; } + SelectionCriteria criteria = SelectionCriteria.forMappingMethods( selectionParameters, + targetPropertyName, + preferUpdateMethods + ); + // forge a method instead of resolving one when there are mapping options. Assignment assignment = null; if ( forgeMethodWithMappingOptions == null ) { assignment = ctx.getMappingResolver().getTargetAssignment( method, targetType, - targetPropertyName, formattingParameters, - selectionParameters, + criteria, rightHandSide, - preferUpdateMethods, positionHint ); } Type sourceType = rightHandSide.getSourceType(); // No mapping found. Try to forge a mapping - if ( assignment == null ) { + if ( assignment == null && !criteria.hasQualfiers() ) { if ( (sourceType.isCollectionType() || sourceType.isArrayType()) && targetType.isIterableType() ) { assignment = forgeIterableMapping( sourceType, targetType, rightHandSide, method.getExecutable() ); } @@ -595,7 +599,7 @@ public class PropertyMapping extends ModelElement { // forge a method from the parameter type to the last entry type. String forgedName = Strings.joinAndCamelize( sourceReference.getElementNames() ); - forgedName = Strings.getSafeVariableName( forgedName, ctx.getNamesOfMappingsToGenerate() ); + forgedName = Strings.getSafeVariableName( forgedName, ctx.getReservedNames() ); ForgedMethod methodRef = new ForgedMethod( forgedName, sourceReference.getParameter().getType(), @@ -699,7 +703,7 @@ public class PropertyMapping extends ModelElement { private ForgedMethod prepareForgedMethod(Type sourceType, Type targetType, SourceRHS source, ExecutableElement element, String suffix) { String name = getName( sourceType, targetType ); - name = Strings.getSafeVariableName( name, ctx.getNamesOfMappingsToGenerate() ); + name = Strings.getSafeVariableName( name, ctx.getReservedNames() ); // copy mapper configuration from the source method, its the same mapper MapperConfiguration config = method.getMapperConfiguration(); @@ -751,7 +755,7 @@ public class PropertyMapping extends ModelElement { } String name = getName( sourceType, targetType ); - name = Strings.getSafeVariableName( name, ctx.getNamesOfMappingsToGenerate() ); + name = Strings.getSafeVariableName( name, ctx.getReservedNames() ); List parameters = new ArrayList<>( method.getContextParameters() ); Type returnType; @@ -873,16 +877,19 @@ public class PropertyMapping extends ModelElement { } Type sourceType = ctx.getTypeFactory().getTypeForLiteral( baseForLiteral ); + SelectionCriteria criteria = SelectionCriteria.forMappingMethods( selectionParameters, + targetPropertyName, + method.getMappingTargetParameter() != null + ); + Assignment assignment = null; if ( !targetType.isEnumType() ) { assignment = ctx.getMappingResolver().getTargetAssignment( method, targetType, - targetPropertyName, formattingParameters, - selectionParameters, + criteria, new SourceRHS( constantExpression, sourceType, existingVariableNames, sourceErrorMessagePart ), - method.getMappingTargetParameter() != null, positionHint ); } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/selector/QualifierSelector.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/selector/QualifierSelector.java index 803e6a08d..5c24e423e 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/selector/QualifierSelector.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/selector/QualifierSelector.java @@ -138,12 +138,7 @@ public class QualifierSelector implements MethodSelector { matches.add( candidate ); } } - if ( !matches.isEmpty() ) { - return matches; - } - else { - return methods; - } + return matches; } } 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 132358ec3..c632fec6c 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 @@ -90,6 +90,10 @@ public class SelectionCriteria { this.preferUpdateMapping = preferUpdateMapping; } + public boolean hasQualfiers() { + return !qualifiedByNames.isEmpty() || !qualifiers.isEmpty(); + } + public static SelectionCriteria forMappingMethods(SelectionParameters selectionParameters, String targetPropertyName, boolean preferUpdateMapping) { 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 9938beff1..6218cbcd1 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 @@ -37,7 +37,6 @@ import org.mapstruct.ap.internal.model.common.SourceRHS; import org.mapstruct.ap.internal.model.common.Type; import org.mapstruct.ap.internal.model.common.TypeFactory; import org.mapstruct.ap.internal.model.source.Method; -import org.mapstruct.ap.internal.model.source.SelectionParameters; import org.mapstruct.ap.internal.model.source.builtin.BuiltInMappingMethods; import org.mapstruct.ap.internal.model.source.builtin.BuiltInMethod; import org.mapstruct.ap.internal.model.source.selector.MethodSelectors; @@ -95,12 +94,10 @@ public class MappingResolverImpl implements MappingResolver { } @Override - public Assignment getTargetAssignment(Method mappingMethod, Type targetType, String targetPropertyName, - FormattingParameters formattingParameters, SelectionParameters selectionParameters, SourceRHS sourceRHS, - boolean preferUpdateMapping, AnnotationMirror positionHint) { - - SelectionCriteria criteria = - SelectionCriteria.forMappingMethods( selectionParameters, targetPropertyName, preferUpdateMapping ); + public Assignment getTargetAssignment(Method mappingMethod, Type targetType, + FormattingParameters formattingParameters, + SelectionCriteria criteria, SourceRHS sourceRHS, + AnnotationMirror positionHint) { ResolvingAttempt attempt = new ResolvingAttempt( sourceModel, @@ -182,12 +179,13 @@ public class MappingResolverImpl implements MappingResolver { } // then direct assignable - if ( sourceType.isAssignableTo( targetType ) || + if ( !hasQualfiers() ) { + if ( sourceType.isAssignableTo( targetType ) || isAssignableThroughCollectionCopyConstructor( sourceType, targetType ) ) { - Assignment simpleAssignment = sourceRHS; - return simpleAssignment; + Assignment simpleAssignment = sourceRHS; + return simpleAssignment; + } } - // At this point the SourceType will either // 1. be a String // 2. or when its a primitive / wrapped type and analysis successful equal to its TargetType. But in that @@ -196,25 +194,29 @@ public class MappingResolverImpl implements MappingResolver { // in NativeType is not successful. We don't want to go through type conversion, double mappings etc. // with something that we already know to be wrong. if ( sourceType.isLiteral() - && "java.lang.String".equals( sourceType.getFullyQualifiedName( ) ) + && "java.lang.String".equals( sourceType.getFullyQualifiedName() ) && targetType.isNative() ) { return null; } // then type conversion - ConversionAssignment conversion = resolveViaConversion( sourceType, targetType ); - if ( conversion != null ) { - conversion.reportMessageWhenNarrowing( messager, this ); - conversion.getAssignment().setAssignment( sourceRHS ); - return conversion.getAssignment(); + if ( !hasQualfiers() ) { + ConversionAssignment conversion = resolveViaConversion( sourceType, targetType ); + if ( conversion != null ) { + conversion.reportMessageWhenNarrowing( messager, this ); + conversion.getAssignment().setAssignment( sourceRHS ); + return conversion.getAssignment(); + } } // check for a built-in method - Assignment builtInMethod = resolveViaBuiltInMethod( sourceType, targetType ); - if ( builtInMethod != null ) { - builtInMethod.setAssignment( sourceRHS ); - usedSupportedMappings.addAll( supportingMethodCandidates ); - return builtInMethod; + if (!hasQualfiers() ) { + Assignment builtInMethod = resolveViaBuiltInMethod( sourceType, targetType ); + if ( builtInMethod != null ) { + builtInMethod.setAssignment( sourceRHS ); + usedSupportedMappings.addAll( supportingMethodCandidates ); + return builtInMethod; + } } // 2 step method, first: method(method(source)) @@ -235,7 +237,7 @@ public class MappingResolverImpl implements MappingResolver { selectionCriteria.setPreferUpdateMapping( false ); // 2 step method, finally: conversion(method(source)) - conversion = resolveViaMethodAndConversion( sourceType, targetType ); + ConversionAssignment conversion = resolveViaMethodAndConversion( sourceType, targetType ); if ( conversion != null ) { usedSupportedMappings.addAll( supportingMethodCandidates ); return conversion.getAssignment(); @@ -245,6 +247,10 @@ public class MappingResolverImpl implements MappingResolver { return null; } + private boolean hasQualfiers() { + return selectionCriteria != null && selectionCriteria.hasQualfiers(); + } + private ConversionAssignment resolveViaConversion(Type sourceType, Type targetType) { ConversionProvider conversionProvider = conversions.getConversion( sourceType, targetType ); @@ -379,9 +385,9 @@ public class MappingResolverImpl implements MappingResolver { * * then this method tries to resolve this combination and make a mapping methodY( conversionX ( parameter ) ) * - * In stead of directly using a built in method candidate all the return types as 'B' of all available built-in - * methods are used to resolve a mapping (assignment) from result type to 'B'. If a match is found, an attempt - * is done to find a matching type conversion. + * In stead of directly using a built in method candidate all the return types as 'B' of all available built-in + * methods are used to resolve a mapping (assignment) from result type to 'B'. If a match is found, an attempt + * is done to find a matching type conversion. */ private Assignment resolveViaConversionAndMethod(Type sourceType, Type targetType) { @@ -503,7 +509,8 @@ public class MappingResolverImpl implements MappingResolver { if ( candidates.size() > 1 ) { if ( sourceRHS.getSourceErrorMessagePart() != null ) { - messager.printMessage( mappingMethod.getExecutable(), + messager.printMessage( + mappingMethod.getExecutable(), positionHint, Message.GENERAL_AMBIGIOUS_MAPPING_METHOD, sourceRHS.getSourceErrorMessagePart(), @@ -512,7 +519,8 @@ public class MappingResolverImpl implements MappingResolver { ); } else { - messager.printMessage( mappingMethod.getExecutable(), + messager.printMessage( + mappingMethod.getExecutable(), positionHint, Message.GENERAL_AMBIGIOUS_FACTORY_METHOD, returnType, @@ -535,7 +543,8 @@ public class MappingResolverImpl implements MappingResolver { return MethodReference.forMapperReference( method.getMethod(), mapperReference, - method.getParameterBindings() ); + method.getParameterBindings() + ); } /** @@ -546,14 +555,14 @@ public class MappingResolverImpl implements MappingResolver { boolean bothCollectionOrMap = false; if ( ( sourceType.isCollectionType() && targetType.isCollectionType() ) || - ( sourceType.isMapType() && targetType.isMapType() ) ) { + ( sourceType.isMapType() && targetType.isMapType() ) ) { bothCollectionOrMap = true; } if ( bothCollectionOrMap ) { return hasCompatibleCopyConstructor( - sourceType, - targetType.getImplementationType() != null ? targetType.getImplementationType() : targetType + sourceType, + targetType.getImplementationType() != null ? targetType.getImplementationType() : targetType ); } @@ -565,8 +574,9 @@ public class MappingResolverImpl implements MappingResolver { * * @param sourceType the source type * @param targetType the target type + * * @return {@code true} if the target type has a constructor accepting the given source type, {@code false} - * otherwise. + * otherwise. */ private boolean hasCompatibleCopyConstructor(Type sourceType, Type targetType) { if ( targetType.isPrimitive() ) { @@ -584,7 +594,8 @@ public class MappingResolverImpl implements MappingResolver { // get the constructor resolved against the type arguments of specific target type ExecutableType typedConstructor = (ExecutableType) typeUtils.asMemberOf( (DeclaredType) targetType.getTypeMirror(), - constructor ); + constructor + ); TypeMirror parameterType = Collections.first( typedConstructor.getParameterTypes() ); if ( parameterType.getKind() == TypeKind.DECLARED ) { @@ -603,7 +614,8 @@ public class MappingResolverImpl implements MappingResolver { } parameterType = typeUtils.getDeclaredType( (TypeElement) p.asElement(), - typeArguments.toArray( new TypeMirror[typeArguments.size()] ) ); + typeArguments.toArray( new TypeMirror[typeArguments.size()] ) + ); } if ( typeUtils.isAssignable( sourceType.getTypeMirror(), parameterType ) ) { diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1714/Issue1714Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1714/Issue1714Mapper.java new file mode 100644 index 000000000..0273457e8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1714/Issue1714Mapper.java @@ -0,0 +1,60 @@ +/* + * 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._1714; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface Issue1714Mapper { + + Issue1714Mapper INSTANCE = Mappers.getMapper( Issue1714Mapper.class ); + + @Mapping(source = "programInstance", target = "seasonNumber", qualifiedByName = "getSeasonNumber") + OfferEntity map(OnDemand offerStatusDTO); + + @Named("getTitle") + default String mapTitle(Program programInstance) { + return "dont care"; + } + + @Named("getSeasonNumber") + default Integer mapSeasonNumber(Program programInstance) { + return 1; + } + + class OfferEntity { + + private String seasonNumber; + + public String getSeasonNumber() { + return seasonNumber; + } + + public void setSeasonNumber(String seasonNumber) { + this.seasonNumber = seasonNumber; + } + + } + + class OnDemand { + + private Program programInstance; + + public Program getProgramInstance() { + return programInstance; + } + + public void setProgramInstance(Program programInstance) { + this.programInstance = programInstance; + } + } + + class Program { + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1714/Issue1714Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1714/Issue1714Test.java new file mode 100644 index 000000000..88a7848c8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1714/Issue1714Test.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._1714; + +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.runner.AnnotationProcessorTestRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(AnnotationProcessorTestRunner.class) +@IssueKey("1714") +@WithClasses({ + Issue1714Mapper.class +}) +public class Issue1714Test { + + @Test + public void codeShouldBeGeneratedCorrectly() { + + Issue1714Mapper.OnDemand source = new Issue1714Mapper.OnDemand(); + source.setProgramInstance( new Issue1714Mapper.Program() ); + + Issue1714Mapper.OfferEntity result = Issue1714Mapper.INSTANCE.map( source ); + + assertThat( result.getSeasonNumber() ).isEqualTo( "1" ); + + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/callbacks/BaseMapper.java b/processor/src/test/java/org/mapstruct/ap/test/callbacks/BaseMapper.java index 11e5e515f..bee462acc 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/callbacks/BaseMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/callbacks/BaseMapper.java @@ -21,6 +21,9 @@ public abstract class BaseMapper { public abstract Target sourceToTarget(Source source); + @Qualified + public abstract Target sourceToTargetQualified(Source source); + private static final List INVOCATIONS = new ArrayList(); @BeforeMapping diff --git a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/QualifierTest.java b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/QualifierTest.java index 6d20d1a45..1d298f94d 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/QualifierTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/QualifierTest.java @@ -96,14 +96,15 @@ public class QualifierTest { ErroneousMapper.class } ) @ExpectedCompilationOutcome( - value = CompilationResult.FAILED, - diagnostics = { - @Diagnostic( type = ErroneousMapper.class, - kind = Kind.ERROR, - line = 28, - messageRegExp = "Ambiguous mapping methods found for mapping property " - + "\"java.lang.String title\" to java.lang.String.*" ) - } + value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = ErroneousMapper.class, + kind = Kind.ERROR, + line = 28, + messageRegExp = + "Can't map property \"java.lang.String title\" to \"java.lang.String title\". " + + "Consider to declare/implement a mapping method: \"java.lang.String map(java.lang.String value)*") + } ) public void shouldNotProduceMatchingMethod() { } diff --git a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/TopologyMapper.java b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/TopologyMapper.java index e1c8190b7..22e87dd08 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/TopologyMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/TopologyMapper.java @@ -9,6 +9,9 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.List; + +import org.mapstruct.IterableMapping; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Qualifier; @@ -29,6 +32,14 @@ public abstract class TopologyMapper { @Mapping( target = "topologyFeatures", qualifiedBy = Cities.class ) public abstract TopologyEntity mapTopologyAsCity(TopologyDto dto); + @Rivers + @IterableMapping( qualifiedBy = Rivers.class ) + public abstract List mapTopologiesAsRiver(List in); + + @Cities + @IterableMapping( qualifiedBy = Cities.class ) + public abstract List mapTopologiesAsCities(List in); + @Rivers protected TopologyFeatureEntity mapRiver( TopologyFeatureDto dto ) { TopologyFeatureEntity topologyFeatureEntity = null;