From 7dcbef349d234e986ba41a4838937274f55e5c14 Mon Sep 17 00:00:00 2001 From: Filip Hrisafov Date: Sat, 29 Aug 2020 13:53:30 +0200 Subject: [PATCH] #2169 Add support for defining a custom unexpected value mapping exception Expose definition via: * `@EnumMapping` * `@Mapper` * `@MapperConfig` * `EnumMappingStrategy` SPI Rename `EnumNamingStrategy` to `EnumMappingStrategy` --- .../main/java/org/mapstruct/EnumMapping.java | 25 ++++- core/src/main/java/org/mapstruct/Mapper.java | 23 ++++ .../main/java/org/mapstruct/MapperConfig.java | 22 ++++ .../chapter-13-using-mapstruct-spi.asciidoc | 8 +- .../internal/model/MappingBuilderContext.java | 12 +-- .../ap/internal/model/ValueMappingMethod.java | 48 +++++++-- .../internal/model/source/DefaultOptions.java | 6 ++ .../model/source/DelegatingOptions.java | 4 + .../model/source/EnumMappingOptions.java | 64 +++++++++-- .../model/source/MapperConfigOptions.java | 8 ++ .../internal/model/source/MapperOptions.java | 8 ++ .../DefaultModelElementProcessorContext.java | 6 +- .../processor/MapperCreationProcessor.java | 2 +- .../processor/ModelElementProcessor.java | 4 +- .../util/AnnotationProcessorContext.java | 16 +-- .../mapstruct/ap/internal/util/Message.java | 4 +- .../mapstruct/ap/internal/util/Strings.java | 4 + ...y.java => DefaultEnumMappingStrategy.java} | 11 +- ...Strategy.java => EnumMappingStrategy.java} | 11 +- .../ap/internal/model/ValueMappingMethod.ftl | 4 +- .../value/CustomIllegalArgumentException.java | 16 +++ .../erroneous/EmptyEnumMappingMapper.java | 25 +++++ .../erroneous/ErroneousEnumMappingTest.java | 63 +++++++++++ .../NoConfigurationEnumMappingMapper.java | 26 +++++ .../ap/test/value/exception/Config.java | 16 +++ ...dValueMappingExceptionDefinedInMapper.java | 35 ++++++ ...xceptionDefinedInMapperAndEnumMapping.java | 38 +++++++ ...MappingExceptionDefinedInMapperConfig.java | 34 ++++++ ...UnexpectedValueMappingExceptionMapper.java | 39 +++++++ ...omUnexpectedValueMappingExceptionTest.java | 48 +++++++++ .../ap/test/value/spi/CustomCheeseMapper.java | 3 + ...gy.java => CustomEnumMappingStrategy.java} | 12 ++- ...ava => CustomEnumMappingStrategyTest.java} | 10 +- ...> CustomErroneousEnumMappingStrategy.java} | 6 +- ...stomErroneousEnumMappingStrategyTest.java} | 14 +-- ...tionDefinedInMapperAndEnumMappingImpl.java | 101 ++++++++++++++++++ ...ingExceptionDefinedInMapperConfigImpl.java | 101 ++++++++++++++++++ ...ueMappingExceptionDefinedInMapperImpl.java | 101 ++++++++++++++++++ ...pectedValueMappingExceptionMapperImpl.java | 101 ++++++++++++++++++ .../value/spi/CustomCheeseMapperImpl.java | 7 +- 40 files changed, 1014 insertions(+), 72 deletions(-) rename processor/src/main/java/org/mapstruct/ap/spi/{DefaultEnumNamingStrategy.java => DefaultEnumMappingStrategy.java} (68%) rename processor/src/main/java/org/mapstruct/ap/spi/{EnumNamingStrategy.java => EnumMappingStrategy.java} (80%) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/value/CustomIllegalArgumentException.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/value/erroneous/EmptyEnumMappingMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/value/erroneous/ErroneousEnumMappingTest.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/value/erroneous/NoConfigurationEnumMappingMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/value/exception/Config.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMapping.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperConfig.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionTest.java rename processor/src/test/java/org/mapstruct/ap/test/value/spi/{CustomEnumNamingStrategy.java => CustomEnumMappingStrategy.java} (77%) rename processor/src/test/java/org/mapstruct/ap/test/value/spi/{CustomEnumNamingStrategyTest.java => CustomEnumMappingStrategyTest.java} (94%) rename processor/src/test/java/org/mapstruct/ap/test/value/spi/{CustomErroneousEnumNamingStrategy.java => CustomErroneousEnumMappingStrategy.java} (87%) rename processor/src/test/java/org/mapstruct/ap/test/value/spi/{CustomErroneousEnumNamingStrategyTest.java => CustomErroneousEnumMappingStrategyTest.java} (90%) create mode 100644 processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMappingImpl.java create mode 100644 processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperConfigImpl.java create mode 100644 processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperImpl.java create mode 100644 processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionMapperImpl.java diff --git a/core/src/main/java/org/mapstruct/EnumMapping.java b/core/src/main/java/org/mapstruct/EnumMapping.java index c184448aa..2f908579e 100644 --- a/core/src/main/java/org/mapstruct/EnumMapping.java +++ b/core/src/main/java/org/mapstruct/EnumMapping.java @@ -111,7 +111,7 @@ public @interface EnumMapping { * * @return the name transformation strategy */ - String nameTransformationStrategy(); + String nameTransformationStrategy() default ""; /** * The configuration that should be passed on the appropriate name transformation strategy. @@ -119,5 +119,26 @@ public @interface EnumMapping { * * @return the configuration to use */ - String configuration(); + String configuration() default ""; + + /** + * Exception that should be thrown by the generated code if no mapping matches. + * If no exception is configured, the exception given via {@link MapperConfig#unexpectedValueMappingException()} or + * {@link Mapper#unexpectedValueMappingException()} will be used, using {@link IllegalArgumentException} by default. + * + *

+ * Note: + *

+ * + * @return the exception that should be used in the generated code + */ + Class unexpectedValueMappingException() default IllegalArgumentException.class; } diff --git a/core/src/main/java/org/mapstruct/Mapper.java b/core/src/main/java/org/mapstruct/Mapper.java index ce8eebf1c..233907621 100644 --- a/core/src/main/java/org/mapstruct/Mapper.java +++ b/core/src/main/java/org/mapstruct/Mapper.java @@ -296,4 +296,27 @@ public @interface Mapper { * @see org.mapstruct.control.MappingControl */ Class mappingControl() default MappingControl.class; + + /** + * Exception that should be thrown by the generated code if no mapping matches for enums. + * If no exception is configured, the exception given via {@link MapperConfig#unexpectedValueMappingException()} + * will be used, using {@link IllegalArgumentException} by default. + * + *

+ * Note: + *

+ * + * @return the exception that should be used in the generated code + * + * @since 1.4 + */ + Class unexpectedValueMappingException() default IllegalArgumentException.class; } diff --git a/core/src/main/java/org/mapstruct/MapperConfig.java b/core/src/main/java/org/mapstruct/MapperConfig.java index 24951fb34..d251ff379 100644 --- a/core/src/main/java/org/mapstruct/MapperConfig.java +++ b/core/src/main/java/org/mapstruct/MapperConfig.java @@ -273,5 +273,27 @@ public @interface MapperConfig { */ Class mappingControl() default MappingControl.class; + /** + * Exception that should be thrown by the generated code if no mapping matches for enums. + * If no exception is configured, {@link IllegalArgumentException} will be used by default. + * + *

+ * Note: + *

+ * + * @return the exception that should be used in the generated code + * + * @since 1.4 + */ + Class unexpectedValueMappingException() default IllegalArgumentException.class; + } diff --git a/documentation/src/main/asciidoc/chapter-13-using-mapstruct-spi.asciidoc b/documentation/src/main/asciidoc/chapter-13-using-mapstruct-spi.asciidoc index 54c33ed93..51fec968b 100644 --- a/documentation/src/main/asciidoc/chapter-13-using-mapstruct-spi.asciidoc +++ b/documentation/src/main/asciidoc/chapter-13-using-mapstruct-spi.asciidoc @@ -202,7 +202,7 @@ include::{processor-ap-main}/spi/NoOpBuilderProvider.java[tag=documentation] [[custom-enum-naming-strategy]] === Custom Enum Naming Strategy -MapStruct offers the possibility to override the `EnumNamingStrategy` via the Service Provider Interface (SPI). +MapStruct offers the possibility to override the `EnumMappingStrategy` via the Service Provider Interface (SPI). This can be used when you have certain enums that follow some conventions within your organization. For example all enums which implement an interface named `CustomEnumMarker` are prefixed with `CUSTOM_` and the default value for them when mapping from `null` is `UNSPECIFIED` @@ -250,15 +250,15 @@ public interface CheeseTypeMapper { ---- ==== -This can be achieved with implementing the SPI `org.mapstruct.ap.spi.EnumNamingStrategy` as in the following example. -Here’s an implemented `org.mapstruct.ap.spi.EnumNamingStrategy`: +This can be achieved with implementing the SPI `org.mapstruct.ap.spi.EnumMappingStrategy` as in the following example. +Here’s an implemented `org.mapstruct.ap.spi.EnumMappingStrategy`: .Custom enum naming strategy ==== [source, java, linenums] [subs="verbatim,attributes"] ---- -public class CustomEnumNamingStrategy extends DefaultEnumNamingStrategy { +public class CustomEnumMappingStrategy extends DefaultEnumMappingStrategy { @Override public String getDefaultNullEnumConstant(TypeElement enumType) { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java b/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java index f5c5887d5..8da5cb508 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/MappingBuilderContext.java @@ -30,7 +30,7 @@ import org.mapstruct.ap.internal.option.Options; import org.mapstruct.ap.internal.util.AccessorNamingUtils; import org.mapstruct.ap.internal.util.FormattingMessager; import org.mapstruct.ap.internal.util.Services; -import org.mapstruct.ap.spi.EnumNamingStrategy; +import org.mapstruct.ap.spi.EnumMappingStrategy; import org.mapstruct.ap.spi.EnumTransformationStrategy; import org.mapstruct.ap.spi.MappingExclusionProvider; @@ -107,7 +107,7 @@ public class MappingBuilderContext { private final Types typeUtils; private final FormattingMessager messager; private final AccessorNamingUtils accessorNaming; - private final EnumNamingStrategy enumNamingStrategy; + private final EnumMappingStrategy enumMappingStrategy; private final Map enumTransformationStrategies; private final Options options; private final TypeElement mapperTypeElement; @@ -124,7 +124,7 @@ public class MappingBuilderContext { Types typeUtils, FormattingMessager messager, AccessorNamingUtils accessorNaming, - EnumNamingStrategy enumNamingStrategy, + EnumMappingStrategy enumMappingStrategy, Map enumTransformationStrategies, Options options, MappingResolver mappingResolver, @@ -136,7 +136,7 @@ public class MappingBuilderContext { this.typeUtils = typeUtils; this.messager = messager; this.accessorNaming = accessorNaming; - this.enumNamingStrategy = enumNamingStrategy; + this.enumMappingStrategy = enumMappingStrategy; this.enumTransformationStrategies = enumTransformationStrategies; this.options = options; this.mappingResolver = mappingResolver; @@ -191,8 +191,8 @@ public class MappingBuilderContext { return accessorNaming; } - public EnumNamingStrategy getEnumNamingStrategy() { - return enumNamingStrategy; + public EnumMappingStrategy getEnumMappingStrategy() { + return enumMappingStrategy; } public Map getEnumTransformationStrategies() { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/ValueMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/internal/model/ValueMappingMethod.java index 72f8153c5..9c7272f2b 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/ValueMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/ValueMappingMethod.java @@ -43,7 +43,9 @@ public class ValueMappingMethod extends MappingMethod { private final List valueMappings; private final String defaultTarget; private final String nullTarget; - private final boolean throwIllegalArgumentException; + + private final Type unexpectedValueMappingException; + private final boolean overridden; public static class Builder { @@ -90,7 +92,7 @@ public class ValueMappingMethod extends MappingMethod { if ( targetType.isEnumType() && valueMappings.nullTarget == null ) { // If null target is not set it means that the user has not explicitly defined a mapping for null - valueMappings.nullValueTarget = ctx.getEnumNamingStrategy() + valueMappings.nullValueTarget = ctx.getEnumMappingStrategy() .getDefaultNullEnumConstant( targetType.getTypeElement() ); } @@ -118,14 +120,14 @@ public class ValueMappingMethod extends MappingMethod { mappingEntries, valueMappings.nullValueTarget, valueMappings.defaultTargetValue, - !valueMappings.hasDefaultValue, + determineUnexpectedValueMappingException(), beforeMappingMethods, afterMappingMethods ); } private void initializeEnumTransformationStrategy() { - if ( !enumMapping.hasAnnotation() ) { + if ( !enumMapping.hasNameTransformationStrategy() ) { enumTransformationInvoker = EnumTransformationStrategyInvoker.DEFAULT; } else { @@ -290,7 +292,7 @@ public class ValueMappingMethod extends MappingMethod { } private String getEnumConstant(TypeElement typeElement, String enumConstant) { - return ctx.getEnumNamingStrategy().getEnumConstant( typeElement, enumConstant ); + return ctx.getEnumMappingStrategy().getEnumConstant( typeElement, enumConstant ); } private SelectionParameters getSelectionParameters(Method method, Types typeUtils) { @@ -408,12 +410,26 @@ public class ValueMappingMethod extends MappingMethod { Message.VALUEMAPPING_NON_EXISTING_CONSTANT_FROM_SPI, valueMappings.nullValueTarget, method.getReturnType(), - ctx.getEnumNamingStrategy() + ctx.getEnumMappingStrategy() ); } return !foundIncorrectMapping; } + + private Type determineUnexpectedValueMappingException() { + if ( !valueMappings.hasDefaultValue ) { + TypeMirror unexpectedValueMappingException = enumMapping.getUnexpectedValueMappingException(); + if ( unexpectedValueMappingException != null ) { + return ctx.getTypeFactory().getType( unexpectedValueMappingException ); + } + + return ctx.getTypeFactory() + .getType( ctx.getEnumMappingStrategy().getUnexpectedValueMappingExceptionType() ); + } + + return null; + } } private static class EnumTransformationStrategyInvoker { @@ -485,16 +501,28 @@ public class ValueMappingMethod extends MappingMethod { } private ValueMappingMethod(Method method, List enumMappings, String nullTarget, String defaultTarget, - boolean throwIllegalArgumentException, List beforeMappingMethods, + Type unexpectedValueMappingException, + List beforeMappingMethods, List afterMappingMethods) { super( method, beforeMappingMethods, afterMappingMethods ); this.valueMappings = enumMappings; this.nullTarget = nullTarget; this.defaultTarget = defaultTarget; - this.throwIllegalArgumentException = throwIllegalArgumentException; + this.unexpectedValueMappingException = unexpectedValueMappingException; this.overridden = method.overridesMethod(); } + @Override + public Set getImportTypes() { + Set importTypes = super.getImportTypes(); + + if ( unexpectedValueMappingException != null && !unexpectedValueMappingException.isJavaLangType() ) { + importTypes.addAll( unexpectedValueMappingException.getImportTypes() ); + } + + return importTypes; + } + public List getValueMappings() { return valueMappings; } @@ -507,8 +535,8 @@ public class ValueMappingMethod extends MappingMethod { return nullTarget; } - public boolean isThrowIllegalArgumentException() { - return throwIllegalArgumentException; + public Type getUnexpectedValueMappingException() { + return unexpectedValueMappingException; } public Parameter getSourceParameter() { 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 77911be2e..81f870e25 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 @@ -8,6 +8,7 @@ package org.mapstruct.ap.internal.model.source; import java.util.Collections; import java.util.Set; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import org.mapstruct.ap.internal.option.Options; @@ -127,6 +128,11 @@ public class DefaultOptions extends DelegatingOptions { return MappingControl.fromTypeMirror( mapper.mappingControl().getDefaultValue(), elementUtils ); } + @Override + public TypeMirror getUnexpectedValueMappingException() { + return null; + } + @Override public boolean hasAnnotation() { return false; diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/DelegatingOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/DelegatingOptions.java index 8bc6ab982..c45868198 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/DelegatingOptions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/DelegatingOptions.java @@ -105,6 +105,10 @@ public abstract class DelegatingOptions { return next.getMappingControl( elementUtils ); } + public TypeMirror getUnexpectedValueMappingException() { + return next.getUnexpectedValueMappingException(); + } + DelegatingOptions next() { return next; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/EnumMappingOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/EnumMappingOptions.java index 576474e68..86c415a4f 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/EnumMappingOptions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/EnumMappingOptions.java @@ -7,6 +7,7 @@ package org.mapstruct.ap.internal.model.source; import java.util.Map; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.type.TypeMirror; import org.mapstruct.ap.internal.gem.EnumMappingGem; import org.mapstruct.ap.internal.util.FormattingMessager; @@ -14,6 +15,8 @@ import org.mapstruct.ap.internal.util.Strings; import org.mapstruct.ap.spi.EnumTransformationStrategy; import static org.mapstruct.ap.internal.util.Message.ENUMMAPPING_INCORRECT_TRANSFORMATION_STRATEGY; +import static org.mapstruct.ap.internal.util.Message.ENUMMAPPING_MISSING_CONFIGURATION; +import static org.mapstruct.ap.internal.util.Message.ENUMMAPPING_NO_ELEMENTS; /** * @author Filip Hrisafov @@ -40,12 +43,25 @@ public class EnumMappingOptions extends DelegatingOptions { return valid; } + public boolean hasNameTransformationStrategy() { + return hasAnnotation() && Strings.isNotEmpty( getNameTransformationStrategy() ); + } + public String getNameTransformationStrategy() { - return enumMapping.nameTransformationStrategy().get(); + return enumMapping.nameTransformationStrategy().getValue(); } public String getNameTransformationConfiguration() { - return enumMapping.configuration().get(); + return enumMapping.configuration().getValue(); + } + + @Override + public TypeMirror getUnexpectedValueMappingException() { + if ( enumMapping != null && enumMapping.unexpectedValueMappingException().hasValue() ) { + return enumMapping.unexpectedValueMappingException().getValue(); + } + + return next().getUnexpectedValueMappingException(); } public boolean isInverse() { @@ -79,21 +95,47 @@ public class EnumMappingOptions extends DelegatingOptions { Map enumTransformationStrategies, FormattingMessager messager) { String strategy = gem.nameTransformationStrategy().getValue(); + String configuration = gem.configuration().getValue(); - if ( !enumTransformationStrategies.containsKey( strategy ) ) { - String registeredStrategies = Strings.join( enumTransformationStrategies.keySet(), ", " ); + boolean isConsistent = false; + + if ( Strings.isNotEmpty( strategy ) || Strings.isNotEmpty( configuration ) ) { + if ( !enumTransformationStrategies.containsKey( strategy ) ) { + String registeredStrategies = Strings.join( enumTransformationStrategies.keySet(), ", " ); + messager.printMessage( + method, + gem.mirror(), + gem.nameTransformationStrategy().getAnnotationValue(), + ENUMMAPPING_INCORRECT_TRANSFORMATION_STRATEGY, + strategy, + registeredStrategies + ); + + return false; + } + else if ( Strings.isEmpty( configuration ) ) { + messager.printMessage( + method, + gem.mirror(), + gem.configuration().getAnnotationValue(), + ENUMMAPPING_MISSING_CONFIGURATION + ); + return false; + } + + isConsistent = true; + } + + isConsistent = isConsistent || gem.unexpectedValueMappingException().hasValue(); + + if ( !isConsistent ) { messager.printMessage( method, gem.mirror(), - gem.nameTransformationStrategy().getAnnotationValue(), - ENUMMAPPING_INCORRECT_TRANSFORMATION_STRATEGY, - strategy, - registeredStrategies + ENUMMAPPING_NO_ELEMENTS ); - - return false; } - return true; + return isConsistent; } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapperConfigOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapperConfigOptions.java index ef25fda05..07f668e65 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapperConfigOptions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapperConfigOptions.java @@ -7,6 +7,7 @@ package org.mapstruct.ap.internal.model.source; import java.util.Set; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import org.mapstruct.ap.internal.gem.BuilderGem; @@ -137,6 +138,13 @@ public class MapperConfigOptions extends DelegatingOptions { next().getMappingControl( elementUtils ); } + @Override + public TypeMirror getUnexpectedValueMappingException() { + return mapperConfig.unexpectedValueMappingException().hasValue() ? + mapperConfig.unexpectedValueMappingException().get() : + next().getUnexpectedValueMappingException(); + } + @Override public boolean hasAnnotation() { return mapperConfig != null; diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapperOptions.java b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapperOptions.java index 19b7d8f0b..b054c628a 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapperOptions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/source/MapperOptions.java @@ -11,6 +11,7 @@ import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import org.mapstruct.ap.internal.option.Options; @@ -167,6 +168,13 @@ public class MapperOptions extends DelegatingOptions { next().getMappingControl( elementUtils ); } + @Override + public TypeMirror getUnexpectedValueMappingException() { + return mapper.unexpectedValueMappingException().hasValue() ? + mapper.unexpectedValueMappingException().get() : + next().getUnexpectedValueMappingException(); + } + // @Mapper specific public DeclaredType mapperConfigType() { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultModelElementProcessorContext.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultModelElementProcessorContext.java index f8f7eee5b..1514f4f5e 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultModelElementProcessorContext.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/DefaultModelElementProcessorContext.java @@ -26,7 +26,7 @@ import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.RoundContext; import org.mapstruct.ap.internal.util.workarounds.TypesDecorator; import org.mapstruct.ap.internal.version.VersionInformation; -import org.mapstruct.ap.spi.EnumNamingStrategy; +import org.mapstruct.ap.spi.EnumMappingStrategy; import org.mapstruct.ap.spi.EnumTransformationStrategy; /** @@ -101,8 +101,8 @@ public class DefaultModelElementProcessorContext implements ProcessorContext { } @Override - public EnumNamingStrategy getEnumNamingStrategy() { - return roundContext.getAnnotationProcessorContext().getEnumNamingStrategy(); + public EnumMappingStrategy getEnumMappingStrategy() { + return roundContext.getAnnotationProcessorContext().getEnumMappingStrategy(); } @Override 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 adb0b8f24..58c6f2513 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 @@ -101,7 +101,7 @@ public class MapperCreationProcessor implements ModelElementProcessor { Map getEnumTransformationStrategies(); - EnumNamingStrategy getEnumNamingStrategy(); + EnumMappingStrategy getEnumMappingStrategy(); Options getOptions(); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/AnnotationProcessorContext.java b/processor/src/main/java/org/mapstruct/ap/internal/util/AnnotationProcessorContext.java index 4b70bd60a..86fb7e309 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/AnnotationProcessorContext.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/AnnotationProcessorContext.java @@ -24,8 +24,8 @@ import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor; import org.mapstruct.ap.spi.BuilderProvider; import org.mapstruct.ap.spi.DefaultAccessorNamingStrategy; import org.mapstruct.ap.spi.DefaultBuilderProvider; -import org.mapstruct.ap.spi.DefaultEnumNamingStrategy; -import org.mapstruct.ap.spi.EnumNamingStrategy; +import org.mapstruct.ap.spi.DefaultEnumMappingStrategy; +import org.mapstruct.ap.spi.EnumMappingStrategy; import org.mapstruct.ap.spi.EnumTransformationStrategy; import org.mapstruct.ap.spi.FreeBuilderAccessorNamingStrategy; import org.mapstruct.ap.spi.ImmutablesAccessorNamingStrategy; @@ -43,7 +43,7 @@ public class AnnotationProcessorContext implements MapStructProcessingEnvironmen private BuilderProvider builderProvider; private AccessorNamingStrategy accessorNamingStrategy; - private EnumNamingStrategy enumNamingStrategy; + private EnumMappingStrategy enumMappingStrategy; private boolean initialized; private Map enumTransformationStrategies; @@ -113,13 +113,13 @@ public class AnnotationProcessorContext implements MapStructProcessingEnvironmen } this.accessorNaming = new AccessorNamingUtils( this.accessorNamingStrategy ); - this.enumNamingStrategy = Services.get( EnumNamingStrategy.class, new DefaultEnumNamingStrategy() ); - this.enumNamingStrategy.init( this ); + this.enumMappingStrategy = Services.get( EnumMappingStrategy.class, new DefaultEnumMappingStrategy() ); + this.enumMappingStrategy.init( this ); if ( verbose ) { messager.printMessage( Diagnostic.Kind.NOTE, "MapStruct: Using enum naming strategy: " - + this.enumNamingStrategy.getClass().getCanonicalName() + + this.enumMappingStrategy.getClass().getCanonicalName() ); } @@ -250,9 +250,9 @@ public class AnnotationProcessorContext implements MapStructProcessingEnvironmen return accessorNamingStrategy; } - public EnumNamingStrategy getEnumNamingStrategy() { + public EnumMappingStrategy getEnumMappingStrategy() { initialize(); - return enumNamingStrategy; + return enumMappingStrategy; } public BuilderProvider getBuilderProvider() { diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java index 6f0db248b..87d3a9abd 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Message.java @@ -105,6 +105,8 @@ public enum Message { ENUMMAPPING_UNMAPPED_SOURCES( "The following constants from the source enum have no corresponding constant in the target enum and must be be mapped via adding additional mappings: %s." ), ENUMMAPPING_REMOVED( "Mapping of Enums via @Mapping is removed. Please use @ValueMapping instead!" ), ENUMMAPPING_INCORRECT_TRANSFORMATION_STRATEGY( "There is no registered EnumTransformationStrategy for '%s'. Registered strategies are: %s." ), + ENUMMAPPING_MISSING_CONFIGURATION( "Configuration has to be defined when strategy is defined." ), + ENUMMAPPING_NO_ELEMENTS( "'nameTransformationStrategy', 'configuration' and 'unexpectedValueMappingException' are undefined in @EnumMapping, define at least one of them." ), LIFECYCLEMETHOD_AMBIGUOUS_PARAMETERS( "Lifecycle method has multiple matching parameters (e. g. same type), in this case please ensure to name the parameters in the lifecycle and mapping method identical. This lifecycle method will not be used for the mapping method '%s'.", Diagnostic.Kind.WARNING), @@ -169,7 +171,7 @@ public enum Message { VALUEMAPPING_UNMAPPED_SOURCES( "The following constants from the %s enum have no corresponding constant in the %s enum and must be be mapped via adding additional mappings: %s." ), VALUEMAPPING_ANY_REMAINING_FOR_NON_ENUM( "Source = \"\" can only be used on targets of type enum and not for %s." ), VALUEMAPPING_ANY_REMAINING_OR_UNMAPPED_MISSING( "Source = \"\" or \"\" is advisable for mapping of type String to an enum type.", Diagnostic.Kind.WARNING ), - VALUEMAPPING_NON_EXISTING_CONSTANT_FROM_SPI( "Constant %s doesn't exist in enum type %s. Constant was returned from EnumNamingStrategy: %s"), + VALUEMAPPING_NON_EXISTING_CONSTANT_FROM_SPI( "Constant %s doesn't exist in enum type %s. Constant was returned from EnumMappingStrategy: %s"), VALUEMAPPING_NON_EXISTING_CONSTANT( "Constant %s doesn't exist in enum type %s." ); // CHECKSTYLE:ON diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java index 07049c17a..f1eca8815 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java @@ -129,6 +129,10 @@ public class Strings { return string == null || string.isEmpty(); } + public static boolean isNotEmpty(String string) { + return !isEmpty( string ); + } + public static String getSafeVariableName(String name, String... existingVariableNames) { return getSafeVariableName( name, Arrays.asList( existingVariableNames ) ); } diff --git a/processor/src/main/java/org/mapstruct/ap/spi/DefaultEnumNamingStrategy.java b/processor/src/main/java/org/mapstruct/ap/spi/DefaultEnumMappingStrategy.java similarity index 68% rename from processor/src/main/java/org/mapstruct/ap/spi/DefaultEnumNamingStrategy.java rename to processor/src/main/java/org/mapstruct/ap/spi/DefaultEnumMappingStrategy.java index a54df7bc0..62d6c3280 100644 --- a/processor/src/main/java/org/mapstruct/ap/spi/DefaultEnumNamingStrategy.java +++ b/processor/src/main/java/org/mapstruct/ap/spi/DefaultEnumMappingStrategy.java @@ -14,7 +14,7 @@ import javax.lang.model.util.Types; * * @since 1.4 */ -public class DefaultEnumNamingStrategy implements EnumNamingStrategy { +public class DefaultEnumMappingStrategy implements EnumMappingStrategy { protected Elements elementUtils; protected Types typeUtils; @@ -34,4 +34,13 @@ public class DefaultEnumNamingStrategy implements EnumNamingStrategy { public String getEnumConstant(TypeElement enumType, String enumConstant) { return enumConstant; } + + @Override + public TypeElement getUnexpectedValueMappingExceptionType() { + return elementUtils.getTypeElement( getUnexpectedValueMappingExceptionClass().getCanonicalName() ); + } + + protected Class getUnexpectedValueMappingExceptionClass() { + return IllegalArgumentException.class; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/spi/EnumNamingStrategy.java b/processor/src/main/java/org/mapstruct/ap/spi/EnumMappingStrategy.java similarity index 80% rename from processor/src/main/java/org/mapstruct/ap/spi/EnumNamingStrategy.java rename to processor/src/main/java/org/mapstruct/ap/spi/EnumMappingStrategy.java index a2361eefd..97088cd8c 100644 --- a/processor/src/main/java/org/mapstruct/ap/spi/EnumNamingStrategy.java +++ b/processor/src/main/java/org/mapstruct/ap/spi/EnumMappingStrategy.java @@ -13,11 +13,12 @@ import org.mapstruct.util.Experimental; * A service provider interface for the mapping between different enum constants * * @author Arne Seime + * @author Filip Hrisafov * * @since 1.4 */ @Experimental("This SPI can have it's signature changed in subsequent releases") -public interface EnumNamingStrategy { +public interface EnumMappingStrategy { /** * Initializes the enum value mapping strategy @@ -47,4 +48,12 @@ public interface EnumNamingStrategy { * never return null */ String getEnumConstant(TypeElement enumType, String enumConstant); + + /** + * Return the type element of the exception that should be used in the generated code + * for an unexpected enum constant. + * + * @return the type element of the exception that should be used, never {@code null} + */ + TypeElement getUnexpectedValueMappingExceptionType(); } diff --git a/processor/src/main/resources/org/mapstruct/ap/internal/model/ValueMappingMethod.ftl b/processor/src/main/resources/org/mapstruct/ap/internal/model/ValueMappingMethod.ftl index ba16d56a2..530d5643e 100644 --- a/processor/src/main/resources/org/mapstruct/ap/internal/model/ValueMappingMethod.ftl +++ b/processor/src/main/resources/org/mapstruct/ap/internal/model/ValueMappingMethod.ftl @@ -25,7 +25,7 @@ case <@writeSource source=valueMapping.source/>: ${resultName} = <@writeTarget target=valueMapping.target/>; break; - default: <#if throwIllegalArgumentException>throw new IllegalArgumentException( "Unexpected enum constant: " + ${sourceParameter.name} )<#else>${resultName} = <@writeTarget target=defaultTarget/>; + default: <#if unexpectedValueMappingException??>throw new <@includeModel object=unexpectedValueMappingException />( "Unexpected enum constant: " + ${sourceParameter.name} )<#else>${resultName} = <@writeTarget target=defaultTarget/>; } <#list beforeMappingReferencesWithMappingTarget as callback> <#if callback_index = 0> @@ -40,7 +40,7 @@ <@includeModel object=callback targetBeanName=resultName targetType=resultType/> - <#if !(valueMappings.empty && throwIllegalArgumentException)> + <#if !(valueMappings.empty && unexpectedValueMappingException??)> return ${resultName}; } diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/CustomIllegalArgumentException.java b/processor/src/test/java/org/mapstruct/ap/test/value/CustomIllegalArgumentException.java new file mode 100644 index 000000000..e5552d798 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/value/CustomIllegalArgumentException.java @@ -0,0 +1,16 @@ +/* + * 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.value; + +/** + * @author Filip Hrisafov + */ +public class CustomIllegalArgumentException extends RuntimeException { + + public CustomIllegalArgumentException(String message) { + super( message ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/erroneous/EmptyEnumMappingMapper.java b/processor/src/test/java/org/mapstruct/ap/test/value/erroneous/EmptyEnumMappingMapper.java new file mode 100644 index 000000000..e0f2f112d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/value/erroneous/EmptyEnumMappingMapper.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.value.erroneous; + +import org.mapstruct.EnumMapping; +import org.mapstruct.Mapper; +import org.mapstruct.ValueMapping; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface EmptyEnumMappingMapper { + + @EnumMapping + @ValueMapping(source = "EXTRA", target = "SPECIAL") + @ValueMapping(source = "STANDARD", target = "DEFAULT") + @ValueMapping(source = "NORMAL", target = "DEFAULT") + ExternalOrderType onlyWithMappings(OrderType orderType); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/erroneous/ErroneousEnumMappingTest.java b/processor/src/test/java/org/mapstruct/ap/test/value/erroneous/ErroneousEnumMappingTest.java new file mode 100644 index 000000000..45d374f21 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/value/erroneous/ErroneousEnumMappingTest.java @@ -0,0 +1,63 @@ +/* + * 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.value.erroneous; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; +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("2169") +@RunWith(AnnotationProcessorTestRunner.class) +@WithClasses({ + CustomIllegalArgumentException.class, + ExternalOrderType.class, + OrderType.class, +}) +public class ErroneousEnumMappingTest { + + @Test + @WithClasses({ + EmptyEnumMappingMapper.class + }) + @ExpectedCompilationOutcome(value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = EmptyEnumMappingMapper.class, + kind = javax.tools.Diagnostic.Kind.ERROR, + line = 20, + message = "'nameTransformationStrategy', 'configuration' and 'unexpectedValueMappingException' are " + + "undefined in @EnumMapping, define at least one of them." + ) + } + ) + public void shouldCompileErrorWhenEnumMappingIsEmpty() { + } + + @Test + @WithClasses({ + NoConfigurationEnumMappingMapper.class + }) + @ExpectedCompilationOutcome(value = CompilationResult.FAILED, + diagnostics = { + @Diagnostic(type = NoConfigurationEnumMappingMapper.class, + kind = javax.tools.Diagnostic.Kind.ERROR, + line = 21, + message = "Configuration has to be defined when strategy is defined.") + } + ) + public void shouldCompileErrorWhenEnumMappingHasStrategyButNoConfiguration() { + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/erroneous/NoConfigurationEnumMappingMapper.java b/processor/src/test/java/org/mapstruct/ap/test/value/erroneous/NoConfigurationEnumMappingMapper.java new file mode 100644 index 000000000..9d82ed059 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/value/erroneous/NoConfigurationEnumMappingMapper.java @@ -0,0 +1,26 @@ +/* + * 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.value.erroneous; + +import org.mapstruct.EnumMapping; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ValueMapping; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface NoConfigurationEnumMappingMapper { + + @EnumMapping(nameTransformationStrategy = MappingConstants.PREFIX_TRANSFORMATION) + @ValueMapping(source = "EXTRA", target = "SPECIAL") + @ValueMapping(source = "STANDARD", target = "DEFAULT") + @ValueMapping(source = "NORMAL", target = "DEFAULT") + ExternalOrderType onlyWithMappings(OrderType orderType); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/exception/Config.java b/processor/src/test/java/org/mapstruct/ap/test/value/exception/Config.java new file mode 100644 index 000000000..627ac7970 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/value/exception/Config.java @@ -0,0 +1,16 @@ +/* + * 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.value.exception; + +import org.mapstruct.MapperConfig; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; + +/** + * @author Filip Hrisafov + */ +@MapperConfig(unexpectedValueMappingException = CustomIllegalArgumentException.class) +public interface Config { +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapper.java b/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapper.java new file mode 100644 index 000000000..6fc94fb8a --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapper.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.value.exception; + +import org.mapstruct.InheritInverseConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ValueMapping; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; + +/** + * @author Filip Hrisafov + */ +@Mapper(unexpectedValueMappingException = CustomIllegalArgumentException.class) +public interface CustomUnexpectedValueMappingExceptionDefinedInMapper { + + @ValueMapping(source = MappingConstants.ANY_UNMAPPED, target = "DEFAULT") + ExternalOrderType withAnyUnmapped(OrderType orderType); + + @ValueMapping(source = MappingConstants.ANY_REMAINING, target = "DEFAULT") + ExternalOrderType withAnyRemaining(OrderType orderType); + + @ValueMapping(source = "EXTRA", target = "SPECIAL") + @ValueMapping(source = "STANDARD", target = "DEFAULT") + @ValueMapping(source = "NORMAL", target = "DEFAULT") + ExternalOrderType onlyWithMappings(OrderType orderType); + + @InheritInverseConfiguration(name = "onlyWithMappings") + OrderType inverseOnlyWithMappings(ExternalOrderType orderType); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMapping.java b/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMapping.java new file mode 100644 index 000000000..c5396ad48 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMapping.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.value.exception; + +import org.mapstruct.EnumMapping; +import org.mapstruct.InheritInverseConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ValueMapping; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; + +/** + * @author Filip Hrisafov + */ +@Mapper(unexpectedValueMappingException = CustomIllegalArgumentException.class) +public interface CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMapping { + + @ValueMapping(source = MappingConstants.ANY_UNMAPPED, target = "DEFAULT") + ExternalOrderType withAnyUnmapped(OrderType orderType); + + @ValueMapping(source = MappingConstants.ANY_REMAINING, target = "DEFAULT") + ExternalOrderType withAnyRemaining(OrderType orderType); + + @ValueMapping(source = "EXTRA", target = "SPECIAL") + @ValueMapping(source = "STANDARD", target = "DEFAULT") + @ValueMapping(source = "NORMAL", target = "DEFAULT") + ExternalOrderType onlyWithMappings(OrderType orderType); + + // If unexpectedValueMappingException is explicitly defined then it should be used instead of what is in the SPI + @EnumMapping(unexpectedValueMappingException = IllegalArgumentException.class) + @InheritInverseConfiguration(name = "onlyWithMappings") + OrderType inverseOnlyWithMappings(ExternalOrderType orderType); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperConfig.java b/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperConfig.java new file mode 100644 index 000000000..3e3d7e219 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperConfig.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.value.exception; + +import org.mapstruct.InheritInverseConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ValueMapping; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; + +/** + * @author Filip Hrisafov + */ +@Mapper(config = Config.class) +public interface CustomUnexpectedValueMappingExceptionDefinedInMapperConfig { + + @ValueMapping(source = MappingConstants.ANY_UNMAPPED, target = "DEFAULT") + ExternalOrderType withAnyUnmapped(OrderType orderType); + + @ValueMapping(source = MappingConstants.ANY_REMAINING, target = "DEFAULT") + ExternalOrderType withAnyRemaining(OrderType orderType); + + @ValueMapping(source = "EXTRA", target = "SPECIAL") + @ValueMapping(source = "STANDARD", target = "DEFAULT") + @ValueMapping(source = "NORMAL", target = "DEFAULT") + ExternalOrderType onlyWithMappings(OrderType orderType); + + @InheritInverseConfiguration(name = "onlyWithMappings") + OrderType inverseOnlyWithMappings(ExternalOrderType orderType); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionMapper.java b/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionMapper.java new file mode 100644 index 000000000..96c8b297c --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionMapper.java @@ -0,0 +1,39 @@ +/* + * 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.value.exception; + +import org.mapstruct.EnumMapping; +import org.mapstruct.InheritInverseConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants; +import org.mapstruct.ValueMapping; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface CustomUnexpectedValueMappingExceptionMapper { + + @EnumMapping(unexpectedValueMappingException = CustomIllegalArgumentException.class) + @ValueMapping( source = MappingConstants.ANY_UNMAPPED, target = "DEFAULT" ) + ExternalOrderType withAnyUnmapped(OrderType orderType); + + @EnumMapping(unexpectedValueMappingException = CustomIllegalArgumentException.class) + @ValueMapping( source = MappingConstants.ANY_REMAINING, target = "DEFAULT" ) + ExternalOrderType withAnyRemaining(OrderType orderType); + + @EnumMapping(unexpectedValueMappingException = CustomIllegalArgumentException.class) + @ValueMapping(source = "EXTRA", target = "SPECIAL") + @ValueMapping(source = "STANDARD", target = "DEFAULT") + @ValueMapping(source = "NORMAL", target = "DEFAULT") + ExternalOrderType onlyWithMappings(OrderType orderType); + + @InheritInverseConfiguration(name = "onlyWithMappings") + OrderType inverseOnlyWithMappings(ExternalOrderType orderType); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionTest.java b/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionTest.java new file mode 100644 index 000000000..fbbf70285 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionTest.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.value.exception; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; +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; + +/** + * @author Filip Hrisafov + */ +@IssueKey("2169") +@RunWith(AnnotationProcessorTestRunner.class) +@WithClasses({ + Config.class, + CustomUnexpectedValueMappingExceptionDefinedInMapper.class, + CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMapping.class, + CustomUnexpectedValueMappingExceptionDefinedInMapperConfig.class, + CustomUnexpectedValueMappingExceptionMapper.class, + CustomIllegalArgumentException.class, + ExternalOrderType.class, + OrderType.class +}) +public class CustomUnexpectedValueMappingExceptionTest { + + @Rule + public final GeneratedSource generatedSource = new GeneratedSource(); + + @Test + public void shouldGenerateCustomUnexpectedValueMappingException() { + generatedSource.addComparisonToFixtureFor( + CustomUnexpectedValueMappingExceptionDefinedInMapper.class, + CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMapping.class, + CustomUnexpectedValueMappingExceptionDefinedInMapperConfig.class, + CustomUnexpectedValueMappingExceptionMapper.class + ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomCheeseMapper.java b/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomCheeseMapper.java index 6524f67c3..b042405c4 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomCheeseMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomCheeseMapper.java @@ -5,6 +5,7 @@ */ package org.mapstruct.ap.test.value.spi; +import org.mapstruct.EnumMapping; import org.mapstruct.Mapper; import org.mapstruct.MappingConstants; import org.mapstruct.ValueMapping; @@ -24,6 +25,8 @@ public interface CustomCheeseMapper { String mapToString(CustomCheeseType cheeseType); + // If unexpectedValueMappingException is explicitly defined then it should be used instead of what is in the SPI + @EnumMapping(unexpectedValueMappingException = IllegalArgumentException.class) String mapToString(CheeseType cheeseType); @ValueMapping(source = MappingConstants.ANY_REMAINING, target = "CUSTOM_BRIE") diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumNamingStrategy.java b/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumMappingStrategy.java similarity index 77% rename from processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumNamingStrategy.java rename to processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumMappingStrategy.java index f84ebaf7b..b505dd640 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumNamingStrategy.java +++ b/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumMappingStrategy.java @@ -9,13 +9,14 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; import org.mapstruct.ap.internal.gem.MappingConstantsGem; -import org.mapstruct.ap.spi.DefaultEnumNamingStrategy; -import org.mapstruct.ap.spi.EnumNamingStrategy; +import org.mapstruct.ap.spi.DefaultEnumMappingStrategy; +import org.mapstruct.ap.spi.EnumMappingStrategy; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; /** * @author Filip Hrisafov */ -public class CustomEnumNamingStrategy extends DefaultEnumNamingStrategy implements EnumNamingStrategy { +public class CustomEnumMappingStrategy extends DefaultEnumMappingStrategy implements EnumMappingStrategy { @Override public String getDefaultNullEnumConstant(TypeElement enumType) { @@ -51,4 +52,9 @@ public class CustomEnumNamingStrategy extends DefaultEnumNamingStrategy implemen return false; } + + @Override + protected Class getUnexpectedValueMappingExceptionClass() { + return CustomIllegalArgumentException.class; + } } diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumNamingStrategyTest.java b/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumMappingStrategyTest.java similarity index 94% rename from processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumNamingStrategyTest.java rename to processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumMappingStrategyTest.java index 47a0a5d64..9cce52d7b 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumNamingStrategyTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomEnumMappingStrategyTest.java @@ -8,6 +8,7 @@ package org.mapstruct.ap.test.value.spi; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.ap.testutil.WithServiceImplementation; import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; @@ -23,9 +24,10 @@ import static org.assertj.core.api.Assertions.assertThat; CheeseType.class, CustomCheeseType.class, CustomEnumMarker.class, + CustomIllegalArgumentException.class, }) -@WithServiceImplementation(CustomEnumNamingStrategy.class) -public class CustomEnumNamingStrategyTest { +@WithServiceImplementation(CustomEnumMappingStrategy.class) +public class CustomEnumMappingStrategyTest { @Rule public final GeneratedSource generatedSource = new GeneratedSource(); @@ -34,7 +36,7 @@ public class CustomEnumNamingStrategyTest { @WithClasses({ CustomCheeseMapper.class }) - public void shouldApplyCustomEnumNamingStrategy() { + public void shouldApplyCustomEnumMappingStrategy() { generatedSource.addComparisonToFixtureFor( CustomCheeseMapper.class ); CustomCheeseMapper mapper = CustomCheeseMapper.INSTANCE; @@ -80,7 +82,7 @@ public class CustomEnumNamingStrategyTest { @WithClasses({ OverridesCustomCheeseMapper.class }) - public void shouldApplyDefinedMappingsInsteadOfCustomEnumNamingStrategy() { + public void shouldApplyDefinedMappingsInsteadOfCustomEnumMappingStrategy() { OverridesCustomCheeseMapper mapper = OverridesCustomCheeseMapper.INSTANCE; // CheeseType -> CustomCheeseType diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumNamingStrategy.java b/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumMappingStrategy.java similarity index 87% rename from processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumNamingStrategy.java rename to processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumMappingStrategy.java index 671ad45c0..8a4f2b5bd 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumNamingStrategy.java +++ b/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumMappingStrategy.java @@ -9,13 +9,13 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; import org.mapstruct.ap.internal.gem.MappingConstantsGem; -import org.mapstruct.ap.spi.DefaultEnumNamingStrategy; -import org.mapstruct.ap.spi.EnumNamingStrategy; +import org.mapstruct.ap.spi.DefaultEnumMappingStrategy; +import org.mapstruct.ap.spi.EnumMappingStrategy; /** * @author Filip Hrisafov */ -public class CustomErroneousEnumNamingStrategy extends DefaultEnumNamingStrategy implements EnumNamingStrategy { +public class CustomErroneousEnumMappingStrategy extends DefaultEnumMappingStrategy implements EnumMappingStrategy { @Override public String getDefaultNullEnumConstant(TypeElement enumType) { diff --git a/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumNamingStrategyTest.java b/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumMappingStrategyTest.java similarity index 90% rename from processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumNamingStrategyTest.java rename to processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumMappingStrategyTest.java index 82d6be4c2..9cb1337bc 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumNamingStrategyTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/value/spi/CustomErroneousEnumMappingStrategyTest.java @@ -25,8 +25,8 @@ import static org.assertj.core.api.Assertions.assertThat; CustomCheeseType.class, CustomEnumMarker.class, }) -@WithServiceImplementation(CustomErroneousEnumNamingStrategy.class) -public class CustomErroneousEnumNamingStrategyTest { +@WithServiceImplementation(CustomErroneousEnumMappingStrategy.class) +public class CustomErroneousEnumMappingStrategyTest { @Test @WithClasses({ @@ -37,18 +37,18 @@ public class CustomErroneousEnumNamingStrategyTest { @Diagnostic( type = CustomCheeseMapper.class, kind = javax.tools.Diagnostic.Kind.ERROR, - line = 23, + line = 24, messageRegExp = "Constant INCORRECT doesn't exist in enum type " + "org\\.mapstruct\\.ap\\.test\\.value\\.spi\\.CustomCheeseType." + - " Constant was returned from EnumNamingStrategy: .*CustomErroneousEnumNamingStrategy@.*" + " Constant was returned from EnumMappingStrategy: .*CustomErroneousEnumMappingStrategy@.*" ), @Diagnostic( type = CustomCheeseMapper.class, kind = javax.tools.Diagnostic.Kind.ERROR, - line = 30, + line = 33, messageRegExp = "Constant INCORRECT doesn't exist in enum type " + "org\\.mapstruct\\.ap\\.test\\.value\\.spi\\.CustomCheeseType." + - " Constant was returned from EnumNamingStrategy: .*CustomErroneousEnumNamingStrategy@.*" + " Constant was returned from EnumMappingStrategy: .*CustomErroneousEnumMappingStrategy@.*" ) } ) @@ -59,7 +59,7 @@ public class CustomErroneousEnumNamingStrategyTest { @WithClasses({ OverridesCustomCheeseMapper.class }) - public void shouldApplyDefinedMappingsInsteadOfCustomEnumNamingStrategy() { + public void shouldApplyDefinedMappingsInsteadOfCustomEnumMappingStrategy() { OverridesCustomCheeseMapper mapper = OverridesCustomCheeseMapper.INSTANCE; // CheeseType -> CustomCheeseType diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMappingImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMappingImpl.java new file mode 100644 index 000000000..f0ae6eecd --- /dev/null +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMappingImpl.java @@ -0,0 +1,101 @@ +/* + * 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.value.exception; + +import javax.annotation.Generated; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; + +@Generated( + value = "org.mapstruct.ap.MappingProcessor", + date = "2020-08-29T09:36:57+0200", + comments = "version: , compiler: javac, environment: Java 11.0.2 (AdoptOpenJDK)" +) +public class CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMappingImpl implements CustomUnexpectedValueMappingExceptionDefinedInMapperAndEnumMapping { + + @Override + public ExternalOrderType withAnyUnmapped(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + default: externalOrderType = ExternalOrderType.DEFAULT; + } + + return externalOrderType; + } + + @Override + public ExternalOrderType withAnyRemaining(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + case RETAIL: externalOrderType = ExternalOrderType.RETAIL; + break; + case B2B: externalOrderType = ExternalOrderType.B2B; + break; + default: externalOrderType = ExternalOrderType.DEFAULT; + } + + return externalOrderType; + } + + @Override + public ExternalOrderType onlyWithMappings(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + case EXTRA: externalOrderType = ExternalOrderType.SPECIAL; + break; + case STANDARD: externalOrderType = ExternalOrderType.DEFAULT; + break; + case NORMAL: externalOrderType = ExternalOrderType.DEFAULT; + break; + case RETAIL: externalOrderType = ExternalOrderType.RETAIL; + break; + case B2B: externalOrderType = ExternalOrderType.B2B; + break; + default: throw new CustomIllegalArgumentException( "Unexpected enum constant: " + orderType ); + } + + return externalOrderType; + } + + @Override + public OrderType inverseOnlyWithMappings(ExternalOrderType orderType) { + if ( orderType == null ) { + return null; + } + + OrderType orderType1; + + switch ( orderType ) { + case SPECIAL: orderType1 = OrderType.EXTRA; + break; + case DEFAULT: orderType1 = OrderType.STANDARD; + break; + case RETAIL: orderType1 = OrderType.RETAIL; + break; + case B2B: orderType1 = OrderType.B2B; + break; + default: throw new IllegalArgumentException( "Unexpected enum constant: " + orderType ); + } + + return orderType1; + } +} diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperConfigImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperConfigImpl.java new file mode 100644 index 000000000..fee7a2bb1 --- /dev/null +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperConfigImpl.java @@ -0,0 +1,101 @@ +/* + * 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.value.exception; + +import javax.annotation.Generated; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; + +@Generated( + value = "org.mapstruct.ap.MappingProcessor", + date = "2020-08-29T09:36:57+0200", + comments = "version: , compiler: javac, environment: Java 11.0.2 (AdoptOpenJDK)" +) +public class CustomUnexpectedValueMappingExceptionDefinedInMapperConfigImpl implements CustomUnexpectedValueMappingExceptionDefinedInMapperConfig { + + @Override + public ExternalOrderType withAnyUnmapped(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + default: externalOrderType = ExternalOrderType.DEFAULT; + } + + return externalOrderType; + } + + @Override + public ExternalOrderType withAnyRemaining(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + case RETAIL: externalOrderType = ExternalOrderType.RETAIL; + break; + case B2B: externalOrderType = ExternalOrderType.B2B; + break; + default: externalOrderType = ExternalOrderType.DEFAULT; + } + + return externalOrderType; + } + + @Override + public ExternalOrderType onlyWithMappings(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + case EXTRA: externalOrderType = ExternalOrderType.SPECIAL; + break; + case STANDARD: externalOrderType = ExternalOrderType.DEFAULT; + break; + case NORMAL: externalOrderType = ExternalOrderType.DEFAULT; + break; + case RETAIL: externalOrderType = ExternalOrderType.RETAIL; + break; + case B2B: externalOrderType = ExternalOrderType.B2B; + break; + default: throw new CustomIllegalArgumentException( "Unexpected enum constant: " + orderType ); + } + + return externalOrderType; + } + + @Override + public OrderType inverseOnlyWithMappings(ExternalOrderType orderType) { + if ( orderType == null ) { + return null; + } + + OrderType orderType1; + + switch ( orderType ) { + case SPECIAL: orderType1 = OrderType.EXTRA; + break; + case DEFAULT: orderType1 = OrderType.STANDARD; + break; + case RETAIL: orderType1 = OrderType.RETAIL; + break; + case B2B: orderType1 = OrderType.B2B; + break; + default: throw new CustomIllegalArgumentException( "Unexpected enum constant: " + orderType ); + } + + return orderType1; + } +} diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperImpl.java new file mode 100644 index 000000000..a89733918 --- /dev/null +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionDefinedInMapperImpl.java @@ -0,0 +1,101 @@ +/* + * 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.value.exception; + +import javax.annotation.Generated; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; + +@Generated( + value = "org.mapstruct.ap.MappingProcessor", + date = "2020-08-29T09:36:57+0200", + comments = "version: , compiler: javac, environment: Java 11.0.2 (AdoptOpenJDK)" +) +public class CustomUnexpectedValueMappingExceptionDefinedInMapperImpl implements CustomUnexpectedValueMappingExceptionDefinedInMapper { + + @Override + public ExternalOrderType withAnyUnmapped(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + default: externalOrderType = ExternalOrderType.DEFAULT; + } + + return externalOrderType; + } + + @Override + public ExternalOrderType withAnyRemaining(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + case RETAIL: externalOrderType = ExternalOrderType.RETAIL; + break; + case B2B: externalOrderType = ExternalOrderType.B2B; + break; + default: externalOrderType = ExternalOrderType.DEFAULT; + } + + return externalOrderType; + } + + @Override + public ExternalOrderType onlyWithMappings(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + case EXTRA: externalOrderType = ExternalOrderType.SPECIAL; + break; + case STANDARD: externalOrderType = ExternalOrderType.DEFAULT; + break; + case NORMAL: externalOrderType = ExternalOrderType.DEFAULT; + break; + case RETAIL: externalOrderType = ExternalOrderType.RETAIL; + break; + case B2B: externalOrderType = ExternalOrderType.B2B; + break; + default: throw new CustomIllegalArgumentException( "Unexpected enum constant: " + orderType ); + } + + return externalOrderType; + } + + @Override + public OrderType inverseOnlyWithMappings(ExternalOrderType orderType) { + if ( orderType == null ) { + return null; + } + + OrderType orderType1; + + switch ( orderType ) { + case SPECIAL: orderType1 = OrderType.EXTRA; + break; + case DEFAULT: orderType1 = OrderType.STANDARD; + break; + case RETAIL: orderType1 = OrderType.RETAIL; + break; + case B2B: orderType1 = OrderType.B2B; + break; + default: throw new CustomIllegalArgumentException( "Unexpected enum constant: " + orderType ); + } + + return orderType1; + } +} diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionMapperImpl.java new file mode 100644 index 000000000..c22ff08f6 --- /dev/null +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/exception/CustomUnexpectedValueMappingExceptionMapperImpl.java @@ -0,0 +1,101 @@ +/* + * 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.value.exception; + +import javax.annotation.Generated; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; +import org.mapstruct.ap.test.value.ExternalOrderType; +import org.mapstruct.ap.test.value.OrderType; + +@Generated( + value = "org.mapstruct.ap.MappingProcessor", + date = "2020-08-02T09:36:57+0200", + comments = "version: , compiler: javac, environment: Java 11.0.2 (AdoptOpenJDK)" +) +public class CustomUnexpectedValueMappingExceptionMapperImpl implements CustomUnexpectedValueMappingExceptionMapper { + + @Override + public ExternalOrderType withAnyUnmapped(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + default: externalOrderType = ExternalOrderType.DEFAULT; + } + + return externalOrderType; + } + + @Override + public ExternalOrderType withAnyRemaining(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + case RETAIL: externalOrderType = ExternalOrderType.RETAIL; + break; + case B2B: externalOrderType = ExternalOrderType.B2B; + break; + default: externalOrderType = ExternalOrderType.DEFAULT; + } + + return externalOrderType; + } + + @Override + public ExternalOrderType onlyWithMappings(OrderType orderType) { + if ( orderType == null ) { + return null; + } + + ExternalOrderType externalOrderType; + + switch ( orderType ) { + case EXTRA: externalOrderType = ExternalOrderType.SPECIAL; + break; + case STANDARD: externalOrderType = ExternalOrderType.DEFAULT; + break; + case NORMAL: externalOrderType = ExternalOrderType.DEFAULT; + break; + case RETAIL: externalOrderType = ExternalOrderType.RETAIL; + break; + case B2B: externalOrderType = ExternalOrderType.B2B; + break; + default: throw new CustomIllegalArgumentException( "Unexpected enum constant: " + orderType ); + } + + return externalOrderType; + } + + @Override + public OrderType inverseOnlyWithMappings(ExternalOrderType orderType) { + if ( orderType == null ) { + return null; + } + + OrderType orderType1; + + switch ( orderType ) { + case SPECIAL: orderType1 = OrderType.EXTRA; + break; + case DEFAULT: orderType1 = OrderType.STANDARD; + break; + case RETAIL: orderType1 = OrderType.RETAIL; + break; + case B2B: orderType1 = OrderType.B2B; + break; + default: throw new CustomIllegalArgumentException( "Unexpected enum constant: " + orderType ); + } + + return orderType1; + } +} diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/spi/CustomCheeseMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/spi/CustomCheeseMapperImpl.java index 9798c4159..b2ba34a32 100644 --- a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/spi/CustomCheeseMapperImpl.java +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/value/spi/CustomCheeseMapperImpl.java @@ -6,6 +6,7 @@ package org.mapstruct.ap.test.value.spi; import javax.annotation.processing.Generated; +import org.mapstruct.ap.test.value.CustomIllegalArgumentException; @Generated( value = "org.mapstruct.ap.MappingProcessor", @@ -31,7 +32,7 @@ public class CustomCheeseMapperImpl implements CustomCheeseMapper { break; case UNRECOGNIZED: cheeseType = null; break; - default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheese ); + default: throw new CustomIllegalArgumentException( "Unexpected enum constant: " + cheese ); } return cheeseType; @@ -50,7 +51,7 @@ public class CustomCheeseMapperImpl implements CustomCheeseMapper { break; case ROQUEFORT: customCheeseType = CustomCheeseType.CUSTOM_ROQUEFORT; break; - default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheese ); + default: throw new CustomIllegalArgumentException( "Unexpected enum constant: " + cheese ); } return customCheeseType; @@ -73,7 +74,7 @@ public class CustomCheeseMapperImpl implements CustomCheeseMapper { break; case UNRECOGNIZED: string = null; break; - default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheeseType ); + default: throw new CustomIllegalArgumentException( "Unexpected enum constant: " + cheeseType ); } return string;