From 427f5023efec6f6a91fd8946bb2b6e86a1ed2a19 Mon Sep 17 00:00:00 2001 From: Sjaak Derksen Date: Sun, 6 Sep 2020 16:12:01 +0200 Subject: [PATCH] #2195 @Beanmapping#resultType should be used to construct return type also if it's a builder (#2196) --- .../ap/internal/model/BeanMappingMethod.java | 30 +++++++------- .../processor/MapperCreationProcessor.java | 13 +++++- .../ap/test/bugs/_2195/Issue2195Mapper.java | 23 +++++++++++ .../ap/test/bugs/_2195/Issue2195Test.java | 35 ++++++++++++++++ .../ap/test/bugs/_2195/dto/Source.java | 18 +++++++++ .../ap/test/bugs/_2195/dto/Target.java | 31 ++++++++++++++ .../ap/test/bugs/_2195/dto/TargetBase.java | 40 +++++++++++++++++++ 7 files changed, 173 insertions(+), 17 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/Issue2195Mapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/Issue2195Test.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/Source.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/Target.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/TargetBase.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 a0ea064f1..c2434da51 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 @@ -87,6 +87,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod { private MappingBuilderContext ctx; private Method method; + private Type userDefinedReturnType; /* returnType to construct can have a builder */ private BuilderType returnTypeBuilder; @@ -108,6 +109,11 @@ public class BeanMappingMethod extends NormalTypeMappingMethod { return this; } + public Builder userDefinedReturnType(Type userDefinedReturnType) { + this.userDefinedReturnType = userDefinedReturnType; + return this; + } + public Builder returnTypeBuilder( BuilderType returnTypeBuilder ) { this.returnTypeBuilder = returnTypeBuilder; return this; @@ -148,20 +154,22 @@ public class BeanMappingMethod extends NormalTypeMappingMethod { // determine which return type to construct boolean cannotConstructReturnType = false; if ( !method.getReturnType().isVoid() ) { - Type returnTypeImpl = getReturnTypeToConstructFromSelectionParameters( selectionParameters ); - if ( returnTypeImpl != null ) { + Type returnTypeImpl = null; + if ( isBuilderRequired() ) { + // the userDefinedReturn type can also require a builder. That buildertype is already set + returnTypeImpl = returnTypeBuilder.getBuilder(); initializeFactoryMethod( returnTypeImpl, selectionParameters ); - if ( factoryMethod != null || canResultTypeFromBeanMappingBeConstructed( returnTypeImpl ) ) { + if ( factoryMethod != null || canReturnTypeBeConstructed( returnTypeImpl ) ) { returnTypeToConstruct = returnTypeImpl; } else { cannotConstructReturnType = true; } } - else if ( isBuilderRequired() ) { - returnTypeImpl = returnTypeBuilder.getBuilder(); + else if ( userDefinedReturnType != null ) { + returnTypeImpl = userDefinedReturnType; initializeFactoryMethod( returnTypeImpl, selectionParameters ); - if ( factoryMethod != null || canReturnTypeBeConstructed( returnTypeImpl ) ) { + if ( factoryMethod != null || canResultTypeFromBeanMappingBeConstructed( returnTypeImpl ) ) { returnTypeToConstruct = returnTypeImpl; } else { @@ -482,16 +490,6 @@ public class BeanMappingMethod extends NormalTypeMappingMethod { } } - private Type getReturnTypeToConstructFromSelectionParameters(SelectionParameters selectionParams) { - // resultType only applies to method that actually has @BeanMapping annotation, never to forged methods - if ( !( method instanceof ForgedMethod ) - && selectionParams != null - && selectionParams.getResultType() != null ) { - return ctx.getTypeFactory().getType( selectionParams.getResultType() ); - } - return null; - } - private boolean canResultTypeFromBeanMappingBeConstructed(Type resultType) { boolean error = true; diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java index 58c6f2513..25632350b 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/MapperCreationProcessor.java @@ -367,11 +367,14 @@ public class MapperCreationProcessor implements ModelElementProcessor M createWithElementMappingMethod(SourceMethod method, MappingMethodOptions mappingMethodOptions, ContainerMappingMethodBuilder builder) { diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/Issue2195Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/Issue2195Mapper.java new file mode 100644 index 000000000..cde09dd2e --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/Issue2195Mapper.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.bugs._2195; + +import org.mapstruct.BeanMapping; +import org.mapstruct.Mapper; +import org.mapstruct.ap.test.bugs._2195.dto.Source; +import org.mapstruct.ap.test.bugs._2195.dto.Target; +import org.mapstruct.ap.test.bugs._2195.dto.TargetBase; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface Issue2195Mapper { + + Issue2195Mapper INSTANCE = Mappers.getMapper( Issue2195Mapper.class ); + + @BeanMapping( resultType = Target.class ) + TargetBase map(Source source); + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/Issue2195Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/Issue2195Test.java new file mode 100644 index 000000000..8d8a754d7 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/Issue2195Test.java @@ -0,0 +1,35 @@ +/* + * 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._2195; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.test.bugs._2195.dto.Source; +import org.mapstruct.ap.test.bugs._2195.dto.Target; +import org.mapstruct.ap.test.bugs._2195.dto.TargetBase; +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("2195") +@WithClasses( { Source.class, Target.class, TargetBase.class } ) +@RunWith(AnnotationProcessorTestRunner.class) +public class Issue2195Test { + + @Test + @WithClasses( Issue2195Mapper.class ) + public void test() { + + Source source = new Source(); + source.setName( "JohnDoe" ); + + TargetBase target = Issue2195Mapper.INSTANCE.map( source ); + + assertThat( target ).isInstanceOf( Target.class ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/Source.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/Source.java new file mode 100644 index 000000000..78a4bba1a --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/Source.java @@ -0,0 +1,18 @@ +/* + * 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._2195.dto; + +public class Source { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/Target.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/Target.java new file mode 100644 index 000000000..8a74d4410 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/Target.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.bugs._2195.dto; + +public class Target extends TargetBase { + + protected Target(Builder builder) { + super( builder ); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends TargetBase.Builder { + + protected Builder() { + } + + public Target build() { + return new Target( this ); + } + + public Builder name(String name) { + return this; + } + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/TargetBase.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/TargetBase.java new file mode 100644 index 000000000..ffb2eff2b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2195/dto/TargetBase.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._2195.dto; + +public class TargetBase { + + private final String name; + + protected TargetBase(Builder builder) { + this.name = builder.name; + } + + public static Builder builder() { + return new Builder(); + } + + public String getName() { + return name; + } + + public static class Builder { + + protected Builder() { + } + + private String name; + + public TargetBase build() { + return new TargetBase( this ); + } + + public Builder name(String name) { + this.name = name; + return this; + } + } +}