#2339 Support throwing an exception as an Enum Mapping option

This commit is contained in:
jude.niroshan11@gmail.com 2021-02-19 23:06:42 +01:00 committed by Filip Hrisafov
parent 228660c74f
commit c4135e68ed
15 changed files with 368 additions and 42 deletions

View File

@ -36,6 +36,14 @@ public final class MappingConstants {
*/ */
public static final String ANY_UNMAPPED = "<ANY_UNMAPPED>"; public static final String ANY_UNMAPPED = "<ANY_UNMAPPED>";
/**
* In an {@link ValueMapping} this represents any target that will be mapped to an
* {@link java.lang.IllegalArgumentException} which will be thrown at runtime.
* <p>
* NOTE: The value is only applicable to {@link ValueMapping#target()} and not to {@link ValueMapping#source()}.
*/
public static final String THROW_EXCEPTION = "<THROW_EXCEPTION>";
/** /**
* In an {@link EnumMapping} this represent the enum transformation strategy that adds a suffix to the source enum. * In an {@link EnumMapping} this represent the enum transformation strategy that adds a suffix to the source enum.
* *

View File

@ -23,7 +23,8 @@ import java.lang.annotation.Target;
* *
* <pre> * <pre>
* <code> * <code>
* public enum OrderType { RETAIL, B2B, EXTRA, STANDARD, NORMAL } *
* public enum OrderType { RETAIL, B2B, C2C, EXTRA, STANDARD, NORMAL }
* *
* public enum ExternalOrderType { RETAIL, B2B, SPECIAL, DEFAULT } * public enum ExternalOrderType { RETAIL, B2B, SPECIAL, DEFAULT }
* *
@ -45,13 +46,12 @@ import java.lang.annotation.Target;
* +---------------------+----------------------------+ * +---------------------+----------------------------+
* </pre> * </pre>
* *
* MapStruct will <B>WARN</B> on incomplete mappings. However, if for some reason no match is found an
* {@link java.lang.IllegalStateException} will be thrown.
* <p> * <p>
* <B>Example 2:</B> * <B>Example 2:</B>
* *
* <pre> * <pre>
* <code> * <code>
*
* &#64;ValueMapping( source = MappingConstants.NULL, target = "DEFAULT" ), * &#64;ValueMapping( source = MappingConstants.NULL, target = "DEFAULT" ),
* &#64;ValueMapping( source = "STANDARD", target = MappingConstants.NULL ), * &#64;ValueMapping( source = "STANDARD", target = MappingConstants.NULL ),
* &#64;ValueMapping( source = MappingConstants.ANY_REMAINING, target = "SPECIAL" ) * &#64;ValueMapping( source = MappingConstants.ANY_REMAINING, target = "SPECIAL" )
@ -70,6 +70,26 @@ import java.lang.annotation.Target;
* +---------------------+----------------------------+ * +---------------------+----------------------------+
* </pre> * </pre>
* *
* <p>
* <B>Example 3:</B>
* </p>
*
* <p></p>MapStruct will <B>WARN</B> on incomplete mappings. However, if for some reason no match is found, an
* {@link java.lang.IllegalStateException} will be thrown. This compile-time error can be avoided by
* using {@link MappingConstants#THROW_EXCEPTION} for {@link ValueMapping#target()}. It will result an
* {@link java.lang.IllegalArgumentException} at runtime.
* <pre>
* <code>
*
* &#64;ValueMapping( source = "STANDARD", target = "DEFAULT" ),
* &#64;ValueMapping( source = "C2C", target = MappingConstants.THROW_EXCEPTION )
* ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
* </code>
* Mapping result:
* {@link java.lang.IllegalArgumentException} with the error message:
* Unexpected enum constant: C2C
* </pre>
*
* @author Sjaak Derksen * @author Sjaak Derksen
*/ */
@Repeatable(ValueMappings.class) @Repeatable(ValueMappings.class)
@ -104,6 +124,7 @@ public @interface ValueMapping {
* <ol> * <ol>
* <li>enum constant name</li> * <li>enum constant name</li>
* <li>{@link MappingConstants#NULL}</li> * <li>{@link MappingConstants#NULL}</li>
* <li>{@link MappingConstants#THROW_EXCEPTION}</li>
* </ol> * </ol>
* *
* @return The target value. * @return The target value.

View File

@ -21,6 +21,8 @@ public final class MappingConstantsGem {
public static final String ANY_UNMAPPED = "<ANY_UNMAPPED>"; public static final String ANY_UNMAPPED = "<ANY_UNMAPPED>";
public static final String THROW_EXCEPTION = "<THROW_EXCEPTION>";
public static final String SUFFIX_TRANSFORMATION = "suffix"; public static final String SUFFIX_TRANSFORMATION = "suffix";
public static final String STRIP_SUFFIX_TRANSFORMATION = "stripSuffix"; public static final String STRIP_SUFFIX_TRANSFORMATION = "stripSuffix";

View File

@ -14,7 +14,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.internal.gem.BeanMappingGem; import org.mapstruct.ap.internal.gem.BeanMappingGem;
import org.mapstruct.ap.internal.model.common.Parameter; import org.mapstruct.ap.internal.model.common.Parameter;
@ -25,11 +24,13 @@ import org.mapstruct.ap.internal.model.source.SelectionParameters;
import org.mapstruct.ap.internal.model.source.ValueMappingOptions; import org.mapstruct.ap.internal.model.source.ValueMappingOptions;
import org.mapstruct.ap.internal.util.Message; import org.mapstruct.ap.internal.util.Message;
import org.mapstruct.ap.internal.util.Strings; import org.mapstruct.ap.internal.util.Strings;
import org.mapstruct.ap.internal.util.TypeUtils;
import org.mapstruct.ap.spi.EnumTransformationStrategy; import org.mapstruct.ap.spi.EnumTransformationStrategy;
import static org.mapstruct.ap.internal.gem.MappingConstantsGem.ANY_REMAINING; import static org.mapstruct.ap.internal.gem.MappingConstantsGem.ANY_REMAINING;
import static org.mapstruct.ap.internal.gem.MappingConstantsGem.ANY_UNMAPPED; import static org.mapstruct.ap.internal.gem.MappingConstantsGem.ANY_UNMAPPED;
import static org.mapstruct.ap.internal.gem.MappingConstantsGem.NULL; import static org.mapstruct.ap.internal.gem.MappingConstantsGem.NULL;
import static org.mapstruct.ap.internal.gem.MappingConstantsGem.THROW_EXCEPTION;
import static org.mapstruct.ap.internal.util.Collections.first; import static org.mapstruct.ap.internal.util.Collections.first;
/** /**
@ -43,6 +44,8 @@ public class ValueMappingMethod extends MappingMethod {
private final List<MappingEntry> valueMappings; private final List<MappingEntry> valueMappings;
private final String defaultTarget; private final String defaultTarget;
private final String nullTarget; private final String nullTarget;
private boolean nullAsException;
private boolean defaultAsException;
private final Type unexpectedValueMappingException; private final Type unexpectedValueMappingException;
@ -119,10 +122,12 @@ public class ValueMappingMethod extends MappingMethod {
return new ValueMappingMethod( method, return new ValueMappingMethod( method,
mappingEntries, mappingEntries,
valueMappings.nullValueTarget, valueMappings.nullValueTarget,
valueMappings.hasNullValueAsException,
valueMappings.defaultTargetValue, valueMappings.defaultTargetValue,
determineUnexpectedValueMappingException(), determineUnexpectedValueMappingException(),
beforeMappingMethods, beforeMappingMethods,
afterMappingMethods afterMappingMethods,
determineExceptionMappingForDefaultCase()
); );
} }
@ -313,7 +318,17 @@ public class ValueMappingMethod extends MappingMethod {
for ( ValueMappingOptions mappedConstant : valueMappings.regularValueMappings ) { for ( ValueMappingOptions mappedConstant : valueMappings.regularValueMappings ) {
if ( !sourceEnumConstants.contains( mappedConstant.getSource() ) ) { if ( !enumMapping.isInverse() && THROW_EXCEPTION.equals( mappedConstant.getSource() ) ) {
ctx.getMessager().printMessage(
method.getExecutable(),
mappedConstant.getMirror(),
mappedConstant.getSourceAnnotationValue(),
Message.VALUEMAPPING_THROW_EXCEPTION_SOURCE
);
foundIncorrectMapping = true;
}
else if ( !sourceEnumConstants.contains( mappedConstant.getSource() ) ) {
ctx.getMessager().printMessage( ctx.getMessager().printMessage(
method.getExecutable(), method.getExecutable(),
mappedConstant.getMirror(), mappedConstant.getMirror(),
@ -361,6 +376,7 @@ public class ValueMappingMethod extends MappingMethod {
for ( ValueMappingOptions mappedConstant : valueMappings.regularValueMappings ) { for ( ValueMappingOptions mappedConstant : valueMappings.regularValueMappings ) {
if ( !NULL.equals( mappedConstant.getTarget() ) if ( !NULL.equals( mappedConstant.getTarget() )
&& !THROW_EXCEPTION.equals( mappedConstant.getTarget() )
&& !targetEnumConstants.contains( mappedConstant.getTarget() ) ) { && !targetEnumConstants.contains( mappedConstant.getTarget() ) ) {
ctx.getMessager().printMessage( ctx.getMessager().printMessage(
method.getExecutable(), method.getExecutable(),
@ -374,7 +390,9 @@ public class ValueMappingMethod extends MappingMethod {
} }
} }
if ( valueMappings.defaultTarget != null && !NULL.equals( valueMappings.defaultTarget.getTarget() ) if ( valueMappings.defaultTarget != null
&& !THROW_EXCEPTION.equals( valueMappings.defaultTarget.getTarget() )
&& !NULL.equals( valueMappings.defaultTarget.getTarget() )
&& !targetEnumConstants.contains( valueMappings.defaultTarget.getTarget() ) ) { && !targetEnumConstants.contains( valueMappings.defaultTarget.getTarget() ) ) {
ctx.getMessager().printMessage( ctx.getMessager().printMessage(
method.getExecutable(), method.getExecutable(),
@ -415,7 +433,9 @@ public class ValueMappingMethod extends MappingMethod {
} }
private Type determineUnexpectedValueMappingException() { private Type determineUnexpectedValueMappingException() {
if ( !valueMappings.hasDefaultValue ) { boolean noDefaultValueForSwitchCase = !valueMappings.hasDefaultValue;
if ( noDefaultValueForSwitchCase || valueMappings.hasAtLeastOneExceptionValue
|| valueMappings.hasNullValueAsException ) {
TypeMirror unexpectedValueMappingException = enumMapping.getUnexpectedValueMappingException(); TypeMirror unexpectedValueMappingException = enumMapping.getUnexpectedValueMappingException();
if ( unexpectedValueMappingException != null ) { if ( unexpectedValueMappingException != null ) {
return ctx.getTypeFactory().getType( unexpectedValueMappingException ); return ctx.getTypeFactory().getType( unexpectedValueMappingException );
@ -427,6 +447,15 @@ public class ValueMappingMethod extends MappingMethod {
return null; return null;
} }
private boolean determineExceptionMappingForDefaultCase() {
if ( valueMappings.hasDefaultValue ) {
return THROW_EXCEPTION.equals( valueMappings.defaultTargetValue );
}
else {
return true;
}
}
} }
private static class EnumTransformationStrategyInvoker { private static class EnumTransformationStrategyInvoker {
@ -464,7 +493,8 @@ public class ValueMappingMethod extends MappingMethod {
boolean hasMapAnyUnmapped = false; boolean hasMapAnyUnmapped = false;
boolean hasMapAnyRemaining = false; boolean hasMapAnyRemaining = false;
boolean hasDefaultValue = false; boolean hasDefaultValue = false;
boolean hasNullValue = false; boolean hasNullValueAsException = false;
boolean hasAtLeastOneExceptionValue = false;
ValueMappings(List<ValueMappingOptions> valueMappings) { ValueMappings(List<ValueMappingOptions> valueMappings) {
@ -484,11 +514,17 @@ public class ValueMappingMethod extends MappingMethod {
else if ( NULL.equals( valueMapping.getSource() ) ) { else if ( NULL.equals( valueMapping.getSource() ) ) {
nullTarget = valueMapping; nullTarget = valueMapping;
nullValueTarget = getValue( nullTarget ); nullValueTarget = getValue( nullTarget );
hasNullValue = true; if ( THROW_EXCEPTION.equals( nullValueTarget ) ) {
hasNullValueAsException = true;
}
} }
else { else {
regularValueMappings.add( valueMapping ); regularValueMappings.add( valueMapping );
} }
if ( THROW_EXCEPTION.equals( valueMapping.getTarget() ) ) {
hasAtLeastOneExceptionValue = true;
}
} }
} }
@ -497,14 +533,20 @@ public class ValueMappingMethod extends MappingMethod {
} }
} }
private ValueMappingMethod(Method method, List<MappingEntry> enumMappings, String nullTarget, String defaultTarget, private ValueMappingMethod(Method method,
List<MappingEntry> enumMappings,
String nullTarget,
boolean hasNullTargetAsException,
String defaultTarget,
Type unexpectedValueMappingException, Type unexpectedValueMappingException,
List<LifecycleCallbackMethodReference> beforeMappingMethods, List<LifecycleCallbackMethodReference> beforeMappingMethods,
List<LifecycleCallbackMethodReference> afterMappingMethods) { List<LifecycleCallbackMethodReference> afterMappingMethods, boolean defaultAsException) {
super( method, beforeMappingMethods, afterMappingMethods ); super( method, beforeMappingMethods, afterMappingMethods );
this.valueMappings = enumMappings; this.valueMappings = enumMappings;
this.nullTarget = nullTarget; this.nullTarget = nullTarget;
this.nullAsException = hasNullTargetAsException;
this.defaultTarget = defaultTarget; this.defaultTarget = defaultTarget;
this.defaultAsException = defaultAsException;
this.unexpectedValueMappingException = unexpectedValueMappingException; this.unexpectedValueMappingException = unexpectedValueMappingException;
this.overridden = method.overridesMethod(); this.overridden = method.overridesMethod();
} }
@ -532,10 +574,18 @@ public class ValueMappingMethod extends MappingMethod {
return nullTarget; return nullTarget;
} }
public boolean isNullAsException() {
return nullAsException;
}
public Type getUnexpectedValueMappingException() { public Type getUnexpectedValueMappingException() {
return unexpectedValueMappingException; return unexpectedValueMappingException;
} }
public boolean isDefaultAsException() {
return defaultAsException;
}
public Parameter getSourceParameter() { public Parameter getSourceParameter() {
return first( getSourceParameters() ); return first( getSourceParameters() );
} }
@ -547,17 +597,25 @@ public class ValueMappingMethod extends MappingMethod {
public static class MappingEntry { public static class MappingEntry {
private final String source; private final String source;
private final String target; private final String target;
private boolean targetAsException = false;
MappingEntry(String source, String target) { MappingEntry(String source, String target) {
this.source = source; this.source = source;
if ( !NULL.equals( target ) ) { if ( !NULL.equals( target ) ) {
this.target = target; this.target = target;
if ( THROW_EXCEPTION.equals( target ) ) {
this.targetAsException = true;
}
} }
else { else {
this.target = null; this.target = null;
} }
} }
public boolean isTargetAsException() {
return targetAsException;
}
public String getSource() { public String getSource() {
return source; return source;
} }

View File

@ -18,6 +18,7 @@ import org.mapstruct.ap.internal.util.Message;
import static org.mapstruct.ap.internal.gem.MappingConstantsGem.ANY_REMAINING; import static org.mapstruct.ap.internal.gem.MappingConstantsGem.ANY_REMAINING;
import static org.mapstruct.ap.internal.gem.MappingConstantsGem.ANY_UNMAPPED; import static org.mapstruct.ap.internal.gem.MappingConstantsGem.ANY_UNMAPPED;
import static org.mapstruct.ap.internal.gem.MappingConstantsGem.THROW_EXCEPTION;
/** /**
* Represents the mapping between one value constant and another. * Represents the mapping between one value constant and another.
@ -112,7 +113,7 @@ public class ValueMappingOptions {
public ValueMappingOptions inverse() { public ValueMappingOptions inverse() {
ValueMappingOptions result; ValueMappingOptions result;
if ( !(ANY_REMAINING.equals( source ) || ANY_UNMAPPED.equals( source ) ) ) { if ( !(ANY_REMAINING.equals( source ) || ANY_UNMAPPED.equals( source ) || THROW_EXCEPTION.equals( target ) ) ) {
result = new ValueMappingOptions( result = new ValueMappingOptions(
target, target,
source, source,

View File

@ -175,7 +175,8 @@ public enum Message {
VALUEMAPPING_ANY_REMAINING_FOR_NON_ENUM( "Source = \"<ANY_REMAINING>\" can only be used on targets of type enum and not for %s." ), VALUEMAPPING_ANY_REMAINING_FOR_NON_ENUM( "Source = \"<ANY_REMAINING>\" can only be used on targets of type enum and not for %s." ),
VALUEMAPPING_ANY_REMAINING_OR_UNMAPPED_MISSING( "Source = \"<ANY_REMAINING>\" or \"<ANY_UNMAPPED>\" is advisable for mapping of type String to an enum type.", Diagnostic.Kind.WARNING ), VALUEMAPPING_ANY_REMAINING_OR_UNMAPPED_MISSING( "Source = \"<ANY_REMAINING>\" or \"<ANY_UNMAPPED>\" 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 EnumMappingStrategy: %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." ); VALUEMAPPING_NON_EXISTING_CONSTANT( "Constant %s doesn't exist in enum type %s." ),
VALUEMAPPING_THROW_EXCEPTION_SOURCE( "Source = \"<THROW_EXCEPTION>\" is not allowed. Target = \"<THROW_EXCEPTION>\" can only be used." );
// CHECKSTYLE:ON // CHECKSTYLE:ON

View File

@ -15,17 +15,17 @@
</#if> </#if>
</#list> </#list>
if ( ${sourceParameter.name} == null ) { if ( ${sourceParameter.name} == null ) {
return <@writeTarget target=nullTarget/>; <#if nullAsException >throw new <@includeModel object=unexpectedValueMappingException />( "Unexpected enum constant: " + ${sourceParameter.name} );<#else>return <@writeTarget target=nullTarget/>;</#if>
} }
<@includeModel object=resultType/> ${resultName}; <@includeModel object=resultType/> ${resultName};
switch ( ${sourceParameter.name} ) { switch ( ${sourceParameter.name} ) {
<#list valueMappings as valueMapping> <#list valueMappings as valueMapping>
case <@writeSource source=valueMapping.source/>: ${resultName} = <@writeTarget target=valueMapping.target/>; case <@writeSource source=valueMapping.source/>: <#if valueMapping.targetAsException >throw new <@includeModel object=unexpectedValueMappingException />( "Unexpected enum constant: " + ${sourceParameter.name} );<#else>${resultName} = <@writeTarget target=valueMapping.target/>;
break; break;</#if>
</#list> </#list>
default: <#if unexpectedValueMappingException??>throw new <@includeModel object=unexpectedValueMappingException />( "Unexpected enum constant: " + ${sourceParameter.name} )<#else>${resultName} = <@writeTarget target=defaultTarget/></#if>; default: <#if defaultAsException >throw new <@includeModel object=unexpectedValueMappingException />( "Unexpected enum constant: " + ${sourceParameter.name} )<#else>${resultName} = <@writeTarget target=defaultTarget/></#if>;
} }
<#list beforeMappingReferencesWithMappingTarget as callback> <#list beforeMappingReferencesWithMappingTarget as callback>
<#if callback_index = 0> <#if callback_index = 0>

View File

@ -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.enum2enum;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;
import org.mapstruct.Named;
import org.mapstruct.ValueMapping;
import org.mapstruct.ap.test.value.ExternalOrderType;
import org.mapstruct.ap.test.value.OrderType;
import org.mapstruct.factory.Mappers;
/**
* @author Jude Niroshan
*/
@Mapper
public interface DefaultOrderThrowExceptionMapper {
DefaultOrderThrowExceptionMapper INSTANCE = Mappers.getMapper( DefaultOrderThrowExceptionMapper.class );
@Named("orderTypeToExternalOrderTypeAnyUnmappedToException")
@ValueMapping(source = MappingConstants.ANY_UNMAPPED, target = MappingConstants.THROW_EXCEPTION)
ExternalOrderType orderTypeToExternalOrderTypeAnyUnmappedToException(OrderType orderType);
}

View File

@ -5,8 +5,6 @@
*/ */
package org.mapstruct.ap.test.value.enum2enum; package org.mapstruct.ap.test.value.enum2enum;
import static org.assertj.core.api.Assertions.assertThat;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
import org.junit.Rule; import org.junit.Rule;
@ -22,14 +20,18 @@ import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutco
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
import org.mapstruct.ap.testutil.runner.GeneratedSource; import org.mapstruct.ap.testutil.runner.GeneratedSource;
import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Test for the generation and invocation of enum mapping methods. * Test for the generation and invocation of enum mapping methods.
* *
* @author Gunnar Morling, Sjaak Derksen * @author Gunnar Morling, Sjaak Derksen
*/ */
@IssueKey("128") @IssueKey("128")
@WithClasses({ OrderMapper.class, SpecialOrderMapper.class, DefaultOrderMapper.class, OrderEntity.class, @WithClasses({
OrderType.class, OrderDto.class, ExternalOrderType.class }) OrderMapper.class, SpecialOrderMapper.class, DefaultOrderMapper.class, OrderEntity.class,
OrderType.class, OrderDto.class, ExternalOrderType.class
})
@RunWith(AnnotationProcessorTestRunner.class) @RunWith(AnnotationProcessorTestRunner.class)
public class EnumToEnumMappingTest { public class EnumToEnumMappingTest {

View File

@ -0,0 +1,93 @@
/*
* 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.enum2enum;
import org.junit.Test;
import org.junit.runner.RunWith;
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;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* @author Jude Niroshan
*/
@IssueKey("2339")
@WithClasses({
OrderEntity.class,
OrderType.class, ExternalOrderType.class
})
@RunWith(AnnotationProcessorTestRunner.class)
public class EnumToEnumThrowExceptionMappingTest {
@IssueKey("2339")
@Test
@WithClasses(DefaultOrderThrowExceptionMapper.class)
public void shouldBeAbleToMapAnyUnmappedToThrowException() {
assertThatThrownBy( () ->
DefaultOrderThrowExceptionMapper.INSTANCE
.orderTypeToExternalOrderTypeAnyUnmappedToException( OrderType.EXTRA ) )
.isInstanceOf( IllegalArgumentException.class )
.hasMessage( "Unexpected enum constant: EXTRA" );
}
@IssueKey("2339")
@Test
@WithClasses({ DefaultOrderThrowExceptionMapper.class, ErroneousOrderMapperThrowExceptionAsSourceType.class })
@ExpectedCompilationOutcome(
value = CompilationResult.FAILED,
diagnostics = {
@Diagnostic(type = ErroneousOrderMapperThrowExceptionAsSourceType.class,
kind = javax.tools.Diagnostic.Kind.ERROR,
line = 29,
message = "Source = \"<THROW_EXCEPTION>\" is not allowed. " +
"Target = \"<THROW_EXCEPTION>\" can only be used.")
}
)
public void shouldRaiseErrorWhenThrowExceptionUsedAsSourceType() {
}
@IssueKey("2339")
@Test
@WithClasses({OrderThrowExceptionMapper.class, OrderDto.class})
public void shouldIgnoreThrowExceptionWhenInverseValueMappings() {
OrderType target = OrderThrowExceptionMapper.INSTANCE.externalOrderTypeToOrderType( ExternalOrderType.B2B );
assertThat( target ).isEqualTo( OrderType.B2B );
}
@IssueKey("2339")
@Test
@WithClasses({SpecialThrowExceptionMapper.class, OrderDto.class})
public void shouldBeAbleToMapAnyRemainingToThrowException() {
assertThatThrownBy( () ->
SpecialThrowExceptionMapper.INSTANCE
.orderTypeToExternalOrderType( OrderType.EXTRA ) )
.isInstanceOf( IllegalArgumentException.class )
.hasMessage( "Unexpected enum constant: EXTRA" );
}
@IssueKey("2339")
@Test
@WithClasses({SpecialThrowExceptionMapper.class, OrderDto.class})
public void shouldBeAbleToMapNullToThrowException() {
assertThatThrownBy( () ->
SpecialThrowExceptionMapper.INSTANCE
.anyRemainingToNullToException( null ) )
.isInstanceOf( IllegalArgumentException.class )
.hasMessage( "Unexpected enum constant: null" );
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.enum2enum;
import org.mapstruct.Mapper;
import org.mapstruct.ValueMapping;
import org.mapstruct.ValueMappings;
import org.mapstruct.ap.test.value.ExternalOrderType;
import org.mapstruct.ap.test.value.OrderType;
import org.mapstruct.factory.Mappers;
/**
* @author Jude Niroshan
*/
@Mapper
public interface ErroneousOrderMapperThrowExceptionAsSourceType {
ErroneousOrderMapperThrowExceptionAsSourceType INSTANCE = Mappers.getMapper(
ErroneousOrderMapperThrowExceptionAsSourceType.class );
@ValueMappings({
@ValueMapping(source = "EXTRA", target = "SPECIAL"),
@ValueMapping(source = "STANDARD", target = "DEFAULT"),
@ValueMapping(source = "NORMAL", target = "DEFAULT"),
@ValueMapping(source = "<ANY_REMAINING>", target = "DEFAULT"),
@ValueMapping(source = "<THROW_EXCEPTION>", target = "DEFAULT")
})
ExternalOrderType orderTypeToExternalOrderTypeWithErroneousSourceMapping(OrderType orderType);
}

View File

@ -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.enum2enum;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;
import org.mapstruct.ValueMapping;
import org.mapstruct.ValueMappings;
import org.mapstruct.ap.test.value.ExternalOrderType;
import org.mapstruct.ap.test.value.OrderType;
import org.mapstruct.factory.Mappers;
/**
* @author Jude Niroshan
*/
@Mapper
public interface OrderThrowExceptionMapper {
OrderThrowExceptionMapper INSTANCE = Mappers.getMapper( OrderThrowExceptionMapper.class );
OrderDto orderEntityToDto(OrderEntity order);
@ValueMappings({
@ValueMapping(source = "EXTRA", target = "SPECIAL"),
@ValueMapping(source = "STANDARD", target = "DEFAULT"),
@ValueMapping(source = "NORMAL", target = MappingConstants.THROW_EXCEPTION)
})
ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
@InheritInverseConfiguration
OrderType externalOrderTypeToOrderType(ExternalOrderType orderType);
}

View File

@ -0,0 +1,47 @@
/*
* 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.enum2enum;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingConstants;
import org.mapstruct.Named;
import org.mapstruct.ValueMapping;
import org.mapstruct.ValueMappings;
import org.mapstruct.ap.test.value.ExternalOrderType;
import org.mapstruct.ap.test.value.OrderType;
import org.mapstruct.factory.Mappers;
/**
* @author Jude Niroshan
*/
@Mapper
public interface SpecialThrowExceptionMapper {
SpecialThrowExceptionMapper INSTANCE = Mappers.getMapper( SpecialThrowExceptionMapper.class );
@Mapping(target = "orderType", source = "orderType", qualifiedByName = "orderTypeToExternalOrderType")
OrderDto orderEntityToDto(OrderEntity order);
@Named("orderTypeToExternalOrderType")
@ValueMappings({
@ValueMapping(source = MappingConstants.NULL, target = "DEFAULT"),
@ValueMapping(source = "STANDARD", target = MappingConstants.NULL),
@ValueMapping(source = MappingConstants.ANY_REMAINING, target = MappingConstants.THROW_EXCEPTION)
})
ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
@InheritInverseConfiguration(name = "orderTypeToExternalOrderType")
@ValueMapping(target = "EXTRA", source = "SPECIAL")
OrderType externalOrderTypeToOrderType(ExternalOrderType orderType);
@ValueMappings({
@ValueMapping(source = MappingConstants.NULL, target = MappingConstants.THROW_EXCEPTION),
@ValueMapping(source = "STANDARD", target = MappingConstants.NULL),
@ValueMapping(source = MappingConstants.ANY_REMAINING, target = MappingConstants.NULL)
})
ExternalOrderType anyRemainingToNullToException(OrderType orderType);
}

View File

@ -11,8 +11,8 @@ import org.mapstruct.ap.test.value.OrderType;
@Generated( @Generated(
value = "org.mapstruct.ap.MappingProcessor", value = "org.mapstruct.ap.MappingProcessor",
date = "2017-02-20T21:25:45+0100", date = "2021-02-19T21:20:19+0100",
comments = "version: , compiler: javac, environment: Java 1.8.0_112 (Oracle Corporation)" comments = "version: , compiler: javac, environment: Java 1.8.0_191 (Oracle Corporation)"
) )
public class SpecialOrderMapperImpl implements SpecialOrderMapper { public class SpecialOrderMapperImpl implements SpecialOrderMapper {