From 7e16aa05c067201342c5678ec862cb6f5d9494eb Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 24 Oct 2020 18:24:49 +0200 Subject: [PATCH 01/15] #2245 Local variable should be created when using default value --- .../ap/internal/model/PropertyMapping.java | 9 ++- .../ap/test/bugs/_2245/Issue2245Test.java | 42 ++++++++++++++ .../ap/test/bugs/_2245/TestMapper.java | 55 +++++++++++++++++++ .../ap/test/bugs/_2245/TestMapperImpl.java | 50 +++++++++++++++++ 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2245/Issue2245Test.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2245/TestMapper.java create mode 100644 processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_2245/TestMapperImpl.java 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 240343ad9b..dbda3daac3 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 @@ -374,6 +374,11 @@ private Assignment getDefaultValueAssignment( Assignment rhs ) { return null; } + private boolean hasDefaultValueAssignment(Assignment rhs) { + return ( defaultValue != null || defaultJavaExpression != null ) && + ( !rhs.getSourceType().isPrimitive() || rhs.getSourcePresenceCheckerReference() != null); + } + private Assignment assignToPlain(Type targetType, AccessorType targetAccessorType, Assignment rightHandSide) { @@ -415,7 +420,9 @@ private Assignment assignToPlainViaSetter(Type targetType, Assignment rhs) { ); } else { - boolean includeSourceNullCheck = SetterWrapper.doSourceNullCheck( rhs, nvcs, nvpms, targetType ); + // If the property mapping has a default value assignment then we have to do a null value check + boolean includeSourceNullCheck = SetterWrapper.doSourceNullCheck( rhs, nvcs, nvpms, targetType ) + || hasDefaultValueAssignment( rhs ); if ( !includeSourceNullCheck ) { // solution for #834 introduced a local var and null check for nested properties always. // however, a local var is not needed if there's no need to check for null. diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2245/Issue2245Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2245/Issue2245Test.java new file mode 100644 index 0000000000..5aa899d055 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2245/Issue2245Test.java @@ -0,0 +1,42 @@ +/* + * 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._2245; + +import org.junit.Rule; +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 org.mapstruct.ap.testutil.runner.GeneratedSource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Filip Hrisafov + */ +@IssueKey("2245") +@RunWith(AnnotationProcessorTestRunner.class) +@WithClasses({ + TestMapper.class +}) +public class Issue2245Test { + + @Rule + public final GeneratedSource generatedSource = new GeneratedSource() + .addComparisonToFixtureFor( TestMapper.class ); + + @Test + public void shouldGenerateSourceGetMethodOnce() { + + TestMapper.Tenant tenant = + TestMapper.INSTANCE.map( new TestMapper.TenantDTO( new TestMapper.Inner( "acme" ) ) ); + + assertThat( tenant ).isNotNull(); + assertThat( tenant.getId() ).isEqualTo( "acme" ); + + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2245/TestMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2245/TestMapper.java new file mode 100644 index 0000000000..750ee12fa5 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2245/TestMapper.java @@ -0,0 +1,55 @@ +/* + * 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._2245; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface TestMapper { + + TestMapper INSTANCE = Mappers.getMapper( TestMapper.class ); + + class Tenant { + private String id; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + } + + class Inner { + private final String id; + + public Inner(String id) { + this.id = id; + } + + public String getId() { + return id; + } + } + + class TenantDTO { + private final Inner inner; + + public TenantDTO(Inner inner) { + this.inner = inner; + } + + public Inner getInner() { + return inner; + } + } + + @Mapping(target = "id", source = "inner.id", defaultValue = "test") + Tenant map(TenantDTO tenant); +} diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_2245/TestMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_2245/TestMapperImpl.java new file mode 100644 index 0000000000..c3ecc02911 --- /dev/null +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/bugs/_2245/TestMapperImpl.java @@ -0,0 +1,50 @@ +/* + * 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._2245; + +import javax.annotation.Generated; + +@Generated( + value = "org.mapstruct.ap.MappingProcessor", + date = "2020-10-24T17:57:23+0200", + comments = "version: , compiler: javac, environment: Java 1.8.0_202 (AdoptOpenJdk)" +) +public class TestMapperImpl implements TestMapper { + + @Override + public Tenant map(TenantDTO tenant) { + if ( tenant == null ) { + return null; + } + + Tenant tenant1 = new Tenant(); + + String id = tenantInnerId( tenant ); + if ( id != null ) { + tenant1.setId( id ); + } + else { + tenant1.setId( "test" ); + } + + return tenant1; + } + + private String tenantInnerId(TenantDTO tenantDTO) { + if ( tenantDTO == null ) { + return null; + } + Inner inner = tenantDTO.getInner(); + if ( inner == null ) { + return null; + } + String id = inner.getId(); + if ( id == null ) { + return null; + } + return id; + } +} From b90c0a9f07f23c8931d82d2beb7418b4e055ed08 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 24 Oct 2020 17:46:20 +0200 Subject: [PATCH 02/15] #2244 Mark mapstruct-processor jar as Spring-Boot-Jar-Type: annotation-processor Doing this would make sure that starting from Spring Boot 2.4 the mapstruct-processor will not be included in the fat jar produced by the Spring Boot maven plugin if people have it as a maven provided dependency. This is an alternative if people are not using the maven-compiler-plugin annotationProcessorPaths --- processor/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/processor/pom.xml b/processor/pom.xml index bbec83bf29..2ff5d2d186 100644 --- a/processor/pom.xml +++ b/processor/pom.xml @@ -123,6 +123,7 @@ org.mapstruct.processor + annotation-processor From e8713fb432a981fa32b7e7db9d0b7aeba13a6dfb Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 31 Oct 2020 12:56:25 +0100 Subject: [PATCH 03/15] #2251 Fix incorrect code generated for constructor mapping from implicit source parameter matching --- .../ap/internal/model/BeanMappingMethod.java | 1 + .../ap/test/bugs/_2251/Issue2251Mapper.java | 20 ++++++++++ .../ap/test/bugs/_2251/Issue2251Test.java | 37 +++++++++++++++++++ .../mapstruct/ap/test/bugs/_2251/Source.java | 22 +++++++++++ .../mapstruct/ap/test/bugs/_2251/Target.java | 24 ++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Issue2251Mapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Issue2251Test.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Source.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Target.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java index 4d086b5126..b17e060848 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java @@ -1315,6 +1315,7 @@ private void applyParameterNameBasedMapping() { sourceParameters.remove(); unprocessedDefinedTargets.remove( targetProperty.getKey() ); unprocessedSourceProperties.remove( targetProperty.getKey() ); + unprocessedConstructorProperties.remove( targetProperty.getKey() ); } } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Issue2251Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Issue2251Mapper.java new file mode 100644 index 0000000000..d09f3440fe --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Issue2251Mapper.java @@ -0,0 +1,20 @@ +/* + * 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._2251; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface Issue2251Mapper { + + Issue2251Mapper INSTANCE = Mappers.getMapper( Issue2251Mapper.class ); + + @Mapping(target = "value1", source = "source.value") + Target map(Source source, String value2); + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Issue2251Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Issue2251Test.java new file mode 100644 index 0000000000..d08a5f7d74 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Issue2251Test.java @@ -0,0 +1,37 @@ +/* + * 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._2251; + +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; + +/** + * @author Filip Hrisafov + */ +@IssueKey("2251") +@RunWith(AnnotationProcessorTestRunner.class) +@WithClasses({ + Issue2251Mapper.class, + Source.class, + Target.class, +}) +public class Issue2251Test { + + @Test + public void shouldGenerateCorrectCode() { + + Target target = Issue2251Mapper.INSTANCE.map( new Source( "source" ), "test" ); + + assertThat( target ).isNotNull(); + assertThat( target.getValue1() ).isEqualTo( "source" ); + assertThat( target.getValue2() ).isEqualTo( "test" ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Source.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Source.java new file mode 100644 index 0000000000..cbd882a8f8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Source.java @@ -0,0 +1,22 @@ +/* + * 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._2251; + +/** + * @author Filip Hrisafov + */ +public class Source { + + private final String value; + + public Source(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Target.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Target.java new file mode 100644 index 0000000000..363129797f --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2251/Target.java @@ -0,0 +1,24 @@ +/* + * 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._2251; + +public class Target { + private final String value1; + private final String value2; + + public Target(String value1, String value2) { + this.value1 = value1; + this.value2 = value2; + } + + public String getValue1() { + return value1; + } + + public String getValue2() { + return value2; + } +} From 5727d20ce3c165ad468a0be5ed10a881ddc170b9 Mon Sep 17 00:00:00 2001 From: Nikolas Charalambidis Date: Wed, 4 Nov 2020 21:39:06 +0100 Subject: [PATCH 04/15] #2258 Fixes vague description of @Default and @ConstructorProperties annotations --- ...er-14-third-party-api-integration.asciidoc | 41 +++++++++++++++++++ .../chapter-3-defining-a-mapper.asciidoc | 6 +-- .../mapstruct-reference-guide.asciidoc | 4 +- 3 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 documentation/src/main/asciidoc/chapter-14-third-party-api-integration.asciidoc diff --git a/documentation/src/main/asciidoc/chapter-14-third-party-api-integration.asciidoc b/documentation/src/main/asciidoc/chapter-14-third-party-api-integration.asciidoc new file mode 100644 index 0000000000..03e18167e3 --- /dev/null +++ b/documentation/src/main/asciidoc/chapter-14-third-party-api-integration.asciidoc @@ -0,0 +1,41 @@ +[[third-party-api-integration]] +== Third-party API integration + +[[non-shipped-annotations]] +=== Non-shipped annotations + +There are various use-cases you must resolve ambiguity for MapStruct to use a correct piece of code. +However, the primary goal of MapStruct is to focus on bean mapping without polluting the entity code. +For that reason, MapStruct is flexible enough to interact with already defined annotations from third-party libraries. +The requirement to enable this behavior is to match the _name_ of such annotation. +Hence, we say that annotation can be _from any package_. + +The annotations _named_ `@ConstructorProperties` and `@Default` are currently examples of this kind of annotation. + +[WARNING] +==== +If such named third-party annotation exists, it does not guarantee its `@Target` matches with the intended placement. +Be aware of placing a third-party annotation just for sake of mapping is not recommended as long as it might lead to unwanted side effects caused by that library. +==== + +A very common case is that no third-party dependency imported to your project provides such annotation or is inappropriate for use as already described. +In such cases create your own annotation, for example: + +==== +[source, java, linenums] +[subs="verbatim,attributes"] +---- +package foo.support.mapstruct; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.CONSTRUCTOR) +@Retention(RetentionPolicy.CLASS) +public @interface Default { + +} +---- +==== \ No newline at end of file diff --git a/documentation/src/main/asciidoc/chapter-3-defining-a-mapper.asciidoc b/documentation/src/main/asciidoc/chapter-3-defining-a-mapper.asciidoc index 54a0dbd709..acdfd98174 100644 --- a/documentation/src/main/asciidoc/chapter-3-defining-a-mapper.asciidoc +++ b/documentation/src/main/asciidoc/chapter-3-defining-a-mapper.asciidoc @@ -537,10 +537,10 @@ When doing a mapping MapStruct checks if there is a builder for the type being m If there is no builder, then MapStruct looks for a single accessible constructor. When there are multiple constructors then the following is done to pick the one which should be used: -* If a constructor is annotated with an annotation named `@Default` (from any package) it will be used. +* If a constructor is annotated with an annotation _named_ `@Default` (from any package, see <>) it will be used. * If a single public constructor exists then it will be used to construct the object, and the other non public constructors will be ignored. * If a parameterless constructor exists then it will be used to construct the object, and the other constructors will be ignored. -* If there are multiple eligible constructors then there will be a compilation error due to ambiguous constructors. In order to break the ambiguity an annotation named `@Default` (from any package) can used. +* If there are multiple eligible constructors then there will be a compilation error due to ambiguous constructors. In order to break the ambiguity an annotation _named_ `@Default` (from any package, see <>) can used. .Deciding which constructor to use ==== @@ -585,7 +585,7 @@ public class Van { ==== When using a constructor then the names of the parameters of the constructor will be used and matched to the target properties. -When the constructor has an annotation named `@ConstructorProperties` (from any package) then this annotation will be used to get the names of the parameters. +When the constructor has an annotation _named_ `@ConstructorProperties` (from any package, see <>) then this annotation will be used to get the names of the parameters. [NOTE] ==== diff --git a/documentation/src/main/asciidoc/mapstruct-reference-guide.asciidoc b/documentation/src/main/asciidoc/mapstruct-reference-guide.asciidoc index 1aa08b17b8..b83c874c5e 100644 --- a/documentation/src/main/asciidoc/mapstruct-reference-guide.asciidoc +++ b/documentation/src/main/asciidoc/mapstruct-reference-guide.asciidoc @@ -44,4 +44,6 @@ include::chapter-11-reusing-mapping-configurations.asciidoc[] include::chapter-12-customizing-mapping.asciidoc[] -include::chapter-13-using-mapstruct-spi.asciidoc[] \ No newline at end of file +include::chapter-13-using-mapstruct-spi.asciidoc[] + +include::chapter-14-third-party-api-integration.asciidoc[] \ No newline at end of file From 934d096fb4f9b6755b84c239abfbe79b6ff878fd Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Mon, 2 Nov 2020 22:26:17 +0100 Subject: [PATCH 05/15] #2263 Fix IndexOutOfBoundsException when resolving TypeVar to a Type --- .../ap/internal/model/common/Type.java | 7 +++- .../test/bugs/_2263/Erroneous2263Mapper.java | 17 ++++++++ .../ap/test/bugs/_2263/Issue2263Test.java | 41 +++++++++++++++++++ .../mapstruct/ap/test/bugs/_2263/Source.java | 22 ++++++++++ .../mapstruct/ap/test/bugs/_2263/Target.java | 22 ++++++++++ 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Erroneous2263Mapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Issue2263Test.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Source.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Target.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java index b2b12b8a25..6bb6d7369b 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java @@ -1160,7 +1160,12 @@ public Type visitTypeVariable(TypeVariable t, Type parameterized) { @Override public Type visitDeclared(DeclaredType t, Type parameterized) { if ( types.isAssignable( types.erasure( t ), types.erasure( parameterized.getTypeMirror() ) ) ) { - // if same type, we can cast en assume number of type args are also the same + // We can't assume that the type args are the same + // e.g. List is assignable to Object + if ( t.getTypeArguments().size() != parameterized.getTypeParameters().size() ) { + return super.visitDeclared( t, parameterized ); + } + for ( int i = 0; i < t.getTypeArguments().size(); i++ ) { Type result = visit( t.getTypeArguments().get( i ), parameterized.getTypeParameters().get( i ) ); if ( result != null ) { diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Erroneous2263Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Erroneous2263Mapper.java new file mode 100644 index 0000000000..59a0a42ddb --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Erroneous2263Mapper.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.bugs._2263; + +import org.mapstruct.Mapper; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface Erroneous2263Mapper { + + Target map(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Issue2263Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Issue2263Test.java new file mode 100644 index 0000000000..03e545b210 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Issue2263Test.java @@ -0,0 +1,41 @@ +/* + * 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._2263; + +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.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; + +/** + * @author Filip Hrisafov + */ +@IssueKey("2263") +@RunWith(AnnotationProcessorTestRunner.class) +@WithClasses({ + Erroneous2263Mapper.class, + Source.class, + Target.class, +}) +public class Issue2263Test { + + @Test + @ExpectedCompilationOutcome(value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = Erroneous2263Mapper.class, + kind = javax.tools.Diagnostic.Kind.ERROR, + line = 16, + message = "Can't map property \"Object value\" to \"String value\". " + + "Consider to declare/implement a mapping method: \"String map(Object value)\".") + }) + public void shouldCorrectlyReportUnmappableTargetObject() { + + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Source.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Source.java new file mode 100644 index 0000000000..54e5b7fd38 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Source.java @@ -0,0 +1,22 @@ +/* + * 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._2263; + +/** + * @author Filip Hrisafov + */ +public class Source { + + private final Object value; + + public Source(Object value) { + this.value = value; + } + + public Object getValue() { + return value; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Target.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Target.java new file mode 100644 index 0000000000..943a51264c --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2263/Target.java @@ -0,0 +1,22 @@ +/* + * 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._2263; + +/** + * @author Filip Hrisafov + */ +public class Target { + + private final String value; + + public Target(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} From 628ff175e0af2212120d4593e47117eb98d9da08 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Fri, 6 Nov 2020 21:24:52 +0100 Subject: [PATCH 06/15] #2253 remove unmapped source properties when source parameter is directly mapped --- .../ap/internal/model/BeanMappingMethod.java | 10 ++++ .../ap/test/bugs/_2253/Issue2253Test.java | 34 +++++++++++++ .../ap/test/bugs/_2253/TestMapper.java | 48 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2253/Issue2253Test.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2253/TestMapper.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java index b17e060848..d19fb4f398 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java @@ -1315,6 +1315,16 @@ private void applyParameterNameBasedMapping() { sourceParameters.remove(); unprocessedDefinedTargets.remove( targetProperty.getKey() ); unprocessedSourceProperties.remove( targetProperty.getKey() ); + + // The source parameter was directly mapped so ignore all of its source properties completely + if ( !sourceParameter.getType().isPrimitive() && !sourceParameter.getType().isArrayType() ) { + // We explicitly ignore source properties from primitives or array types + Map readAccessors = sourceParameter.getType().getPropertyReadAccessors(); + for ( String sourceProperty : readAccessors.keySet() ) { + unprocessedSourceProperties.remove( sourceProperty ); + } + } + unprocessedConstructorProperties.remove( targetProperty.getKey() ); } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2253/Issue2253Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2253/Issue2253Test.java new file mode 100644 index 0000000000..fc0e007daa --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2253/Issue2253Test.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._2253; + +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; + +/** + * @author Filip Hrisafov + */ +@IssueKey("2253") +@RunWith( AnnotationProcessorTestRunner.class ) +@WithClasses( { + TestMapper.class, +} ) +public class Issue2253Test { + + @Test + public void shouldNotTreatMatchedSourceParameterAsBean() { + + TestMapper.Person person = TestMapper.INSTANCE.map( new TestMapper.PersonDto( 20 ), "Tester" ); + + assertThat( person.getAge() ).isEqualTo( 20 ); + assertThat( person.getName() ).isEqualTo( "Tester" ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2253/TestMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2253/TestMapper.java new file mode 100644 index 0000000000..1e05e444a2 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2253/TestMapper.java @@ -0,0 +1,48 @@ +/* + * 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._2253; + +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper(unmappedSourcePolicy = ReportingPolicy.ERROR) +public interface TestMapper { + + TestMapper INSTANCE = Mappers.getMapper( TestMapper.class ); + + Person map(PersonDto personDto, String name); + + class Person { + private final int age; + private final String name; + + public Person(int age, String name) { + this.age = age; + this.name = name; + } + + public int getAge() { + return age; + } + + public String getName() { + return name; + } + } + + class PersonDto { + private final int age; + + public PersonDto(int age) { + this.age = age; + } + + public int getAge() { + return age; + } + } +} From 164535e3542f2fab0543eed2da4a3bc1fb32ccd9 Mon Sep 17 00:00:00 2001 From: Nikolas Charalambidis Date: Wed, 11 Nov 2020 22:28:53 +0100 Subject: [PATCH 07/15] Add Lombok subsection in the documentation (#2266) --- ...er-14-third-party-api-integration.asciidoc | 151 +++++++++++++++++- .../chapter-3-defining-a-mapper.asciidoc | 3 +- 2 files changed, 152 insertions(+), 2 deletions(-) diff --git a/documentation/src/main/asciidoc/chapter-14-third-party-api-integration.asciidoc b/documentation/src/main/asciidoc/chapter-14-third-party-api-integration.asciidoc index 03e18167e3..c31424a0de 100644 --- a/documentation/src/main/asciidoc/chapter-14-third-party-api-integration.asciidoc +++ b/documentation/src/main/asciidoc/chapter-14-third-party-api-integration.asciidoc @@ -38,4 +38,153 @@ public @interface Default { } ---- -==== \ No newline at end of file +==== + +[[lombok]] +=== Lombok + +MapStruct works together with https://projectlombok.org/[Project Lombok] as of MapStruct 1.2.0.Beta1 and Lombok 1.16.14. + +MapStruct takes advantage of generated getters, setters, and constructors and uses them to generate the mapper implementations. + +[NOTE] +==== +Lombok 1.18.16 introduces a breaking change (https://projectlombok.org/changelog[changelog]). +The additional annotation processor `lombok-mapstruct-binding` (https://mvnrepository.com/artifact/org.projectlombok/lombok-mapstruct-binding[Maven]) must be added otherwise MapStruct stops working with Lombok. +This resolves the compilation issues of Lombok and MapStruct modules. + +[source, xml] +---- + + org.projectlombok + lombok-mapstruct-binding + 0.1.0 + +---- +==== + +==== Set up + +The set up using Maven or Gradle does not differ from what is described in <>. Additionally, you need to provide Lombok dependencies. + +.Maven configuration +==== +[source, xml, linenums] +[subs="verbatim,attributes"] +---- + + + {mapstructVersion} + 1.18.16 + 1.8 + 1.8 + + + + + org.mapstruct + mapstruct + ${org.mapstruct.version} + + + + + org.projectlombok + lombok + ${org.projectlombok.version} + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + org.projectlombok + lombok + ${org.projectlombok.version} + + + + + org.projectlombok + lombok-mapstruct-binding + 0.1.0 + + + + + + +---- +==== + +.Gradle configuration (3.4 and later) +==== +[source, groovy, linenums] +[subs="verbatim,attributes"] +---- + +dependencies { + + implementation "org.mapstruct:mapstruct:${mapstructVersion}" + implementation "org.projectlombok:lombok:1.18.16" + annotationProcessor "org.projectlombok:lombok-mapstruct-binding:0.1.0" + annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}" + annotationProcessor "org.projectlombok:lombok:1.18.16" +} + +---- +==== + +The usage combines what you already know from <> and Lombok. + +.Usage of MapStruct with Lombok +==== +[source, java, linenums] +[subs="verbatim,attributes"] +---- +@Data +public class Source { + + private String test; +} + +public class Target { + + private Long testing; + + public Long getTesting() { + return testing; + } + + public void setTesting( Long testing ) { + this.testing = testing; + } +} + +@Mapper +public interface SourceTargetMapper { + + SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class ); + + @Mapping( source = "test", target = "testing" ) + Target toTarget( Source s ); +} + +---- +==== + +A working example can be found on the GitHub project https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-lombok[mapstruct-lombok]. diff --git a/documentation/src/main/asciidoc/chapter-3-defining-a-mapper.asciidoc b/documentation/src/main/asciidoc/chapter-3-defining-a-mapper.asciidoc index acdfd98174..be3435b541 100644 --- a/documentation/src/main/asciidoc/chapter-3-defining-a-mapper.asciidoc +++ b/documentation/src/main/asciidoc/chapter-3-defining-a-mapper.asciidoc @@ -516,7 +516,8 @@ public class PersonMapperImpl implements PersonMapper { Supported builder frameworks: -* https://projectlombok.org/[Lombok] - requires having the Lombok classes in a separate module. See for more information https://github.com/rzwitserloot/lombok/issues/1538[rzwitserloot/lombok#1538] +* https://projectlombok.org/[Lombok] - It is required to have the Lombok classes in a separate module. +See for more information at https://github.com/rzwitserloot/lombok/issues/1538[rzwitserloot/lombok#1538] and to set up Lombok with MapStruct, refer to <>. * https://github.com/google/auto/blob/master/value/userguide/index.md[AutoValue] * https://immutables.github.io/[Immutables] - When Immutables are present on the annotation processor path then the `ImmutablesAccessorNamingStrategy` and `ImmutablesBuilderProvider` would be used by default * https://github.com/google/FreeBuilder[FreeBuilder] - When FreeBuilder is present on the annotation processor path then the `FreeBuilderAccessorNamingStrategy` would be used by default. From 24ac2f3963920e5b1e77f725062b56b92167d02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20D=C3=BCsterhus?= Date: Mon, 14 Dec 2020 11:44:04 +0100 Subject: [PATCH 08/15] Update chapter-2-set-up.asciidoc See official maven doc on this: https://maven.apache.org/plugins/maven-compiler-plugin/examples/pass-compiler-arguments.html Otherwise for example intellij doesn't recognize the compiler options on maven import --- .../src/main/asciidoc/chapter-2-set-up.asciidoc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc b/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc index fb954ac58f..cb0067f2f3 100644 --- a/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc +++ b/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc @@ -187,15 +187,15 @@ When invoking javac directly, these options are passed to the compiler in the fo true - + -Amapstruct.suppressGeneratorTimestamp=true - - + + -Amapstruct.suppressGeneratorVersionInfoComment=true - - + + -Amapstruct.verbose=true - + From e6479dce87380ba02de3d464a94b6b84288ac25e Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 5 Dec 2020 10:29:48 +0100 Subject: [PATCH 09/15] #2293 Use MapperConfig instead of MappingConfig in the documentation --- .../chapter-10-advanced-mapping-options.asciidoc | 12 ++++++------ .../chapter-5-data-type-conversions.asciidoc | 2 +- .../ap/internal/model/source/DefaultOptions.java | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/documentation/src/main/asciidoc/chapter-10-advanced-mapping-options.asciidoc b/documentation/src/main/asciidoc/chapter-10-advanced-mapping-options.asciidoc index ddf7fbcaed..4ccad69f2c 100644 --- a/documentation/src/main/asciidoc/chapter-10-advanced-mapping-options.asciidoc +++ b/documentation/src/main/asciidoc/chapter-10-advanced-mapping-options.asciidoc @@ -161,13 +161,13 @@ The mechanism is also present on iterable mapping and map mapping. `@IterableMap MapStruct offers control over the object to create when the source argument of the mapping method equals `null`. By default `null` will be returned. -However, by specifying `nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT` on `@BeanMapping`, `@IterableMapping`, `@MapMapping`, or globally on `@Mapper` or `@MappingConfig`, the mapping result can be altered to return empty *default* values. This means for: +However, by specifying `nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT` on `@BeanMapping`, `@IterableMapping`, `@MapMapping`, or globally on `@Mapper` or `@MapperConfig`, the mapping result can be altered to return empty *default* values. This means for: * *Bean mappings*: an 'empty' target bean will be returned, with the exception of constants and expressions, they will be populated when present. * *Iterables / Arrays*: an empty iterable will be returned. * *Maps*: an empty map will be returned. -The strategy works in a hierarchical fashion. Setting `nullValueMappingStrategy` on mapping method level will override `@Mapper#nullValueMappingStrategy`, and `@Mapper#nullValueMappingStrategy` will override `@MappingConfig#nullValueMappingStrategy`. +The strategy works in a hierarchical fashion. Setting `nullValueMappingStrategy` on mapping method level will override `@Mapper#nullValueMappingStrategy`, and `@Mapper#nullValueMappingStrategy` will override `@MapperConfig#nullValueMappingStrategy`. [[mapping-result-for-null-properties]] @@ -179,13 +179,13 @@ By default the target property will be set to null. However: -1. By specifying `nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT` on `@Mapping`, `@BeanMapping`, `@Mapper` or `@MappingConfig`, the mapping result can be altered to return *default* values. +1. By specifying `nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT` on `@Mapping`, `@BeanMapping`, `@Mapper` or `@MapperConfig`, the mapping result can be altered to return *default* values. For `List` MapStruct generates an `ArrayList`, for `Map` a `HashMap`, for arrays an empty array, for `String` `""` and for primitive / boxed types a representation of `false` or `0`. For all other objects an new instance is created. Please note that a default constructor is required. If not available, use the `@Mapping#defaultValue`. -2. By specifying `nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE` on `@Mapping`, `@BeanMapping`, `@Mapper` or `@MappingConfig`, the mapping result will be equal to the original value of the `@MappingTarget` annotated target. +2. By specifying `nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE` on `@Mapping`, `@BeanMapping`, `@Mapper` or `@MapperConfig`, the mapping result will be equal to the original value of the `@MappingTarget` annotated target. -The strategy works in a hierarchical fashion. Setting `nullValuePropertyMappingStrategy` on mapping method level will override `@Mapper#nullValuePropertyMappingStrategy`, and `@Mapper#nullValuePropertyMappingStrategy` will override `@MappingConfig#nullValuePropertyMappingStrategy`. +The strategy works in a hierarchical fashion. Setting `nullValuePropertyMappingStrategy` on mapping method level will override `@Mapper#nullValuePropertyMappingStrategy`, and `@Mapper#nullValuePropertyMappingStrategy` will override `@MapperConfig#nullValuePropertyMappingStrategy`. [NOTE] ==== @@ -213,7 +213,7 @@ First calling a mapping method on the source property is not protected by a null The option `nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS` will always include a null check when source is non primitive, unless a source presence checker is defined on the source bean. -The strategy works in a hierarchical fashion. `@Mapping#nullValueCheckStrategy` will override `@BeanMapping#nullValueCheckStrategy`, `@BeanMapping#nullValueCheckStrategy` will override `@Mapper#nullValueCheckStrategy` and `@Mapper#nullValueCheckStrategy` will override `@MappingConfig#nullValueCheckStrategy`. +The strategy works in a hierarchical fashion. `@Mapping#nullValueCheckStrategy` will override `@BeanMapping#nullValueCheckStrategy`, `@BeanMapping#nullValueCheckStrategy` will override `@Mapper#nullValueCheckStrategy` and `@Mapper#nullValueCheckStrategy` will override `@MaperConfig#nullValueCheckStrategy`. [[source-presence-check]] === Source presence checking diff --git a/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc b/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc index 725c69bad0..9619d0fe26 100644 --- a/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc +++ b/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc @@ -155,7 +155,7 @@ When generating the implementation of a mapping method, MapStruct will apply the . If no such method was found MapStruct will try to generate an automatic sub-mapping method that will do the mapping between the source and target attributes. . If MapStruct could not create a name based mapping method an error will be raised at build time, indicating the non-mappable attribute and its path. -A mapping control (`MappingControl`) can be defined on all levels (`@MappingConfig`, `@Mapper`, `@BeanMapping`, `@Mapping`), the latter taking precedence over the former. For example: `@Mapper( mappingControl = NoComplexMapping.class )` takes precedence over `@MapperConfig( mappingControl = DeepClone.class )`. `@IterableMapping` and `@MapMapping` work similar as `@Mapping`. MappingControl is experimental from MapStruct 1.4. +A mapping control (`MappingControl`) can be defined on all levels (`@MapperConfig`, `@Mapper`, `@BeanMapping`, `@Mapping`), the latter taking precedence over the former. For example: `@Mapper( mappingControl = NoComplexMapping.class )` takes precedence over `@MapperConfig( mappingControl = DeepClone.class )`. `@IterableMapping` and `@MapMapping` work similar as `@Mapping`. MappingControl is experimental from MapStruct 1.4. `MappingControl` has an enum that corresponds to the first 4 options above: `MappingControl.Use#DIRECT`, `MappingControl.Use#MAPPING_METHOD`, `MappingControl.Use#BUILT_IN_CONVERSION` and `MappingControl.Use#COMPLEX_MAPPING` the presence of which allows the user to switch *on* a option. The absence of an enum switches *off* a mapping option. Default they are all present enabling all mapping options. [NOTE] diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/DefaultOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/DefaultOptions.java index 81f870e25b..ecc05888d6 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/DefaultOptions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/DefaultOptions.java @@ -119,7 +119,7 @@ public NullValueMappingStrategyGem getNullValueMappingStrategy() { public BuilderGem getBuilder() { // TODO: I realized this is not correct, however it needs to be null in order to keep downward compatibility // but assuming a default @Builder will make testcases fail. Not having a default means that you need to - // specify this mandatory on @MappingConfig and @Mapper. + // specify this mandatory on @MapperConfig and @Mapper. return null; } From 15b3469f04f78a290af9429f3a257b198fe04aa0 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 19 Dec 2020 19:50:32 +0100 Subject: [PATCH 10/15] #2301 Implicitly ignore forward inherited mappings from different method types --- .../ap/internal/model/BeanMappingMethod.java | 9 +++ .../ap/test/bugs/_2301/Artifact.java | 66 +++++++++++++++++++ .../ap/test/bugs/_2301/ArtifactDto.java | 22 +++++++ .../ap/test/bugs/_2301/Issue2301Mapper.java | 28 ++++++++ .../ap/test/bugs/_2301/Issue2301Test.java | 40 +++++++++++ 5 files changed, 165 insertions(+) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Artifact.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/ArtifactDto.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Issue2301Mapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Issue2301Test.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java index d19fb4f398..898f7df8a0 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/BeanMappingMethod.java @@ -938,6 +938,15 @@ private boolean handleDefinedMapping(MappingReference mappingRef, Type resultTyp if ( targetWriteAccessor == null ) { if ( targetReadAccessor == null ) { + if ( mapping.getInheritContext() != null && mapping.getInheritContext().isForwarded() && + mapping.getInheritContext().getTemplateMethod().isUpdateMethod() != method.isUpdateMethod() ) { + // When a configuration is inherited and the template method is not same type as the current + // method then we can safely ignore this mapping. + // This means that a property which is inherited might be present for a direct mapping + // via the Builder, but not for an update mapping (directly on the object itself), + // or vice versa + return false; + } Set readAccessors = resultTypeToMap.getPropertyReadAccessors().keySet(); String mostSimilarProperty = Strings.getMostSimilarWord( targetPropertyName, readAccessors ); diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Artifact.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Artifact.java new file mode 100644 index 0000000000..316959f48b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Artifact.java @@ -0,0 +1,66 @@ +/* + * 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._2301; + +import java.util.Set; + +/** + * @author Filip Hrisafov + */ +public class Artifact { + + private String name; + private Set dependantBuildRecords; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getDependantBuildRecords() { + return dependantBuildRecords; + } + + public void setDependantBuildRecords(Set dependantBuildRecords) { + this.dependantBuildRecords = dependantBuildRecords; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private String name; + private Set dependantBuildRecords; + + public Artifact build() { + Artifact artifact = new Artifact(); + artifact.setName( name ); + artifact.setDependantBuildRecords( dependantBuildRecords ); + + return artifact; + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public Builder dependantBuildRecord(String dependantBuildRecord) { + this.dependantBuildRecords.add( dependantBuildRecord ); + return this; + } + + public Builder dependantBuildRecords(Set dependantBuildRecords) { + this.dependantBuildRecords = dependantBuildRecords; + return this; + } + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/ArtifactDto.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/ArtifactDto.java new file mode 100644 index 0000000000..68b9280930 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/ArtifactDto.java @@ -0,0 +1,22 @@ +/* + * 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._2301; + +/** + * @author Filip Hrisafov + */ +public class ArtifactDto { + + private final String name; + + public ArtifactDto(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Issue2301Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Issue2301Mapper.java new file mode 100644 index 0000000000..cd3cca3744 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Issue2301Mapper.java @@ -0,0 +1,28 @@ +/* + * 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._2301; + +import org.mapstruct.InheritConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.factory.Mappers; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface Issue2301Mapper { + + Issue2301Mapper INSTANCE = Mappers.getMapper( Issue2301Mapper.class ); + + @Mapping(target = "dependantBuildRecords", ignore = true) + @Mapping(target = "dependantBuildRecord", ignore = true) + Artifact map(ArtifactDto dto); + + @InheritConfiguration + void update(@MappingTarget Artifact artifact, ArtifactDto dto); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Issue2301Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Issue2301Test.java new file mode 100644 index 0000000000..8c237a2d30 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2301/Issue2301Test.java @@ -0,0 +1,40 @@ +/* + * 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._2301; + +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; + +/** + * @author Filip Hrisafov + */ +@IssueKey("2301") +@RunWith(AnnotationProcessorTestRunner.class) +@WithClasses({ + Artifact.class, + ArtifactDto.class, + Issue2301Mapper.class +}) +public class Issue2301Test { + + @Test + public void shouldCorrectlyIgnoreProperties() { + Artifact artifact = Issue2301Mapper.INSTANCE.map( new ArtifactDto( "mapstruct" ) ); + + assertThat( artifact ).isNotNull(); + assertThat( artifact.getName() ).isEqualTo( "mapstruct" ); + assertThat( artifact.getDependantBuildRecords() ).isNull(); + + Issue2301Mapper.INSTANCE.update( artifact, new ArtifactDto( "mapstruct-processor" ) ); + + assertThat( artifact.getName() ).isEqualTo( "mapstruct-processor" ); + } +} From 0c51f7a5aa37c6cece9a95050143630a5d83f26b Mon Sep 17 00:00:00 2001 From: Sjaak Derksen Date: Sat, 23 Jan 2021 09:15:46 +0100 Subject: [PATCH 11/15] #2278 inherited property ignored due to ignore on nested level (#2332) Co-authored-by: sjaakd --- .../model/source/MappingMethodOptions.java | 10 +- .../ap/test/bugs/_2278/Issue2278MapperA.java | 62 ++++++++++ .../ap/test/bugs/_2278/Issue2278MapperB.java | 65 ++++++++++ .../bugs/_2278/Issue2278ReferenceMapper.java | 54 ++++++++ .../ap/test/bugs/_2278/Issue2278Test.java | 95 +++++++++++++++ .../ap/test/bugs/_2318/Issue2318Mapper.java | 115 ++++++++++++++++++ .../ap/test/bugs/_2318/Issue2318Test.java | 38 ++++++ 7 files changed, 435 insertions(+), 4 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278MapperA.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278MapperB.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278ReferenceMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278Test.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2318/Issue2318Mapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2318/Issue2318Test.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingMethodOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingMethodOptions.java index b7fd7f00d0..859a4c6f5f 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingMethodOptions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MappingMethodOptions.java @@ -230,9 +230,11 @@ private void addAllNonRedefined(Set inheritedMappings) { } private boolean isRedefined(Set redefinedNames, String inheritedName ) { - for ( String redefinedName : redefinedNames ) { - if ( elementsAreContainedIn( redefinedName, inheritedName ) ) { - return true; + if ( inheritedName != null ) { + for ( String redefinedName : redefinedNames ) { + if ( elementsAreContainedIn( inheritedName, redefinedName ) ) { + return true; + } } } return false; @@ -241,7 +243,7 @@ private boolean isRedefined(Set redefinedNames, String inheritedName ) { private boolean elementsAreContainedIn( String redefinedName, String inheritedName ) { if ( inheritedName != null && redefinedName.startsWith( inheritedName ) ) { // it is possible to redefine an exact matching source name, because the same source can be mapped to - // multiple targets. It is not possible for target, but caught by the Set and equals methoded in + // multiple targets. It is not possible for target, but caught by the Set and equals method in // MappingOptions. SourceName == null also could hint at redefinition if ( redefinedName.length() > inheritedName.length() ) { // redefined.lenght() > inherited.length(), first following character should be separator diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278MapperA.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278MapperA.java new file mode 100644 index 0000000000..8527be3f89 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278MapperA.java @@ -0,0 +1,62 @@ +/* + * 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._2278; + +import org.mapstruct.InheritInverseConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * ReproducerA + * + */ +@Mapper +public interface Issue2278MapperA { + + Issue2278MapperA INSTANCE = Mappers.getMapper( Issue2278MapperA.class ); + + @Mapping( target = "detailsDTO", source = "details" ) + @Mapping( target = "detailsDTO.fuelType", ignore = true ) + CarDTO map(Car in); + + // checkout the Issue2278ReferenceMapper, the @InheritInverseConfiguration + // is de-facto @Mapping( target = "details", source = "detailsDTO" ) + @InheritInverseConfiguration + @Mapping( target = "details.model", ignore = true ) + @Mapping( target = "details.type", constant = "gto") + @Mapping( target = "details.fuel", source = "detailsDTO.fuelType") + Car map(CarDTO in); + + class Car { + //CHECKSTYLE:OFF + public Details details; + //CHECKSTYLE:ON + } + + class CarDTO { + //CHECKSTYLE:OFF + public DetailsDTO detailsDTO; + //CHECKSTYLE:ON + } + + class Details { + //CHECKSTYLE:OFF + public String brand; + public String model; + public String type; + public String fuel; + //CHECKSTYLE:ON + } + + class DetailsDTO { + //CHECKSTYLE:OFF + public String brand; + public String fuelType; + //CHECKSTYLE:ON + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278MapperB.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278MapperB.java new file mode 100644 index 0000000000..b9d0abd523 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278MapperB.java @@ -0,0 +1,65 @@ +/* + * 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._2278; + +import org.mapstruct.InheritInverseConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * ReproducerB + * + */ +@Mapper +public interface Issue2278MapperB { + + Issue2278MapperB INSTANCE = Mappers.getMapper( Issue2278MapperB.class ); + + // id mapping is cros-linked + @Mapping( target = "amount", source = "price" ) + @Mapping( target = "detailsDTO.brand", source = "details.type" ) + @Mapping( target = "detailsDTO.id1", source = "details.id2" ) + @Mapping( target = "detailsDTO.id2", source = "details.id1" ) + CarDTO map(Car in); + + // inherit inverse, but undo cross-link in one sweep + @InheritInverseConfiguration // inherits all + @Mapping( target = "details", source = "detailsDTO" ) // resets everything on details <> detailsDto + @Mapping( target = "details.type", source = "detailsDTO.brand" ) // so this needs to be redone + Car map2(CarDTO in); + + class Car { + //CHECKSTYLE:OFF + public float price; + public Details details; + //CHECKSTYLE:ON + } + + class CarDTO { + //CHECKSTYLE:OFF + public float amount; + public DetailsDTO detailsDTO; + //CHECKSTYLE:ON + } + + class Details { + //CHECKSTYLE:OFF + public String type; + public String id1; + public String id2; + //CHECKSTYLE:ON + } + + class DetailsDTO { + //CHECKSTYLE:OFF + public String brand; + public String id1; + public String id2; + //CHECKSTYLE:ON + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278ReferenceMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278ReferenceMapper.java new file mode 100644 index 0000000000..48b457f84c --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278ReferenceMapper.java @@ -0,0 +1,54 @@ +/* + * 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._2278; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * A reference mapper, that checks how a regular forward merge works + */ +@Mapper +public interface Issue2278ReferenceMapper { + + Issue2278ReferenceMapper INSTANCE = Mappers.getMapper( Issue2278ReferenceMapper.class ); + + @Mapping( target = "details", source = "detailsDTO" ) + @Mapping( target = "details.model", ignore = true ) + @Mapping( target = "details.type", constant = "gto") + @Mapping( target = "details.fuel", source = "detailsDTO.fuelType") + Car map(CarDTO in); + + class Car { + //CHECKSTYLE:OFF + public Details details; + //CHECKSTYLE:ON + } + + class CarDTO { + //CHECKSTYLE:OFF + public DetailsDTO detailsDTO; + //CHECKSTYLE:ON + } + + class Details { + //CHECKSTYLE:OFF + public String brand; + public String model; + public String type; + public String fuel; + //CHECKSTYLE:ON + } + + class DetailsDTO { + //CHECKSTYLE:OFF + public String brand; + public String fuelType; + //CHECKSTYLE:ON + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278Test.java new file mode 100644 index 0000000000..eefebfa870 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2278/Issue2278Test.java @@ -0,0 +1,95 @@ +/* + * 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._2278; + +import static org.assertj.core.api.Assertions.assertThat; + +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; + +@IssueKey("2278") +@RunWith( AnnotationProcessorTestRunner.class) +public class Issue2278Test { + + @Test + @WithClasses( Issue2278ReferenceMapper.class ) + public void testReferenceMergeBehaviour() { + + Issue2278ReferenceMapper.CarDTO dto = new Issue2278ReferenceMapper.CarDTO(); + dto.detailsDTO = new Issue2278ReferenceMapper.DetailsDTO(); + dto.detailsDTO.brand = "Ford"; + dto.detailsDTO.fuelType = "petrol"; + + Issue2278ReferenceMapper.Car target = Issue2278ReferenceMapper.INSTANCE.map( dto ); + + assertThat( target ).isNotNull(); + assertThat( target.details ).isNotNull(); + assertThat( target.details.brand ).isEqualTo( "Ford" ); + assertThat( target.details.model ).isNull(); + assertThat( target.details.type ).isEqualTo( "gto" ); + assertThat( target.details.fuel ).isEqualTo( "petrol" ); + + } + + @Test + @WithClasses( Issue2278MapperA.class ) + public void shouldBehaveJustAsTestReferenceMergeBehaviour() { + + Issue2278MapperA.CarDTO dto = new Issue2278MapperA.CarDTO(); + dto.detailsDTO = new Issue2278MapperA.DetailsDTO(); + dto.detailsDTO.brand = "Ford"; + dto.detailsDTO.fuelType = "petrol"; + + Issue2278MapperA.Car target = Issue2278MapperA.INSTANCE.map( dto ); + + assertThat( target ).isNotNull(); + assertThat( target.details ).isNotNull(); + assertThat( target.details.brand ).isEqualTo( "Ford" ); + assertThat( target.details.model ).isNull(); + assertThat( target.details.type ).isEqualTo( "gto" ); + assertThat( target.details.fuel ).isEqualTo( "petrol" ); + + } + + @Test + @WithClasses( Issue2278MapperB.class ) + public void shouldOverrideDetailsMappingWithRedefined() { + + Issue2278MapperB.Car source = new Issue2278MapperB.Car(); + source.details = new Issue2278MapperB.Details(); + source.details.type = "Ford"; + source.details.id1 = "id1"; + source.details.id2 = "id2"; + source.price = 20000f; + + Issue2278MapperB.CarDTO target1 = Issue2278MapperB.INSTANCE.map( source ); + + assertThat( target1 ).isNotNull(); + assertThat( target1.amount ).isEqualTo( 20000f ); + assertThat( target1.detailsDTO ).isNotNull(); + assertThat( target1.detailsDTO.brand ).isEqualTo( "Ford" ); + assertThat( target1.detailsDTO.id1 ).isEqualTo( "id2" ); + assertThat( target1.detailsDTO.id2 ).isEqualTo( "id1" ); + + // restore the mappings, just to make it logical again + target1.detailsDTO.id1 = "id1"; + target1.detailsDTO.id2 = "id2"; + + // now check the reverse inheritance + Issue2278MapperB.Car target2 = Issue2278MapperB.INSTANCE.map2( target1 ); + + assertThat( target2 ).isNotNull(); + assertThat( target2.price ).isEqualTo( 20000f ); + assertThat( target2.details ).isNotNull(); + assertThat( target2.details.type ).isEqualTo( "Ford" ); // should inherit + assertThat( target2.details.id1 ).isEqualTo( "id1" ); // should be undone + assertThat( target2.details.id2 ).isEqualTo( "id2" ); // should be undone + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2318/Issue2318Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2318/Issue2318Mapper.java new file mode 100644 index 0000000000..20621e4d01 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2318/Issue2318Mapper.java @@ -0,0 +1,115 @@ +/* + * 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._2318; + +import org.mapstruct.InheritConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.MapperConfig; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +@Mapper(config = Issue2318Mapper.Config.class) +public interface Issue2318Mapper { + + Issue2318Mapper INSTANCE = Mappers.getMapper( Issue2318Mapper.class ); + + @MapperConfig + interface Config { + + @Mapping(target = "parentValue1", source = "holder") + TargetParent mapParent(SourceParent parent); + + @InheritConfiguration(name = "mapParent") + @Mapping(target = "childValue", source = "value") + @Mapping(target = "parentValue2", source = "holder.parentValue2") + TargetChild mapChild(SourceChild child); + } + + @InheritConfiguration(name = "mapChild") + TargetChild mapChild(SourceChild child); + + default String parentValue1(SourceParent.Holder holder) { + return holder.getParentValue1(); + } + + class SourceParent { + private Holder holder; + + public Holder getHolder() { + return holder; + } + + public void setHolder(Holder holder) { + this.holder = holder; + } + + public static class Holder { + private String parentValue1; + private Integer parentValue2; + + public String getParentValue1() { + return parentValue1; + } + + public void setParentValue1(String parentValue1) { + this.parentValue1 = parentValue1; + } + + public Integer getParentValue2() { + return parentValue2; + } + + public void setParentValue2(Integer parentValue2) { + this.parentValue2 = parentValue2; + } + } + } + + class SourceChild extends SourceParent { + private String value; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + } + + class TargetParent { + private String parentValue1; + private Integer parentValue2; + + public String getParentValue1() { + return parentValue1; + } + + public void setParentValue1(String parentValue1) { + this.parentValue1 = parentValue1; + } + + public Integer getParentValue2() { + return parentValue2; + } + + public void setParentValue2(Integer parentValue2) { + this.parentValue2 = parentValue2; + } + } + + class TargetChild extends TargetParent { + private String childValue; + + public String getChildValue() { + return childValue; + } + + public void setChildValue(String childValue) { + this.childValue = childValue; + } + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2318/Issue2318Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2318/Issue2318Test.java new file mode 100644 index 0000000000..a1f1ad250b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2318/Issue2318Test.java @@ -0,0 +1,38 @@ +/* + * 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._2318; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.test.bugs._2318.Issue2318Mapper.SourceChild; +import org.mapstruct.ap.test.bugs._2318.Issue2318Mapper.TargetChild; +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; + +@IssueKey("2318") +@RunWith(AnnotationProcessorTestRunner.class) +public class Issue2318Test { + + @Test + @WithClasses( Issue2318Mapper.class ) + public void shouldMap() { + + SourceChild source = new SourceChild(); + source.setValue( "From child" ); + source.setHolder( new Issue2318Mapper.SourceParent.Holder() ); + source.getHolder().setParentValue1( "From parent" ); + source.getHolder().setParentValue2( 12 ); + + TargetChild target = Issue2318Mapper.INSTANCE.mapChild( source ); + + assertThat( target.getParentValue1() ).isEqualTo( "From parent" ); + assertThat( target.getParentValue2() ).isEqualTo( 12 ); + assertThat( target.getChildValue() ).isEqualTo( "From child" ); + } +} From bef3482af5e539ac0e5412cf9ba42037ea19a521 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 16 Jan 2021 19:43:22 +0100 Subject: [PATCH 12/15] #2250, #2324 Do not throw error when qualifier is missing on iterable mapping With this change we are relaxing the error handling when qualifiers are used in `@Mapping` and we allow defining qualifiers for collections / array mapping to mean the same as if it was defined on `@IterableMapping` i.e. apply the qualifier on the element mapping --- .../model/ContainerMappingMethodBuilder.java | 10 +++- .../ap/internal/model/PropertyMapping.java | 1 + .../creation/MappingResolverImpl.java | 8 +++- ...neousMessageByNamedWithIterableMapper.java | 31 ++++++++++++ .../qualifier/errors/QualfierMessageTest.java | 23 +++++++++ .../selection/qualifier/iterable/Cities.java | 23 +++++++++ .../iterable/IterableAndQualifiersTest.java | 40 +++++++++++++++- .../selection/qualifier/iterable/Rivers.java | 23 +++++++++ .../qualifier/iterable/TopologyMapper.java | 17 ------- .../TopologyWithoutIterableMappingMapper.java | 47 +++++++++++++++++++ 10 files changed, 203 insertions(+), 20 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/errors/ErroneousMessageByNamedWithIterableMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/Cities.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/Rivers.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/TopologyWithoutIterableMappingMapper.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/ContainerMappingMethodBuilder.java b/processor/src/main/java/org/mapstruct/ap/internal/model/ContainerMappingMethodBuilder.java index b9bbf6d094..be08ac1ca4 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/ContainerMappingMethodBuilder.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/ContainerMappingMethodBuilder.java @@ -22,6 +22,8 @@ import static org.mapstruct.ap.internal.util.Collections.first; +import javax.lang.model.element.AnnotationMirror; + /** * Builder that can be used to build {@link ContainerMappingMethod}(s). * @@ -37,6 +39,7 @@ public abstract class ContainerMappingMethodBuilder selfType, String errorMessagePart) { super( selfType ); @@ -58,6 +61,11 @@ public B callingContextTargetPropertyName(String callingContextTargetPropertyNam return myself; } + public B positionHint(AnnotationMirror positionHint) { + this.positionHint = positionHint; + return myself; + } + @Override public final M build() { Type sourceParameterType = first( method.getSourceParameters() ).getType(); @@ -88,7 +96,7 @@ public final M build() { formattingParameters, criteria, sourceRHS, - null, + positionHint, () -> forge( sourceRHS, sourceElementType, targetElementType ) ); 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 dbda3daac3..459c428058 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 @@ -617,6 +617,7 @@ private Assignment forgeWithElementMapping(Type sourceType, Type targetType, Sou .method( methodRef ) .selectionParameters( selectionParameters ) .callingContextTargetPropertyName( targetPropertyName ) + .positionHint( positionHint ) .build(); return createForgedAssignment( source, methodRef, iterableMappingMethod ); 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 73392a00f8..4394ab7b43 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 @@ -298,7 +298,13 @@ && allowDirect( sourceType, targetType ) ) { } if ( hasQualfiers() ) { - printQualifierMessage( selectionCriteria ); + if ((sourceType.isCollectionType() || sourceType.isArrayType()) && targetType.isIterableType()) { + // Allow forging iterable mapping when no iterable mapping already found + return forger.get(); + } + else { + printQualifierMessage( selectionCriteria ); + } } else if ( allowMappingMethod() ) { // only forge if we would allow mapping method diff --git a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/errors/ErroneousMessageByNamedWithIterableMapper.java b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/errors/ErroneousMessageByNamedWithIterableMapper.java new file mode 100644 index 0000000000..088207c610 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/errors/ErroneousMessageByNamedWithIterableMapper.java @@ -0,0 +1,31 @@ +/* + * 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.selection.qualifier.errors; + +import java.util.Collection; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper +public interface ErroneousMessageByNamedWithIterableMapper { + + @Mapping(target = "elements", qualifiedByName = "SelectMe") + Target map(Source source); + + // CHECKSTYLE:OFF + class Source { + + public Collection elements; + } + + class Target { + + public Collection elements; + } + // CHECKSTYLE ON + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/errors/QualfierMessageTest.java b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/errors/QualfierMessageTest.java index 4c8edc64dd..48295ed4fb 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/errors/QualfierMessageTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/errors/QualfierMessageTest.java @@ -87,4 +87,27 @@ public void testNoQualifyingMethodByNamedFound() { ) public void testNoQualifyingMethodByAnnotationAndNamedFound() { } + + @Test + @WithClasses(ErroneousMessageByNamedWithIterableMapper.class) + @ExpectedCompilationOutcome( + value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic( + type = ErroneousMessageByNamedWithIterableMapper.class, + kind = ERROR, + line = 16, + message = "Qualifier error. No method found annotated with @Named#value: [ SelectMe ]. " + + "See https://mapstruct.org/faq/#qualifier for more info."), + @Diagnostic( + type = ErroneousMessageByNamedWithIterableMapper.class, + kind = ERROR, + line = 16, + messageRegExp = "Can't map property.*"), + + } + ) + public void testNoQualifyingMethodByNamedForForgedIterableFound() { + } + } diff --git a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/Cities.java b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/Cities.java new file mode 100644 index 0000000000..828750399a --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/Cities.java @@ -0,0 +1,23 @@ +/* + * 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.selection.qualifier.iterable; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.mapstruct.Qualifier; + +/** + * @author Filip Hrisafov + */ +@Qualifier +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.CLASS) +public @interface Cities { + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/IterableAndQualifiersTest.java b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/IterableAndQualifiersTest.java index db8de9496e..c2465b255e 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/IterableAndQualifiersTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/IterableAndQualifiersTest.java @@ -15,6 +15,7 @@ import org.mapstruct.ap.testutil.IssueKey; import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; +import org.mapstruct.factory.Mappers; /** * @@ -22,20 +23,22 @@ */ @IssueKey( "707" ) @WithClasses( { + Cities.class, CityDto.class, CityEntity.class, RiverDto.class, RiverEntity.class, + Rivers.class, TopologyDto.class, TopologyEntity.class, TopologyFeatureDto.class, TopologyFeatureEntity.class, - TopologyMapper.class } ) @RunWith( AnnotationProcessorTestRunner.class ) public class IterableAndQualifiersTest { @Test + @WithClasses(TopologyMapper.class) public void testGenerationBasedOnQualifier() { TopologyDto topologyDto1 = new TopologyDto(); @@ -67,4 +70,39 @@ public void testGenerationBasedOnQualifier() { assertThat( ( (CityEntity) result2.getTopologyFeatures().get( 0 ) ).getPopulation() ).isEqualTo( 800000 ); } + + @Test + @WithClasses(TopologyWithoutIterableMappingMapper.class) + public void testIterableGeneratorBasedOnQualifier() { + + TopologyWithoutIterableMappingMapper mapper = Mappers.getMapper( TopologyWithoutIterableMappingMapper.class ); + + TopologyDto riverTopologyDto = new TopologyDto(); + List topologyFeatures1 = new ArrayList<>(); + RiverDto riverDto = new RiverDto(); + riverDto.setName( "Rhine" ); + riverDto.setLength( 5 ); + topologyFeatures1.add( riverDto ); + riverTopologyDto.setTopologyFeatures( topologyFeatures1 ); + + TopologyEntity riverTopology = mapper.mapTopologyAsRiver( riverTopologyDto ); + assertThat( riverTopology.getTopologyFeatures() ).hasSize( 1 ); + assertThat( riverTopology.getTopologyFeatures().get( 0 ).getName() ).isEqualTo( "Rhine" ); + assertThat( riverTopology.getTopologyFeatures().get( 0 ) ).isInstanceOf( RiverEntity.class ); + assertThat( ( (RiverEntity) riverTopology.getTopologyFeatures().get( 0 ) ).getLength() ).isEqualTo( 5 ); + + TopologyDto cityTopologyDto = new TopologyDto(); + List topologyFeatures2 = new ArrayList<>(); + CityDto cityDto = new CityDto(); + cityDto.setName( "Amsterdam" ); + cityDto.setPopulation( 800000 ); + topologyFeatures2.add( cityDto ); + cityTopologyDto.setTopologyFeatures( topologyFeatures2 ); + + TopologyEntity cityTopology = mapper.mapTopologyAsCity( cityTopologyDto ); + assertThat( cityTopology.getTopologyFeatures() ).hasSize( 1 ); + assertThat( cityTopology.getTopologyFeatures().get( 0 ).getName() ).isEqualTo( "Amsterdam" ); + assertThat( cityTopology.getTopologyFeatures().get( 0 ) ).isInstanceOf( CityEntity.class ); + assertThat( ( (CityEntity) cityTopology.getTopologyFeatures().get( 0 ) ).getPopulation() ).isEqualTo( 800000 ); + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/Rivers.java b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/Rivers.java new file mode 100644 index 0000000000..f6a56951a1 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/Rivers.java @@ -0,0 +1,23 @@ +/* + * 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.selection.qualifier.iterable; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.mapstruct.Qualifier; + +/** + * @author Filip Hrisafov + */ +@Qualifier +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.CLASS) +public @interface Rivers { + +} 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 22e87dd084..84c4bc58a1 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 @@ -5,16 +5,11 @@ */ package org.mapstruct.ap.test.selection.qualifier.iterable; -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; import org.mapstruct.factory.Mappers; /** @@ -64,16 +59,4 @@ protected TopologyFeatureEntity mapCity( TopologyFeatureDto dto ) { return topologyFeatureEntity; } - @Qualifier - @Target(ElementType.METHOD) - @Retention(RetentionPolicy.CLASS) - public @interface Rivers { - } - - @Qualifier - @Target(ElementType.METHOD) - @Retention(RetentionPolicy.CLASS) - public @interface Cities { - } - } diff --git a/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/TopologyWithoutIterableMappingMapper.java b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/TopologyWithoutIterableMappingMapper.java new file mode 100644 index 0000000000..4b72b34663 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/selection/qualifier/iterable/TopologyWithoutIterableMappingMapper.java @@ -0,0 +1,47 @@ +/* + * 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.selection.qualifier.iterable; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface TopologyWithoutIterableMappingMapper { + + @Mapping( target = "topologyFeatures", qualifiedBy = Rivers.class ) + TopologyEntity mapTopologyAsRiver(TopologyDto dto); + + @Mapping( target = "topologyFeatures", qualifiedBy = Cities.class ) + TopologyEntity mapTopologyAsCity(TopologyDto dto); + + @Rivers + default TopologyFeatureEntity mapRiver( TopologyFeatureDto dto ) { + TopologyFeatureEntity topologyFeatureEntity = null; + if ( dto instanceof RiverDto ) { + RiverEntity riverEntity = new RiverEntity(); + riverEntity.setLength( ( (RiverDto) dto ).getLength() ); + topologyFeatureEntity = riverEntity; + topologyFeatureEntity.setName( dto.getName() ); + } + return topologyFeatureEntity; + } + + @Cities + default TopologyFeatureEntity mapCity( TopologyFeatureDto dto ) { + TopologyFeatureEntity topologyFeatureEntity = null; + if ( dto instanceof CityDto ) { + CityEntity cityEntity = new CityEntity(); + cityEntity.setPopulation( ( (CityDto) dto ).getPopulation() ); + topologyFeatureEntity = cityEntity; + topologyFeatureEntity.setName( dto.getName() ); + } + return topologyFeatureEntity; + } + +} From 7d20cf27deb4017f8de0341950ca10d180859c10 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 30 Jan 2021 10:35:04 +0100 Subject: [PATCH 13/15] #2346 Update documentation and readme about MapStruct and Gradle Remove obsolete net.ltgt.apt Use com.diffplug.eclipse.apt for Eclipse IntelliJ works transparently --- .../main/asciidoc/chapter-2-set-up.asciidoc | 36 ++----------------- readme.md | 7 +--- 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc b/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc index cb0067f2f3..76626f44ce 100644 --- a/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc +++ b/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc @@ -76,7 +76,7 @@ It will not work with older versions. Add the following to your Gradle build file in order to enable MapStruct: -.Gradle configuration (3.4 and later) +.Gradle configuration ==== [source, groovy, linenums] [subs="verbatim,attributes"] @@ -84,14 +84,9 @@ Add the following to your Gradle build file in order to enable MapStruct: ... plugins { ... - id 'net.ltgt.apt' version '0.20' + id "com.diffplug.eclipse.apt" version "3.26.0" // Only for Eclipse } -// You can integrate with your IDEs. -// See more details: https://github.com/tbroyer/gradle-apt-plugin#usage-with-ides -apply plugin: 'net.ltgt.apt-idea' -apply plugin: 'net.ltgt.apt-eclipse' - dependencies { ... implementation "org.mapstruct:mapstruct:${mapstructVersion}" @@ -103,33 +98,6 @@ dependencies { ... ---- ==== -.Gradle (3.3 and older) -==== -[source, groovy, linenums] -[subs="verbatim,attributes"] ----- -... -plugins { - ... - id 'net.ltgt.apt' version '0.20' -} - -// You can integrate with your IDEs. -// See more details: https://github.com/tbroyer/gradle-apt-plugin#usage-with-ides -apply plugin: 'net.ltgt.apt-idea' -apply plugin: 'net.ltgt.apt-eclipse' - -dependencies { - ... - compile "org.mapstruct:mapstruct:${mapstructVersion}" - annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}" - - // If you are using mapstruct in test code - testAnnotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}" -} -... ----- -==== You can find a complete example in the https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-on-gradle[mapstruct-examples] project on GitHub. diff --git a/readme.md b/readme.md index c39a408ac2..45eeda27e6 100644 --- a/readme.md +++ b/readme.md @@ -109,14 +109,9 @@ For Gradle, you need something along the following lines: ```groovy plugins { ... - id 'net.ltgt.apt' version '0.15' + id "com.diffplug.eclipse.apt" version "3.26.0" // Only for Eclipse } -// You can integrate with your IDEs. -// See more details: https://github.com/tbroyer/gradle-apt-plugin#usage-with-ides -apply plugin: 'net.ltgt.apt-idea' -apply plugin: 'net.ltgt.apt-eclipse' - dependencies { ... compile 'org.mapstruct:mapstruct:1.4.1.Final' From 1ca7c7b5c8a863f6bc7d8702d5e744dbe3e24767 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sun, 31 Jan 2021 13:49:14 +0100 Subject: [PATCH 14/15] [maven-release-plugin] prepare release 1.4.2.Final --- build-config/pom.xml | 2 +- core-jdk8/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- documentation/pom.xml | 2 +- integrationtest/pom.xml | 2 +- parent/pom.xml | 4 ++-- pom.xml | 4 ++-- processor/pom.xml | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build-config/pom.xml b/build-config/pom.xml index aaae7b5404..b0601aadeb 100644 --- a/build-config/pom.xml +++ b/build-config/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.5.0-SNAPSHOT + 1.4.2.Final ../parent/pom.xml diff --git a/core-jdk8/pom.xml b/core-jdk8/pom.xml index 293043e6f9..dee6f3a835 100644 --- a/core-jdk8/pom.xml +++ b/core-jdk8/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.5.0-SNAPSHOT + 1.4.2.Final ../parent/pom.xml diff --git a/core/pom.xml b/core/pom.xml index b02b809ed7..a58fa8a914 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.5.0-SNAPSHOT + 1.4.2.Final ../parent/pom.xml diff --git a/distribution/pom.xml b/distribution/pom.xml index 30beb1d319..14f96c3874 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.5.0-SNAPSHOT + 1.4.2.Final ../parent/pom.xml diff --git a/documentation/pom.xml b/documentation/pom.xml index 0426805375..23fa3cb107 100644 --- a/documentation/pom.xml +++ b/documentation/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.5.0-SNAPSHOT + 1.4.2.Final ../parent/pom.xml diff --git a/integrationtest/pom.xml b/integrationtest/pom.xml index f19ecfe343..aaf6e7a57d 100644 --- a/integrationtest/pom.xml +++ b/integrationtest/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.5.0-SNAPSHOT + 1.4.2.Final ../parent/pom.xml diff --git a/parent/pom.xml b/parent/pom.xml index 9e5c04f27a..ab3c48a70f 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -11,7 +11,7 @@ org.mapstruct mapstruct-parent - 1.5.0-SNAPSHOT + 1.4.2.Final pom MapStruct Parent @@ -63,7 +63,7 @@ scm:git:git://github.com/mapstruct/mapstruct.git scm:git:git@github.com:mapstruct/mapstruct.git https://github.com/mapstruct/mapstruct/ - HEAD + 1.4.2.Final diff --git a/pom.xml b/pom.xml index 28c35aea74..71e4c7925a 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ org.mapstruct mapstruct-parent - 1.5.0-SNAPSHOT + 1.4.2.Final parent/pom.xml @@ -54,7 +54,7 @@ scm:git:git://github.com/mapstruct/mapstruct.git scm:git:git@github.com:mapstruct/mapstruct.git https://github.com/mapstruct/mapstruct/ - HEAD + 1.4.2.Final diff --git a/processor/pom.xml b/processor/pom.xml index 2ff5d2d186..b013e37461 100644 --- a/processor/pom.xml +++ b/processor/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.5.0-SNAPSHOT + 1.4.2.Final ../parent/pom.xml From 710f8e67fc11c1e3c4490a4809489cfdc651f3f9 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sun, 31 Jan 2021 13:49:15 +0100 Subject: [PATCH 15/15] [maven-release-plugin] prepare for next development iteration --- build-config/pom.xml | 2 +- core-jdk8/pom.xml | 2 +- core/pom.xml | 2 +- distribution/pom.xml | 2 +- documentation/pom.xml | 2 +- integrationtest/pom.xml | 2 +- parent/pom.xml | 4 ++-- pom.xml | 4 ++-- processor/pom.xml | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build-config/pom.xml b/build-config/pom.xml index b0601aadeb..e5a6284580 100644 --- a/build-config/pom.xml +++ b/build-config/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.4.2.Final + 1.4.3-SNAPSHOT ../parent/pom.xml diff --git a/core-jdk8/pom.xml b/core-jdk8/pom.xml index dee6f3a835..6375c8d99c 100644 --- a/core-jdk8/pom.xml +++ b/core-jdk8/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.4.2.Final + 1.4.3-SNAPSHOT ../parent/pom.xml diff --git a/core/pom.xml b/core/pom.xml index a58fa8a914..eccbf6ba25 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.4.2.Final + 1.4.3-SNAPSHOT ../parent/pom.xml diff --git a/distribution/pom.xml b/distribution/pom.xml index 14f96c3874..51788794d9 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.4.2.Final + 1.4.3-SNAPSHOT ../parent/pom.xml diff --git a/documentation/pom.xml b/documentation/pom.xml index 23fa3cb107..3111008ed5 100644 --- a/documentation/pom.xml +++ b/documentation/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.4.2.Final + 1.4.3-SNAPSHOT ../parent/pom.xml diff --git a/integrationtest/pom.xml b/integrationtest/pom.xml index aaf6e7a57d..5495b5b74e 100644 --- a/integrationtest/pom.xml +++ b/integrationtest/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.4.2.Final + 1.4.3-SNAPSHOT ../parent/pom.xml diff --git a/parent/pom.xml b/parent/pom.xml index ab3c48a70f..943471039e 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -11,7 +11,7 @@ org.mapstruct mapstruct-parent - 1.4.2.Final + 1.4.3-SNAPSHOT pom MapStruct Parent @@ -63,7 +63,7 @@ scm:git:git://github.com/mapstruct/mapstruct.git scm:git:git@github.com:mapstruct/mapstruct.git https://github.com/mapstruct/mapstruct/ - 1.4.2.Final + HEAD diff --git a/pom.xml b/pom.xml index 71e4c7925a..1e5c125d53 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ org.mapstruct mapstruct-parent - 1.4.2.Final + 1.4.3-SNAPSHOT parent/pom.xml @@ -54,7 +54,7 @@ scm:git:git://github.com/mapstruct/mapstruct.git scm:git:git@github.com:mapstruct/mapstruct.git https://github.com/mapstruct/mapstruct/ - 1.4.2.Final + HEAD diff --git a/processor/pom.xml b/processor/pom.xml index b013e37461..8cdc4cf876 100644 --- a/processor/pom.xml +++ b/processor/pom.xml @@ -12,7 +12,7 @@ org.mapstruct mapstruct-parent - 1.4.2.Final + 1.4.3-SNAPSHOT ../parent/pom.xml