diff --git a/core/src/main/java/org/mapstruct/Mapping.java b/core/src/main/java/org/mapstruct/Mapping.java
index 01ffcd17a..a12aeba70 100644
--- a/core/src/main/java/org/mapstruct/Mapping.java
+++ b/core/src/main/java/org/mapstruct/Mapping.java
@@ -136,7 +136,7 @@ public @interface Mapping {
* imported via {@link Mapper#imports()}.
*
* This attribute can not be used together with {@link #source()}, {@link #defaultValue()},
- * {@link #defaultExpression()} or {@link #constant()}.
+ * {@link #defaultExpression()}, {@link #qualifiedBy()}, {@link #qualifiedByName()} or {@link #constant()}.
*
* @return An expression specifying the value for the designated target property
*/
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java
index fabd444fc..789b22126 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/Mapping.java
@@ -236,6 +236,10 @@ public class Mapping {
else if ( mappingPrism.values.defaultValue() != null && mappingPrism.values.defaultExpression() != null ) {
message = Message.PROPERTYMAPPING_DEFAULT_VALUE_AND_DEFAULT_EXPRESSION_BOTH_DEFINED;
}
+ else if ( mappingPrism.values.expression() != null
+ && ( mappingPrism.values.qualifiedByName() != null || mappingPrism.values.qualifiedBy() != null ) ) {
+ message = Message.PROPERTYMAPPING_EXPRESSION_AND_QUALIFIER_BOTH_DEFINED;
+ }
else if ( mappingPrism.values.nullValuePropertyMappingStrategy() != null
&& mappingPrism.values.defaultValue() != null ) {
message = Message.PROPERTYMAPPING_DEFAULT_VALUE_AND_NVPMS;
diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java
index 4ecf757d4..83ad59fcc 100644
--- a/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java
+++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java
@@ -57,6 +57,7 @@ public enum Message {
PROPERTYMAPPING_CONSTANT_VALUE_AND_NVPMS( "Constant and nullValuePropertyMappingStrategy are both defined in @Mapping, either define a constant or an nullValuePropertyMappingStrategy." ),
PROPERTYMAPPING_DEFAULT_EXPERSSION_AND_NVPMS( "DefaultExpression and nullValuePropertyMappingStrategy are both defined in @Mapping, either define a defaultExpression or an nullValuePropertyMappingStrategy." ),
PROPERTYMAPPING_IGNORE_AND_NVPMS( "Ignore and nullValuePropertyMappingStrategy are both defined in @Mapping, either define ignore or an nullValuePropertyMappingStrategy." ),
+ PROPERTYMAPPING_EXPRESSION_AND_QUALIFIER_BOTH_DEFINED("Expression and a qualifier both defined in @Mapping, either define an expression or a qualifier."),
PROPERTYMAPPING_INVALID_EXPRESSION( "Value for expression must be given in the form \"java()\"." ),
PROPERTYMAPPING_INVALID_DEFAULT_EXPRESSION( "Value for default expression must be given in the form \"java()\"." ),
PROPERTYMAPPING_INVALID_PARAMETER_NAME( "Method has no source parameter named \"%s\". Method source parameters are: \"%s\"." ),
diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/expressions/java/ErroneousSourceTargetMapperExpressionAndQualifiers.java b/processor/src/test/java/org/mapstruct/ap/test/source/expressions/java/ErroneousSourceTargetMapperExpressionAndQualifiers.java
new file mode 100644
index 000000000..189fc58b5
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/source/expressions/java/ErroneousSourceTargetMapperExpressionAndQualifiers.java
@@ -0,0 +1,29 @@
+/*
+ * 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.source.expressions.java;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.Mappings;
+import org.mapstruct.ReportingPolicy;
+
+@Mapper( uses = QualifierProvider.class, unmappedTargetPolicy = ReportingPolicy.IGNORE )
+public interface ErroneousSourceTargetMapperExpressionAndQualifiers {
+
+ @Mappings( {
+ @Mapping( target = "anotherProp", expression = "java( s.getClass().getName() )", qualifiedByName = "toUpper" ),
+ @Mapping( target = "timeAndFormat", ignore = true )
+ } )
+ Target sourceToTargetWithExpressionAndNamedQualifier(Source s, @MappingTarget Target t);
+
+ @Mappings( {
+ @Mapping( target = "anotherProp", expression = "java( s.getClass().getName() )",
+ qualifiedBy = QualifierProvider.ToUpper.class ),
+ @Mapping( target = "timeAndFormat", ignore = true )
+ } )
+ Target sourceToTargetWithExpressionAndQualifier(Source s, @MappingTarget Target t);
+}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/expressions/java/JavaExpressionTest.java b/processor/src/test/java/org/mapstruct/ap/test/source/expressions/java/JavaExpressionTest.java
index 3cec82ea9..726690ed8 100644
--- a/processor/src/test/java/org/mapstruct/ap/test/source/expressions/java/JavaExpressionTest.java
+++ b/processor/src/test/java/org/mapstruct/ap/test/source/expressions/java/JavaExpressionTest.java
@@ -17,6 +17,9 @@ import org.junit.runner.RunWith;
import org.mapstruct.ap.test.source.expressions.java.mapper.TimeAndFormat;
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;
/**
@@ -131,4 +134,33 @@ public class JavaExpressionTest {
assertThat( target ).isNotNull();
assertThat( target.getList() ).isEqualTo( Arrays.asList( "test2" ) );
}
+
+ @IssueKey( "1851" )
+ @Test
+ @WithClasses({
+ Source.class,
+ Target.class,
+ QualifierProvider.class,
+ TimeAndFormat.class,
+ ErroneousSourceTargetMapperExpressionAndQualifiers.class
+ })
+ @ExpectedCompilationOutcome(
+ value = CompilationResult.FAILED,
+ diagnostics = {
+ @Diagnostic(type = ErroneousSourceTargetMapperExpressionAndQualifiers.class,
+ kind = javax.tools.Diagnostic.Kind.ERROR,
+ line = 18,
+ messageRegExp = "Expression and a qualifier both defined in @Mapping," +
+ " either define an expression or a qualifier."
+ ),
+ @Diagnostic(type = ErroneousSourceTargetMapperExpressionAndQualifiers.class,
+ kind = javax.tools.Diagnostic.Kind.ERROR,
+ line = 24,
+ messageRegExp = "Expression and a qualifier both defined in @Mapping," +
+ " either define an expression or a qualifier."
+ )
+ }
+ )
+ public void testExpressionAndQualifiedDoesNotCompile() {
+ }
}
diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/expressions/java/QualifierProvider.java b/processor/src/test/java/org/mapstruct/ap/test/source/expressions/java/QualifierProvider.java
new file mode 100644
index 000000000..a5a508b6f
--- /dev/null
+++ b/processor/src/test/java/org/mapstruct/ap/test/source/expressions/java/QualifierProvider.java
@@ -0,0 +1,17 @@
+/*
+ * 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.source.expressions.java;
+
+public class QualifierProvider {
+
+ public @interface ToUpper {
+ }
+
+ @ToUpper
+ public String toUpper( String string ) {
+ return string.toUpperCase();
+ }
+}