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; + } +}