#2445 Improve error reporting when EnumTransformationStrategy throws an error during transformation

This commit is contained in:
Filip Hrisafov 2021-05-15 11:37:27 +02:00
parent fdf3dcc8ef
commit 4576103752
5 changed files with 69 additions and 4 deletions

View File

@ -56,6 +56,7 @@ public class ValueMappingMethod extends MappingMethod {
private ValueMappings valueMappings; private ValueMappings valueMappings;
private EnumMappingOptions enumMapping; private EnumMappingOptions enumMapping;
private EnumTransformationStrategyInvoker enumTransformationInvoker; private EnumTransformationStrategyInvoker enumTransformationInvoker;
private boolean enumTransformationIllegalReported = false;
public Builder mappingContext(MappingBuilderContext mappingContext) { public Builder mappingContext(MappingBuilderContext mappingContext) {
this.ctx = mappingContext; this.ctx = mappingContext;
@ -144,6 +145,25 @@ public class ValueMappingMethod extends MappingMethod {
} }
private String transform(String source) {
try {
return enumTransformationInvoker.transform( source );
}
catch ( IllegalArgumentException ex ) {
if ( !enumTransformationIllegalReported ) {
enumTransformationIllegalReported = true;
ctx.getMessager().printMessage(
method.getExecutable(),
enumMapping.getMirror(),
Message.ENUMMAPPING_ILLEGAL_TRANSFORMATION,
enumTransformationInvoker.transformationStrategy.getStrategyName(),
ex.getMessage()
);
}
return source;
}
}
private List<MappingEntry> enumToEnumMapping(Method method, Type sourceType, Type targetType ) { private List<MappingEntry> enumToEnumMapping(Method method, Type sourceType, Type targetType ) {
List<MappingEntry> mappings = new ArrayList<>(); List<MappingEntry> mappings = new ArrayList<>();
@ -175,7 +195,7 @@ public class ValueMappingMethod extends MappingMethod {
if ( enumMappingInverse ) { if ( enumMappingInverse ) {
// If the mapping is inverse we have to change the target enum constant // If the mapping is inverse we have to change the target enum constant
targetConstants.put( targetConstants.put(
enumTransformationInvoker.transform( targetNameEnum ), transform( targetNameEnum ),
targetEnumConstant targetEnumConstant
); );
} }
@ -189,7 +209,7 @@ public class ValueMappingMethod extends MappingMethod {
String sourceNameConstant = getEnumConstant( sourceTypeElement, sourceConstant ); String sourceNameConstant = getEnumConstant( sourceTypeElement, sourceConstant );
String targetConstant; String targetConstant;
if ( !enumMappingInverse ) { if ( !enumMappingInverse ) {
targetConstant = enumTransformationInvoker.transform( sourceNameConstant ); targetConstant = transform( sourceNameConstant );
} }
else { else {
targetConstant = sourceNameConstant; targetConstant = sourceNameConstant;
@ -251,7 +271,7 @@ public class ValueMappingMethod extends MappingMethod {
// all remaining constants are mapped // all remaining constants are mapped
for ( String sourceConstant : unmappedSourceConstants ) { for ( String sourceConstant : unmappedSourceConstants ) {
String sourceNameConstant = getEnumConstant( sourceTypeElement, sourceConstant ); String sourceNameConstant = getEnumConstant( sourceTypeElement, sourceConstant );
String targetConstant = enumTransformationInvoker.transform( sourceNameConstant ); String targetConstant = transform( sourceNameConstant );
mappings.add( new MappingEntry( sourceConstant, targetConstant ) ); mappings.add( new MappingEntry( sourceConstant, targetConstant ) );
} }
} }
@ -283,7 +303,7 @@ public class ValueMappingMethod extends MappingMethod {
// all remaining constants are mapped // all remaining constants are mapped
for ( String sourceConstant : unmappedSourceConstants ) { for ( String sourceConstant : unmappedSourceConstants ) {
String sourceNameConstant = getEnumConstant( targetTypeElement, sourceConstant ); String sourceNameConstant = getEnumConstant( targetTypeElement, sourceConstant );
String stringConstant = enumTransformationInvoker.transform( sourceNameConstant ); String stringConstant = transform( sourceNameConstant );
if ( !mappedSources.contains( stringConstant ) ) { if ( !mappedSources.contains( stringConstant ) ) {
mappings.add( new MappingEntry( stringConstant, sourceConstant ) ); mappings.add( new MappingEntry( stringConstant, sourceConstant ) );
} }

View File

@ -6,6 +6,8 @@
package org.mapstruct.ap.internal.model.source; package org.mapstruct.ap.internal.model.source;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
@ -64,6 +66,10 @@ public class EnumMappingOptions extends DelegatingOptions {
return next().getUnexpectedValueMappingException(); return next().getUnexpectedValueMappingException();
} }
public AnnotationMirror getMirror() {
return Optional.ofNullable( enumMapping ).map( EnumMappingGem::mirror ).orElse( null );
}
public boolean isInverse() { public boolean isInverse() {
return inverse; return inverse;
} }

View File

@ -110,6 +110,7 @@ public enum Message {
ENUMMAPPING_INCORRECT_TRANSFORMATION_STRATEGY( "There is no registered EnumTransformationStrategy for '%s'. Registered strategies are: %s." ), 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_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." ), ENUMMAPPING_NO_ELEMENTS( "'nameTransformationStrategy', 'configuration' and 'unexpectedValueMappingException' are undefined in @EnumMapping, define at least one of them." ),
ENUMMAPPING_ILLEGAL_TRANSFORMATION( "Illegal transformation for '%s' EnumTransformationStrategy. Error: '%s'." ),
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), 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),

View File

@ -101,6 +101,24 @@ public class EnumNameTransformationStrategyTest {
public void shouldGiveCompileErrorWhenUsingUnknownNameTransformStrategy() { public void shouldGiveCompileErrorWhenUsingUnknownNameTransformStrategy() {
} }
@ProcessorTest
@WithClasses({
ErroneousCaseTransformStrategyMapper.class
})
@ExpectedCompilationOutcome(value = CompilationResult.FAILED,
diagnostics = {
@Diagnostic(
type = ErroneousCaseTransformStrategyMapper.class,
kind = javax.tools.Diagnostic.Kind.ERROR,
line = 18,
message = "Illegal transformation for 'case' EnumTransformationStrategy." +
" Error: 'Unexpected configuration for enum case transformation: unknown'."
)
}
)
public void shouldGiveCompileErrorWhenUsingUnknownConfigurationForCaseTransformStrategy() {
}
@ProcessorTest @ProcessorTest
@WithClasses({ @WithClasses({
ErroneousNameTransformStrategyMapper.class ErroneousNameTransformStrategyMapper.class

View File

@ -0,0 +1,20 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.value.nametransformation;
import org.mapstruct.EnumMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;
/**
* @author Filip Hrisafov
*/
@Mapper
public interface ErroneousCaseTransformStrategyMapper {
@EnumMapping(nameTransformationStrategy = MappingConstants.CASE_TRANSFORMATION, configuration = "unknown")
CheeseType map(CheeseType cheese);
}