From f0a13bb306e4e86f13d328512bde3be07ed0b72b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20Kemal=20=C3=96zcan?= Date: Mon, 6 Sep 2021 00:38:38 +0300 Subject: [PATCH] #2555 Add unmappedSourcePolicy annotation processor argument --- .../main/asciidoc/chapter-2-set-up.asciidoc | 13 ++++++ .../org/mapstruct/ap/MappingProcessor.java | 4 ++ .../internal/model/source/DefaultOptions.java | 3 ++ .../mapstruct/ap/internal/option/Options.java | 7 +++ ...SourceTargetMapperWithoutMapperConfig.java | 25 +++++++++++ .../unmappedsource/UnmappedSourceTest.java | 43 +++++++++++++++++++ 6 files changed, 95 insertions(+) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/unmappedsource/SourceTargetMapperWithoutMapperConfig.java diff --git a/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc b/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc index d26be7215..730433639 100644 --- a/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc +++ b/documentation/src/main/asciidoc/chapter-2-set-up.asciidoc @@ -247,6 +247,19 @@ Supported values are: 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` + +|`mapstruct.unmappedSourcePolicy` +|The default reporting policy to be applied in case an attribute of the source object of a mapping method is not populated with a target value. + +Supported values are: + +* `ERROR`: any unmapped source property will cause the mapping code generation to fail +* `WARN`: any unmapped source property will cause a warning at build time +* `IGNORE`: unmapped source properties are ignored + +If a policy is given for a specific mapper via `@Mapper#unmappedSourcePolicy()`, the value from the annotation takes precedence. +If a policy is given for a specific bean mapping via `@BeanMapping#ignoreUnmappedSourceProperties()`, it takes precedence over both `@Mapper#unmappedSourcePolicy()` and the option. +|`WARN` |=== === Using MapStruct with the Java Module System diff --git a/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java b/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java index 8369a8b27..952257753 100644 --- a/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/MappingProcessor.java @@ -84,6 +84,7 @@ import static javax.lang.model.element.ElementKind.CLASS; MappingProcessor.SUPPRESS_GENERATOR_TIMESTAMP, MappingProcessor.SUPPRESS_GENERATOR_VERSION_INFO_COMMENT, MappingProcessor.UNMAPPED_TARGET_POLICY, + MappingProcessor.UNMAPPED_SOURCE_POLICY, MappingProcessor.DEFAULT_COMPONENT_MODEL, MappingProcessor.DEFAULT_INJECTION_STRATEGY, MappingProcessor.VERBOSE @@ -99,6 +100,7 @@ public class MappingProcessor extends AbstractProcessor { protected static final String SUPPRESS_GENERATOR_VERSION_INFO_COMMENT = "mapstruct.suppressGeneratorVersionInfoComment"; protected static final String UNMAPPED_TARGET_POLICY = "mapstruct.unmappedTargetPolicy"; + protected static final String UNMAPPED_SOURCE_POLICY = "mapstruct.unmappedSourcePolicy"; protected static final String DEFAULT_COMPONENT_MODEL = "mapstruct.defaultComponentModel"; protected static final String DEFAULT_INJECTION_STRATEGY = "mapstruct.defaultInjectionStrategy"; protected static final String ALWAYS_GENERATE_SERVICE_FILE = "mapstruct.alwaysGenerateServicesFile"; @@ -134,11 +136,13 @@ public class MappingProcessor extends AbstractProcessor { private Options createOptions() { String unmappedTargetPolicy = processingEnv.getOptions().get( UNMAPPED_TARGET_POLICY ); + String unmappedSourcePolicy = processingEnv.getOptions().get( UNMAPPED_SOURCE_POLICY ); return new Options( Boolean.valueOf( processingEnv.getOptions().get( SUPPRESS_GENERATOR_TIMESTAMP ) ), Boolean.valueOf( processingEnv.getOptions().get( SUPPRESS_GENERATOR_VERSION_INFO_COMMENT ) ), unmappedTargetPolicy != null ? ReportingPolicyGem.valueOf( unmappedTargetPolicy.toUpperCase() ) : null, + unmappedSourcePolicy != null ? ReportingPolicyGem.valueOf( unmappedSourcePolicy.toUpperCase() ) : null, processingEnv.getOptions().get( DEFAULT_COMPONENT_MODEL ), processingEnv.getOptions().get( DEFAULT_INJECTION_STRATEGY ), Boolean.valueOf( processingEnv.getOptions().get( ALWAYS_GENERATE_SERVICE_FILE ) ), 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 58f03ad55..d52d09493 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 @@ -63,6 +63,9 @@ public class DefaultOptions extends DelegatingOptions { @Override public ReportingPolicyGem unmappedSourcePolicy() { + if ( options.getUnmappedSourcePolicy() != null ) { + return options.getUnmappedSourcePolicy(); + } return ReportingPolicyGem.valueOf( mapper.unmappedSourcePolicy().getDefaultValue() ); } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/option/Options.java b/processor/src/main/java/org/mapstruct/ap/internal/option/Options.java index 54b69c28b..46a90d4b4 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/option/Options.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/option/Options.java @@ -17,6 +17,7 @@ public class Options { private final boolean suppressGeneratorTimestamp; private final boolean suppressGeneratorVersionComment; private final ReportingPolicyGem unmappedTargetPolicy; + private final ReportingPolicyGem unmappedSourcePolicy; private final boolean alwaysGenerateSpi; private final String defaultComponentModel; private final String defaultInjectionStrategy; @@ -24,11 +25,13 @@ public class Options { public Options(boolean suppressGeneratorTimestamp, boolean suppressGeneratorVersionComment, ReportingPolicyGem unmappedTargetPolicy, + ReportingPolicyGem unmappedSourcePolicy, String defaultComponentModel, String defaultInjectionStrategy, boolean alwaysGenerateSpi, boolean verbose) { this.suppressGeneratorTimestamp = suppressGeneratorTimestamp; this.suppressGeneratorVersionComment = suppressGeneratorVersionComment; this.unmappedTargetPolicy = unmappedTargetPolicy; + this.unmappedSourcePolicy = unmappedSourcePolicy; this.defaultComponentModel = defaultComponentModel; this.defaultInjectionStrategy = defaultInjectionStrategy; this.alwaysGenerateSpi = alwaysGenerateSpi; @@ -47,6 +50,10 @@ public class Options { return unmappedTargetPolicy; } + public ReportingPolicyGem getUnmappedSourcePolicy() { + return unmappedSourcePolicy; + } + public String getDefaultComponentModel() { return defaultComponentModel; } diff --git a/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/SourceTargetMapperWithoutMapperConfig.java b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/SourceTargetMapperWithoutMapperConfig.java new file mode 100644 index 000000000..4ab2d3688 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/unmappedsource/SourceTargetMapperWithoutMapperConfig.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; + +import org.mapstruct.Mapper; +import org.mapstruct.ap.test.unmappedtarget.Source; +import org.mapstruct.ap.test.unmappedtarget.Target; +import org.mapstruct.factory.Mappers; + +/** + * + * @author Yusuf Kemal Ozcan + */ +@Mapper +public interface SourceTargetMapperWithoutMapperConfig { + + SourceTargetMapperWithoutMapperConfig INSTANCE = Mappers.getMapper( SourceTargetMapperWithoutMapperConfig.class ); + + Target sourceToTarget(Source source); + + Source targetToSource(Target target); +} 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 59d44a6ba..9b244592a 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 @@ -14,6 +14,7 @@ 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.compilation.annotation.ProcessorOption; import static org.assertj.core.api.Assertions.assertThat; @@ -67,4 +68,46 @@ public class UnmappedSourceTest { ) public void shouldRaiseErrorDueToUnsetSourceProperty() { } + + @ProcessorTest + @WithClasses({ Source.class, Target.class, + org.mapstruct.ap.test.unmappedsource.SourceTargetMapperWithoutMapperConfig.class }) + @ProcessorOption(name = "mapstruct.unmappedTargetPolicy", value = "IGNORE") + @ProcessorOption(name = "mapstruct.unmappedSourcePolicy", value = "ERROR") + @ExpectedCompilationOutcome( + value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = org.mapstruct.ap.test.unmappedsource.SourceTargetMapperWithoutMapperConfig.class, + kind = Kind.ERROR, + line = 22, + message = "Unmapped source property: \"qux\"."), + @Diagnostic(type = org.mapstruct.ap.test.unmappedsource.SourceTargetMapperWithoutMapperConfig.class, + kind = Kind.ERROR, + line = 24, + message = "Unmapped source property: \"bar\".") + } + ) + public void shouldRaiseErrorDueToUnsetSourcePropertyWithPolicySetViaProcessorOption() { + } + + @ProcessorTest + @WithClasses({ Source.class, Target.class, + org.mapstruct.ap.test.unmappedsource.SourceTargetMapperWithoutMapperConfig.class }) + @ProcessorOption(name = "mapstruct.unmappedTargetPolicy", value = "IGNORE") + @ProcessorOption(name = "mapstruct.unmappedSourcePolicy", value = "WARN") + @ExpectedCompilationOutcome( + value = CompilationResult.SUCCEEDED, + diagnostics = { + @Diagnostic(type = org.mapstruct.ap.test.unmappedsource.SourceTargetMapperWithoutMapperConfig.class, + kind = Kind.WARNING, + line = 22, + message = "Unmapped source property: \"qux\"."), + @Diagnostic(type = org.mapstruct.ap.test.unmappedsource.SourceTargetMapperWithoutMapperConfig.class, + kind = Kind.WARNING, + line = 24, + message = "Unmapped source property: \"bar\".") + } + ) + public void shouldLeaveUnmappedSourcePropertyUnsetWithWarnPolicySetViaProcessorOption() { + } }