From cc1562c5adacd09afcfd547b3bc340be95c953bd Mon Sep 17 00:00:00 2001 From: Lukas Lazar Date: Wed, 14 Apr 2021 14:39:22 +0200 Subject: [PATCH] #2132 Add unmappedTargetPolicy to @BeanMapping --- .../main/java/org/mapstruct/BeanMapping.java | 11 ++++++ .../main/asciidoc/chapter-2-set-up.asciidoc | 1 + .../ap/internal/model/BeanMappingMethod.java | 3 ++ .../model/source/BeanMappingOptions.java | 12 +++++++ .../BeanMappingSourceTargetMapper.java | 20 +++++++++++ ...usBeanMappingStrictSourceTargetMapper.java | 23 +++++++++++++ .../unmappedtarget/UnmappedProductTest.java | 34 +++++++++++++++++++ 7 files changed, 104 insertions(+) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/BeanMappingSourceTargetMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/ErroneousBeanMappingStrictSourceTargetMapper.java diff --git a/core/src/main/java/org/mapstruct/BeanMapping.java b/core/src/main/java/org/mapstruct/BeanMapping.java index 329d7bd50..f8c749fbd 100644 --- a/core/src/main/java/org/mapstruct/BeanMapping.java +++ b/core/src/main/java/org/mapstruct/BeanMapping.java @@ -140,6 +140,17 @@ public @interface BeanMapping { */ String[] ignoreUnmappedSourceProperties() default {}; + /** + * 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 + * {@link Mapper#unmappedTargetPolicy()} will be applied, using {@link ReportingPolicy#WARN} by default. + * + * @return The reporting policy for unmapped target properties. + * + * @since 1.5 + */ + ReportingPolicy unmappedTargetPolicy() default ReportingPolicy.WARN; + /** * The information that should be used for the builder mappings. This can be used to define custom build methods * for the builder strategy that one uses. diff --git a/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc b/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc index fd27b25e4..d26be7215 100644 --- a/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc +++ b/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc @@ -245,6 +245,7 @@ Supported values are: * `IGNORE`: unmapped target properties are ignored If a policy is given for a specific mapper via `@Mapper#unmappedTargetPolicy()`, the value from the annotation takes precedence. +If a policy is given for a specific bean mapping via `@BeanMapping#unmappedTargetPolicy()`, it takes precedence over both `@Mapper#unmappedTargetPolicy()` and the option. |`WARN` |=== 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 2e82366f8..324df63cc 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 @@ -1390,6 +1390,9 @@ public class BeanMappingMethod extends NormalTypeMappingMethod { if ( mappingReferences.isForForgedMethods() ) { return ReportingPolicyGem.IGNORE; } + if ( method.getOptions().getBeanMapping() != null ) { + return method.getOptions().getBeanMapping().unmappedTargetPolicy(); + } return method.getOptions().getMapper().unmappedTargetPolicy(); } 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 d600ed0fc..78800e605 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 @@ -11,6 +11,8 @@ import java.util.Objects; import java.util.Optional; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.ExecutableElement; + +import org.mapstruct.ap.internal.gem.ReportingPolicyGem; import org.mapstruct.ap.internal.util.ElementUtils; import org.mapstruct.ap.internal.util.TypeUtils; @@ -88,6 +90,7 @@ public class BeanMappingOptions extends DelegatingOptions { && !gem.nullValueCheckStrategy().hasValue() && !gem.nullValuePropertyMappingStrategy().hasValue() && !gem.nullValueMappingStrategy().hasValue() + && !gem.unmappedTargetPolicy().hasValue() && !gem.ignoreByDefault().hasValue() && !gem.builder().hasValue() ) { @@ -134,6 +137,15 @@ public class BeanMappingOptions extends DelegatingOptions { .orElse( next().getNullValueMappingStrategy() ); } + @Override + public ReportingPolicyGem unmappedTargetPolicy() { + return Optional.ofNullable( beanMapping ).map( BeanMappingGem::unmappedTargetPolicy ) + .filter( GemValue::hasValue ) + .map( GemValue::getValue ) + .map( ReportingPolicyGem::valueOf ) + .orElse( next().unmappedTargetPolicy() ); + } + @Override public BuilderGem getBuilder() { return Optional.ofNullable( beanMapping ).map( BeanMappingGem::builder ) diff --git a/processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/BeanMappingSourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/BeanMappingSourceTargetMapper.java new file mode 100644 index 000000000..4f15e5d6e --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/BeanMappingSourceTargetMapper.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.unmappedtarget; + +import org.mapstruct.BeanMapping; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR) +public interface BeanMappingSourceTargetMapper { + + BeanMappingSourceTargetMapper INSTANCE = Mappers.getMapper( BeanMappingSourceTargetMapper.class ); + + @BeanMapping(unmappedTargetPolicy = ReportingPolicy.WARN) + Target sourceToTarget(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/ErroneousBeanMappingStrictSourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/ErroneousBeanMappingStrictSourceTargetMapper.java new file mode 100644 index 000000000..77a946e63 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/ErroneousBeanMappingStrictSourceTargetMapper.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.unmappedtarget; + +import org.mapstruct.BeanMapping; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface ErroneousBeanMappingStrictSourceTargetMapper { + + ErroneousBeanMappingStrictSourceTargetMapper INSTANCE = + Mappers.getMapper( ErroneousBeanMappingStrictSourceTargetMapper.class ); + + @BeanMapping(unmappedTargetPolicy = ReportingPolicy.ERROR) + Target sourceToTarget(Source source); + + Source targetToSource(Target target); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/UnmappedProductTest.java b/processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/UnmappedProductTest.java index a36ec3143..bd3636541 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/UnmappedProductTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/unmappedtarget/UnmappedProductTest.java @@ -87,4 +87,38 @@ public class UnmappedProductTest { ) public void shouldRaiseErrorDueToUnsetTargetPropertyWithPolicySetViaProcessorOption() { } + + @ProcessorTest + @IssueKey("2132") + @WithClasses({ Source.class, Target.class, ErroneousBeanMappingStrictSourceTargetMapper.class }) + @ExpectedCompilationOutcome( + value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = ErroneousBeanMappingStrictSourceTargetMapper.class, + kind = Kind.ERROR, + line = 20, + message = "Unmapped target property: \"bar\"."), + @Diagnostic(type = ErroneousBeanMappingStrictSourceTargetMapper.class, + kind = Kind.WARNING, + line = 22, + message = "Unmapped target property: \"qux\".") + } + ) + public void shouldRaiseErrorDueToUnsetTargetPropertyWithPolicySetViaBeanMapping() { + } + + @ProcessorTest + @IssueKey("2132") + @WithClasses({ Source.class, Target.class, BeanMappingSourceTargetMapper.class }) + @ExpectedCompilationOutcome( + value = CompilationResult.SUCCEEDED, + diagnostics = { + @Diagnostic(type = BeanMappingSourceTargetMapper.class, + kind = Kind.WARNING, + line = 19, + message = "Unmapped target property: \"bar\".") + } + ) + public void shouldLeaveUnmappedTargetPropertyUnsetWithWarnPolicySetViaBeanMapping() { + } }