diff --git a/.gitignore b/.gitignore
index 1249d1b..8288b4b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,75 +36,9 @@ nbdist/
# ---> JetBrains
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+.idea
+*.iml
-# User-specific stuff
-.idea/**/workspace.xml
-.idea/**/tasks.xml
-.idea/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
-
-# Generated files
-.idea/**/contentModel.xml
-
-# Sensitive or high-churn files
-.idea/**/dataSources/
-.idea/**/dataSources.ids
-.idea/**/dataSources.local.xml
-.idea/**/sqlDataSources.xml
-.idea/**/dynamic.xml
-.idea/**/uiDesigner.xml
-.idea/**/dbnavigator.xml
-
-# Gradle
-.idea/**/gradle.xml
-.idea/**/libraries
-
-# Gradle and Maven with auto-import
-# When using Gradle or Maven with auto-import, you should exclude module files,
-# since they will be recreated, and may cause churn. Uncomment if using
-# auto-import.
-# .idea/artifacts
-# .idea/compiler.xml
-# .idea/jarRepositories.xml
-# .idea/modules.xml
-# .idea/*.iml
-# .idea/modules
-# *.iml
-# *.ipr
-
-# CMake
-cmake-build-*/
-
-# Mongo Explorer plugin
-.idea/**/mongoSettings.xml
-
-# File-based project format
-*.iws
-
-# IntelliJ
-out/
-
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
-atlassian-ide-plugin.xml
-
-# Cursive Clojure plugin
-.idea/replstate.xml
-
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-fabric.properties
-
-# Editor-based Rest Client
-.idea/httpRequests
-
-# Android studio 3.1+ serialized cache file
-.idea/caches/build_file_checksums.ser
# ---> Eclipse
.metadata
diff --git a/README.md b/README.md
index 82f14e8..357572d 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,71 @@
# mapstruct-support
-Additional DefaultAccessorNamingStrategy to support fluent API withXYZ setters.
\ No newline at end of file
+Additional DefaultAccessorNamingStrategy to support fluent API withXYZ setters.
+
+Mapstruct default naming strategy detects the methods `withFirstName` and `withLastName` (see example below) as extra
+target fields are therefore cause an error, when the mapper is annotated with
+`unmappedTargetPolicy = ReportingPolicy.ERROR`.
+
+## Installation
+
+To use the extended naming strategy, just include it as project dependency alongside with mapstruct.
+
+```xml
+
+
+
+ org.mapstruct
+ mapstruct
+ 1.4.2.Final
+
+
+ de.muehlencord.mapstruct
+ mapstruct-support
+ 1.4.2
+
+
+```
+
+## Example
+
+```java
+public class Person {
+
+ private String firstName;
+ private String lastName;
+
+ // standard getter / setter - these are covered by mapstruct by default */
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ /* fluent setter - these are detected as extra setters and would
+ cause an mapping exception, if the mapper is annotated with
+ unmappedTargetPolicy = ReportingPolicy.ERROR.
+ */
+
+ public Person withFirstName(String firstName) {
+ this.firstName = firstName;
+ return this;
+ }
+
+ public Person withLastName(String lastName) {
+ this.lastName = lastName;
+ return this;
+ }
+}
+
+```
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..f530033
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,56 @@
+
+
+ 4.0.0
+
+ de.muehlencord.mapstruct
+ mapstruct-support
+ 1.4.2-SNAPSHOT
+
+
+ 11
+ 11
+
+
+ 2021
+
+ mapstruct-support
+ https://jomu.timelord.de/git/jomu/mapstruct-support
+
+
+ Gitea
+ https://jomu.timelord.de/git/jomu/mapstruct-support/issues
+
+
+
+ scm:git:https://jomu.timelord.de/git/jomu/mapstruct-support
+ scm:git:git@jomu.timelord.de:jomu/mapstruct-support.git
+ HEAD
+
+
+
+
+ Joern Muehlencord
+ joern@muehlencord.de
+
+ developer
+
+
+
+
+
+ Joern Muehlencord
+ https://www.muehlencord.de
+
+
+
+
+ org.mapstruct
+ mapstruct-processor
+ 1.4.2.Final
+
+
+
+
+
diff --git a/src/main/java/de/muehlencord/mapstruct/support/WitherAccessorNamingStrategy.java b/src/main/java/de/muehlencord/mapstruct/support/WitherAccessorNamingStrategy.java
new file mode 100644
index 0000000..a6e8ad3
--- /dev/null
+++ b/src/main/java/de/muehlencord/mapstruct/support/WitherAccessorNamingStrategy.java
@@ -0,0 +1,26 @@
+package de.muehlencord.mapstruct.support;
+
+import javax.lang.model.element.ExecutableElement;
+import org.mapstruct.ap.spi.DefaultAccessorNamingStrategy;
+
+/**
+ * MapStruct naming strategy to to support fluent API withXYZ setters. When this strategy is applied, the wither are
+ * ignored so just the normal setter are used.
+ *
+ * @author Joern Muehlencord, 2021-05-01
+ * @since 1.4.2
+ */
+public class WitherAccessorNamingStrategy extends DefaultAccessorNamingStrategy {
+
+ @Override
+ protected boolean isFluentSetter(ExecutableElement method) {
+ return !isWitherMethod(method) && super.isFluentSetter(method);
+ }
+
+ protected boolean isWitherMethod(ExecutableElement method) {
+ String methodName = method.getSimpleName().toString();
+ return methodName.length() > 4 && methodName.startsWith("with") && Character.isUpperCase(methodName.charAt(4));
+ }
+
+
+}
diff --git a/src/main/resources/META-INF/services/org.mapstruct.ap.spi.AccessorNamingStrategy b/src/main/resources/META-INF/services/org.mapstruct.ap.spi.AccessorNamingStrategy
new file mode 100644
index 0000000..4e5d9d3
--- /dev/null
+++ b/src/main/resources/META-INF/services/org.mapstruct.ap.spi.AccessorNamingStrategy
@@ -0,0 +1 @@
+de.muehlencord.mapstruct.support.WitherAccessorNamingStrategy
diff --git a/src/test/java/de/muehlencord/mapstruct/support/Person.java b/src/test/java/de/muehlencord/mapstruct/support/Person.java
new file mode 100644
index 0000000..036ae42
--- /dev/null
+++ b/src/test/java/de/muehlencord/mapstruct/support/Person.java
@@ -0,0 +1,45 @@
+package de.muehlencord.mapstruct.support;
+
+/**
+ * Example class used in README.md
+ *
+ * @author Joern Muehlencord, 2021-05-01
+ * @since 1.4.2
+ */
+public class Person {
+
+ private String firstName;
+ private String lastName;
+
+ // standard getter / setter - these are covered by mapstruct by default */
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ /* fluent setter - these are detected as extra setters and would
+ cause an mapping exception, if the mapper is annotated with
+ unmappedTargetPolicy = ReportingPolicy.ERROR.
+ */
+
+ public Person withFirstName(String firstName) {
+ this.firstName = firstName;
+ return this;
+ }
+
+ public Person withLastName(String lastName) {
+ this.lastName = lastName;
+ return this;
+ }
+}