diff --git a/src/main/resources/inspectionDescriptions/TargetPropertyMappedMoreThanOnceInspection.html b/src/main/resources/inspectionDescriptions/TargetPropertyMappedMoreThanOnceInspection.html
new file mode 100644
index 0000000..43578fb
--- /dev/null
+++ b/src/main/resources/inspectionDescriptions/TargetPropertyMappedMoreThanOnceInspection.html
@@ -0,0 +1,29 @@
+
+
+
+ This inspection reports when a target property is explicit mapped more than once
+
+
+
+//wrong
+@Mapper
+public interface EmployeeMapper {
+ @Mapping(source = "employeeName", target = "name")
+ @Mapping(source = "employeeNameLast", target = "name")
+ Employee toEmployee(EmployeeDto employeeDto, @Context CycleAvoidingMappingContext context);
+}
+
+
+
+
+//correct
+@Mapper
+public interface EmployeeMapper {
+ @Mapping(source = "employeeName", target = "name")
+ Employee toEmployee(EmployeeDto employeeDto, @Context CycleAvoidingMappingContext context);
+}
+
+
+
+
+
diff --git a/src/main/resources/org/mapstruct/intellij/messages/MapStructBundle.properties b/src/main/resources/org/mapstruct/intellij/messages/MapStructBundle.properties
index 5732d13..8664108 100644
--- a/src/main/resources/org/mapstruct/intellij/messages/MapStructBundle.properties
+++ b/src/main/resources/org/mapstruct/intellij/messages/MapStructBundle.properties
@@ -25,6 +25,8 @@ inspection.wrong.map.mapping.map.type.raw=Raw map used for mapping Map to Bean
inspection.wrong.map.mapping.map.type.raw.set.default=Replace {0} with {0}
inspection.wrong.map.mapping.map.key=Key must be of type String for mapping Map to Bean
inspection.wrong.map.mapping.map.key.change.to.string=Change key type to String
+inspection.target.property.mapped.more.than.once=Target property ''{0}'' must not be mapped more than once.
+inspection.target.property.mapped.more.than.once.title=Target properties must not be mapped more than once.
intention.add.ignore.all.unmapped.target.properties=Add ignore all unmapped target properties
intention.add.ignore.unmapped.target.property=Add ignore unmapped target property
intention.add.unmapped.target.property=Add unmapped target property
@@ -34,6 +36,8 @@ intention.not.null.checkable.property.source.used.with.default.property=Remove d
intention.java.expression.remove.unnecessary.whitespace=Remove unnecessary whitespaces
intention.wrong.map.mapping.map.type.raw=Add type to Map for mapping Map to Bean
intention.wrong.map.mapping.map.key=Use Map with key of type String for mapping Map to Bean
+intention.remove.annotation=Remove {0} annotation
+intention.change.target.property=Change target property
plugin.settings.title=MapStruct
plugin.settings.quickFix.title=Quick fix properties
plugin.settings.quickFix.preferSourceBeforeTargetInMapping=Prefer source before target in @Mapping
diff --git a/src/test/java/org/mapstruct/intellij/inspection/TargetPropertyMappedMoreThanOnceInspectionTest.java b/src/test/java/org/mapstruct/intellij/inspection/TargetPropertyMappedMoreThanOnceInspectionTest.java
new file mode 100644
index 0000000..486f524
--- /dev/null
+++ b/src/test/java/org/mapstruct/intellij/inspection/TargetPropertyMappedMoreThanOnceInspectionTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright MapStruct Authors.
+ *
+ * Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
+ */
+package org.mapstruct.intellij.inspection;
+
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.openapi.editor.Caret;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author hduelme
+ */
+public class TargetPropertyMappedMoreThanOnceInspectionTest extends BaseInspectionTest {
+
+ @Override
+ protected @NotNull Class extends LocalInspectionTool> getInspection() {
+ return TargetPropertyMappedMoreThanOnceInspection.class;
+ }
+
+ public void testTargetPropertyMappedMoreThanOnce() {
+ doTest();
+ String testName = getTestName( false );
+ List allQuickFixes = myFixture.getAllQuickFixes();
+
+ assertThat( allQuickFixes )
+ .extracting( IntentionAction::getText )
+ .as( "Intent Text" )
+ .containsExactly(
+ "Remove Mapping annotation",
+ "Change target property",
+ "Remove Mapping annotation",
+ "Change target property",
+ "Remove Mapping annotation",
+ "Change target property",
+ "Remove Mapping annotation",
+ "Change target property",
+ "Remove Mapping annotation",
+ "Change target property",
+ "Remove Mapping annotation",
+ "Change target property",
+ "Remove Mapping annotation",
+ "Change target property",
+ "Remove MyMappingAnnotation annotation",
+ "Remove Mapping annotation",
+ "Change target property",
+ "Remove MyMappingAnnotation annotation"
+ );
+
+ // Delete annotations
+ myFixture.launchAction( allQuickFixes.get( 0 ) );
+ myFixture.launchAction( allQuickFixes.get( 3 ) );
+ myFixture.launchAction( allQuickFixes.get( 6 ) );
+ myFixture.launchAction( allQuickFixes.get( 8 ) );
+ myFixture.launchAction( allQuickFixes.get( 14 ) );
+ // Set cursor
+ myFixture.launchAction( allQuickFixes.get( 16 ) );
+ myFixture.checkResultByFile( testName + "_after.java" );
+ Caret currentCaret = myFixture.getEditor().getCaretModel().getCurrentCaret();
+ assertThat( currentCaret.getSelectedText( ) ).isEqualTo( "testName" );
+ }
+}
diff --git a/testData/inspection/TargetPropertyMappedMoreThanOnce.java b/testData/inspection/TargetPropertyMappedMoreThanOnce.java
new file mode 100644
index 0000000..2437a33
--- /dev/null
+++ b/testData/inspection/TargetPropertyMappedMoreThanOnce.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright MapStruct Authors.
+ *
+ * Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+class Target {
+ private String testName;
+
+ public String getTestName() {
+ return testName;
+ }
+
+ public void setTestName(String testName) {
+ this.testName = testName;
+ }
+}
+
+class Source {
+ private String name;
+ private String lastName;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+}
+
+@Retention(RetentionPolicy.CLASS)
+@Mapping(target = "testName", source = "name")
+@interface MyMappingAnnotation {
+}
+
+
+@Mapper
+interface TargetMappedMoreThanOnceByMappingAnnotationMapper {
+
+ @Mapping(target = "testName", source = "name")
+ @Mapping(target = "testName", source = "lastName")
+ Target map(Source source);
+}
+
+@Mapper
+interface TargetMappedMoreThanOnceByMappingsAnnotationsMapper {
+
+ @Mappings({
+ @Mapping(target = "testName", source = "name"),
+ @Mapping(target = "testName", source = "lastName")
+ })
+ Target map(Source source);
+}
+
+@Mapper
+interface TargetMappedMoreThanOnceByMappingsAnnotationsAndMappingAnnotationMapper {
+
+ @Mapping(target = "testName", source = "name")
+ @Mappings({
+ @Mapping(target = "testName", source = "lastName")
+ })
+ Target map(Source source);
+}
+
+@Mapper
+interface TargetMappedMoreThanOnceByMyMappingAnnotationAndMappingAnnotationMapper {
+
+ @Mapping(target = "testName", source = "lastName")
+ @MyMappingAnnotation
+ Target map(Source source);
+}
+
+@Mapper
+interface TargetMappedMoreThanOnceByMyMappingAnnotationAndMappingsAnnotationMapper {
+
+ @Mappings({
+ @Mapping(target = "testName", source = "lastName")
+ })
+ @MyMappingAnnotation
+ Target map(Source source);
+}
\ No newline at end of file
diff --git a/testData/inspection/TargetPropertyMappedMoreThanOnce_after.java b/testData/inspection/TargetPropertyMappedMoreThanOnce_after.java
new file mode 100644
index 0000000..669c79b
--- /dev/null
+++ b/testData/inspection/TargetPropertyMappedMoreThanOnce_after.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright MapStruct Authors.
+ *
+ * Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+class Target {
+ private String testName;
+
+ public String getTestName() {
+ return testName;
+ }
+
+ public void setTestName(String testName) {
+ this.testName = testName;
+ }
+}
+
+class Source {
+ private String name;
+ private String lastName;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+}
+
+@Retention(RetentionPolicy.CLASS)
+@Mapping(target = "testName", source = "name")
+@interface MyMappingAnnotation {
+}
+
+
+@Mapper
+interface TargetMappedMoreThanOnceByMappingAnnotationMapper {
+
+ @Mapping(target = "testName", source = "lastName")
+ Target map(Source source);
+}
+
+@Mapper
+interface TargetMappedMoreThanOnceByMappingsAnnotationsMapper {
+
+ @Mappings({
+ @Mapping(target = "testName", source = "name")
+ })
+ Target map(Source source);
+}
+
+@Mapper
+interface TargetMappedMoreThanOnceByMappingsAnnotationsAndMappingAnnotationMapper {
+
+ @Mappings({
+ @Mapping(target = "testName", source = "lastName")
+ })
+ Target map(Source source);
+}
+
+@Mapper
+interface TargetMappedMoreThanOnceByMyMappingAnnotationAndMappingAnnotationMapper {
+
+ @Mapping(target = "testName", source = "lastName")
+ Target map(Source source);
+}
+
+@Mapper
+interface TargetMappedMoreThanOnceByMyMappingAnnotationAndMappingsAnnotationMapper {
+
+ @Mappings({
+ @Mapping(target = "testName", source = "lastName")
+ })
+ @MyMappingAnnotation
+ Target map(Source source);
+}
\ No newline at end of file