From 279ab2248291cba77391cae38a4b2ea40fbeae7c Mon Sep 17 00:00:00 2001 From: Venkatesh Prasad Kannan Date: Tue, 1 Aug 2023 08:48:20 +0100 Subject: [PATCH] #3309 Add `BeanMapping#unmappedSourcePolicy` --- .../main/java/org/mapstruct/BeanMapping.java | 11 +++ .../ap/internal/model/BeanMappingMethod.java | 2 +- .../model/source/BeanMappingOptions.java | 10 +++ .../unmappedsource/UnmappedSourceTest.java | 1 + ...eanMappingSourcePolicyErroneousMapper.java | 18 +++++ .../BeanMappingSourcePolicyMapper.java | 25 +++++++ .../unmappedsource/beanmapping/Source.java | 30 +++++++++ .../unmappedsource/beanmapping/Target.java | 20 ++++++ .../beanmapping/UnmappedSourceTest.java | 67 +++++++++++++++++++ 9 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/BeanMappingSourcePolicyErroneousMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/BeanMappingSourcePolicyMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/Source.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/Target.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/UnmappedSourceTest.java diff --git a/core/src/main/java/org/mapstruct/BeanMapping.java b/core/src/main/java/org/mapstruct/BeanMapping.java index be3df0d29..a03546b07 100644 --- a/core/src/main/java/org/mapstruct/BeanMapping.java +++ b/core/src/main/java/org/mapstruct/BeanMapping.java @@ -152,6 +152,17 @@ public @interface BeanMapping { */ String[] ignoreUnmappedSourceProperties() default {}; + /** + * How unmapped properties of the source type of a mapping should be reported. + * If no policy is configured, the policy given via {@link MapperConfig#unmappedSourcePolicy()} or + * {@link Mapper#unmappedSourcePolicy()} will be applied, using {@link ReportingPolicy#IGNORE} by default. + * + * @return The reporting policy for unmapped source properties. + * + * @since 1.6 + */ + ReportingPolicy unmappedSourcePolicy() default ReportingPolicy.IGNORE; + /** * How unmapped properties of the target type of a mapping should be reported. * If no policy is configured, the policy given via {@link MapperConfig#unmappedTargetPolicy()} or 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 903dfa5cc..11245b337 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 @@ -1740,7 +1740,7 @@ public class BeanMappingMethod extends NormalTypeMappingMethod { if ( method.getOptions().getBeanMapping().isignoreByDefault() ) { return ReportingPolicyGem.IGNORE; } - return method.getOptions().getMapper().unmappedSourcePolicy(); + return method.getOptions().getBeanMapping().unmappedSourcePolicy(); } private void reportErrorForUnmappedSourcePropertiesIfRequired() { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/BeanMappingOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/BeanMappingOptions.java index e8f19f91f..6f36238a3 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/BeanMappingOptions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/BeanMappingOptions.java @@ -113,6 +113,7 @@ public class BeanMappingOptions extends DelegatingOptions { && !gem.nullValueMappingStrategy().hasValue() && !gem.subclassExhaustiveStrategy().hasValue() && !gem.unmappedTargetPolicy().hasValue() + && !gem.unmappedSourcePolicy().hasValue() && !gem.ignoreByDefault().hasValue() && !gem.builder().hasValue() ) { @@ -179,6 +180,15 @@ public class BeanMappingOptions extends DelegatingOptions { .orElse( next().unmappedTargetPolicy() ); } + @Override + public ReportingPolicyGem unmappedSourcePolicy() { + return Optional.ofNullable( beanMapping ).map( BeanMappingGem::unmappedSourcePolicy ) + .filter( GemValue::hasValue ) + .map( GemValue::getValue ) + .map( ReportingPolicyGem::valueOf ) + .orElse( next().unmappedSourcePolicy() ); + } + @Override public BuilderGem getBuilder() { return Optional.ofNullable( beanMapping ).map( BeanMappingGem::builder ) diff --git a/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/UnmappedSourceTest.java b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/UnmappedSourceTest.java index 9b244592a..75231f3f5 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/UnmappedSourceTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/UnmappedSourceTest.java @@ -110,4 +110,5 @@ public class UnmappedSourceTest { ) public void shouldLeaveUnmappedSourcePropertyUnsetWithWarnPolicySetViaProcessorOption() { } + } diff --git a/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/BeanMappingSourcePolicyErroneousMapper.java b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/BeanMappingSourcePolicyErroneousMapper.java new file mode 100644 index 000000000..eab3f8f42 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/BeanMappingSourcePolicyErroneousMapper.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.unmappedsource.beanmapping; + +import org.mapstruct.BeanMapping; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +@Mapper(unmappedSourcePolicy = ReportingPolicy.WARN) +public interface BeanMappingSourcePolicyErroneousMapper { + + @BeanMapping(unmappedSourcePolicy = ReportingPolicy.ERROR) + Target map(Source source); + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/BeanMappingSourcePolicyMapper.java b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/BeanMappingSourcePolicyMapper.java new file mode 100644 index 000000000..11e1f0713 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/BeanMappingSourcePolicyMapper.java @@ -0,0 +1,25 @@ +/* + * 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.unmappedsource.beanmapping; + +import org.mapstruct.BeanMapping; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper(unmappedSourcePolicy = ReportingPolicy.ERROR) +public interface BeanMappingSourcePolicyMapper { + + BeanMappingSourcePolicyMapper MAPPER = + Mappers.getMapper( BeanMappingSourcePolicyMapper.class ); + + @BeanMapping(unmappedSourcePolicy = ReportingPolicy.WARN) + Target map(Source source); + + @BeanMapping(unmappedSourcePolicy = ReportingPolicy.IGNORE) + Target map2(Source source); + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/Source.java b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/Source.java new file mode 100644 index 000000000..fc92d1a5c --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/Source.java @@ -0,0 +1,30 @@ +/* + * 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.unmappedsource.beanmapping; + +public class Source { + + private int foo; + + private int bar; + + public int getFoo() { + return foo; + } + + public void setFoo(int foo) { + this.foo = foo; + } + + public int getBar() { + return bar; + } + + public void setBar(int bar) { + this.bar = bar; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/Target.java b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/Target.java new file mode 100644 index 000000000..5696455b4 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/Target.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.unmappedsource.beanmapping; + +public class Target { + + private int foo; + + public int getFoo() { + return foo; + } + + public void setFoo(int foo) { + this.foo = foo; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/UnmappedSourceTest.java b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/UnmappedSourceTest.java new file mode 100644 index 000000000..6eff38877 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/beanmapping/UnmappedSourceTest.java @@ -0,0 +1,67 @@ +/* + * 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.unmappedsource.beanmapping; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.tools.Diagnostic.Kind; + +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.ProcessorTest; +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; + +@IssueKey("3309") +class UnmappedSourceTest { + + @ProcessorTest + @WithClasses({ Source.class, Target.class, BeanMappingSourcePolicyMapper.class }) + @ExpectedCompilationOutcome( + value = CompilationResult.SUCCEEDED, + diagnostics = { + @Diagnostic(type = BeanMappingSourcePolicyMapper.class, + kind = Kind.WARNING, + line = 20, + message = "Unmapped source property: \"bar\".") + } + ) + public void shouldCompileWithUnmappedSourcePolicySetToWarnWithBeanMapping() { + Source source = new Source(); + Source source2 = new Source(); + + source.setFoo( 10 ); + source.setBar( 20 ); + + source2.setFoo( 1 ); + source2.setBar( 2 ); + + Target target = BeanMappingSourcePolicyMapper.MAPPER.map( source ); + Target target2 = BeanMappingSourcePolicyMapper.MAPPER.map2( source2 ); + + assertThat( target ).isNotNull(); + assertThat( target.getFoo() ).isEqualTo( 10 ); + + assertThat( target2 ).isNotNull(); + assertThat( target2.getFoo() ).isEqualTo( 1 ); + } + + @ProcessorTest + @WithClasses({ Source.class, Target.class, BeanMappingSourcePolicyErroneousMapper.class }) + @ExpectedCompilationOutcome( + value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = BeanMappingSourcePolicyErroneousMapper.class, + kind = Kind.ERROR, + line = 16, + message = "Unmapped source property: \"bar\".") + } + ) + public void shouldErrorWithUnmappedSourcePolicySetToErrorWithBeanMapping() { + } + +}