#2445 Support for case changing enum transformation strategy

Available case transformations: upper, lower, capital
This commit is contained in:
João Paulo Bassinello 2021-05-06 15:13:13 -03:00 committed by Filip Hrisafov
parent 5c22eee6c3
commit fdf3dcc8ef
15 changed files with 252 additions and 2 deletions

View File

@ -104,6 +104,18 @@ public @interface EnumMapping {
* prefix to the source enum</li>
* <li>{@link MappingConstants#STRIP_PREFIX_TRANSFORMATION} - strips the given {@link #configuration()} from
* the start of the source enum</li>
* <li>
* {@link MappingConstants#CASE_TRANSFORMATION} - applies the given {@link #configuration()} case
* transformation to the source enum. Supported configurations are:
* <ul>
* <li><i>upper</i> - Performs upper case transformation to the source enum</li>
* <li><i>lower</i> - Performs lower case transformation to the source enum</li>
* <li>
* <i>capital</i> - Performs capitalisation of the first character of every word in the source enum
* and everything else to lower case. A word is split by "_".
* </li>
* </ul>
* </li>
* </ul>
*
* It is possible to use custom name transformation strategies by implementing the {@code

View File

@ -74,6 +74,14 @@ public final class MappingConstants {
*/
public static final String STRIP_PREFIX_TRANSFORMATION = "stripPrefix";
/**
* In an {@link EnumMapping} this represent the enum transformation strategy that applies case transformation
* at the source.
*
* @since 1.5
*/
public static final String CASE_TRANSFORMATION = "case";
/**
* Specifies the component model constants to which the generated mapper should adhere.
* It can be used with the annotation {@link Mapper#componentModel()} or {@link MapperConfig#componentModel()}

View File

@ -259,6 +259,10 @@ MapStruct provides the following out of the box enum name transformation strateg
* _stripSuffix_ - Strips a suffix from the source enum
* _prefix_ - Applies a prefix on the source enum
* _stripPrefix_ - Strips a prefix from the source enum
* _case_ - Applies case transformation to the source enum. Supported _case_ transformations are:
** _upper_ - Performs upper case transformation to the source enum
** _lower_ - Performs lower case transformation to the source enum
** _capital_ - Performs capitalisation of the first character of every word in the source enum and everything else to lowercase. A word is split by "_"
It is also possible to register custom strategies.
For more information on how to do that have a look at <<custom-enum-transformation-strategy>>

View File

@ -31,6 +31,8 @@ public final class MappingConstantsGem {
public static final String STRIP_PREFIX_TRANSFORMATION = "stripPrefix";
public static final String CASE_TRANSFORMATION = "case";
/**
* Gem for the class {@link org.mapstruct.MappingConstants.ComponentModel}
*

View File

@ -0,0 +1,59 @@
/*
* 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.spi;
import java.util.Arrays;
import java.util.Locale;
import java.util.stream.Collectors;
/**
* Applies case transformation to the source enum
*
* @author jpbassinello
* @since 1.5
*/
public class CaseEnumTransformationStrategy implements EnumTransformationStrategy {
private static final String UPPER = "upper";
private static final String LOWER = "lower";
private static final String CAPITAL = "capital";
@Override
public String getStrategyName() {
return "case";
}
@Override
public String transform(String value, String configuration) {
switch ( configuration.toLowerCase() ) {
case UPPER:
return value.toUpperCase( Locale.ROOT );
case LOWER:
return value.toLowerCase( Locale.ROOT );
case CAPITAL:
return capitalize( value );
default:
throw new IllegalArgumentException(
"Unexpected configuration for enum case transformation: " + configuration );
}
}
private static String capitalize(String value) {
return Arrays.stream( value.split( "_" ) )
.map( CaseEnumTransformationStrategy::upperCaseFirst )
.collect( Collectors.joining( "_" ) );
}
private static String upperCaseFirst(String value) {
char[] array = value.toCharArray();
array[0] = Character.toUpperCase( array[0] );
for ( int i = 1; i < array.length; i++ ) {
array[i] = Character.toLowerCase( array[i] );
}
return new String( array );
}
}

View File

@ -6,3 +6,4 @@ org.mapstruct.ap.spi.PrefixEnumTransformationStrategy
org.mapstruct.ap.spi.StripPrefixEnumTransformationStrategy
org.mapstruct.ap.spi.StripSuffixEnumTransformationStrategy
org.mapstruct.ap.spi.SuffixEnumTransformationStrategy
org.mapstruct.ap.spi.CaseEnumTransformationStrategy

View File

@ -30,6 +30,7 @@ public class ConstantTest {
assertThat( MappingConstants.PREFIX_TRANSFORMATION ).isEqualTo( MappingConstantsGem.PREFIX_TRANSFORMATION );
assertThat( MappingConstants.STRIP_PREFIX_TRANSFORMATION )
.isEqualTo( MappingConstantsGem.STRIP_PREFIX_TRANSFORMATION );
assertThat( MappingConstants.CASE_TRANSFORMATION ).isEqualTo( MappingConstantsGem.CASE_TRANSFORMATION );
}
@Test

View File

@ -0,0 +1,57 @@
/*
* 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.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;
import org.mapstruct.factory.Mappers;
/**
* @author jpbassinello
*/
@Mapper
public interface CheeseCaseMapper {
CheeseCaseMapper INSTANCE = Mappers.getMapper( CheeseCaseMapper.class );
@EnumMapping(nameTransformationStrategy = MappingConstants.CASE_TRANSFORMATION, configuration = "lower")
CheeseTypeLower mapToLower(CheeseType cheese);
@InheritInverseConfiguration
CheeseType mapToLowerInverse(CheeseTypeLower cheese);
@EnumMapping(nameTransformationStrategy = MappingConstants.CASE_TRANSFORMATION, configuration = "lower")
CheeseTypeLower mapToLower(CheeseTypeCapital cheese);
@EnumMapping(nameTransformationStrategy = MappingConstants.CASE_TRANSFORMATION, configuration = "upper")
CheeseType mapToUpper(CheeseTypeLower cheese);
@EnumMapping(nameTransformationStrategy = MappingConstants.CASE_TRANSFORMATION, configuration = "upper")
CheeseType mapToUpper(CheeseTypeCapital cheese);
@InheritInverseConfiguration(name = "mapToUpper")
CheeseTypeCapital mapToUpperInverse(CheeseType cheese);
@EnumMapping(nameTransformationStrategy = MappingConstants.CASE_TRANSFORMATION, configuration = "capital")
CheeseTypeCapital mapToCapital(CheeseTypeLower cheese);
@EnumMapping(nameTransformationStrategy = MappingConstants.CASE_TRANSFORMATION, configuration = "capital")
CheeseTypeCapital mapToCapital(CheeseType cheese);
@InheritInverseConfiguration(name = "mapToCapital")
CheeseType mapToCapitalInverse(CheeseTypeCapital cheese);
@EnumMapping(nameTransformationStrategy = MappingConstants.CASE_TRANSFORMATION, configuration = "lower")
String mapToLowerString(CheeseType cheese);
@EnumMapping(nameTransformationStrategy = MappingConstants.CASE_TRANSFORMATION, configuration = "upper")
String mapToUpperString(CheeseType cheese);
@EnumMapping(nameTransformationStrategy = MappingConstants.CASE_TRANSFORMATION, configuration = "capital")
String mapToCapitalString(CheeseType cheese);
}

View File

@ -11,5 +11,6 @@ package org.mapstruct.ap.test.value.nametransformation;
public enum CheeseType {
BRIE,
ROQUEFORT
ROQUEFORT,
COLBY_JACK
}

View File

@ -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.nametransformation;
/**
* @author jpbassinello
*/
public enum CheeseTypeCapital {
Brie,
Roquefort,
Colby_Jack
}

View File

@ -12,4 +12,5 @@ public enum CheeseTypeCustomSuffix {
brie_TYPE,
roquefort_TYPE,
colby_jack_TYPE
}

View File

@ -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.nametransformation;
/**
* @author jpbassinello
*/
public enum CheeseTypeLower {
brie,
roquefort,
colby_jack
}

View File

@ -13,4 +13,5 @@ public enum CheeseTypePrefixed {
DEFAULT,
SWISS_BRIE,
SWISS_ROQUEFORT,
SWISS_COLBY_JACK
}

View File

@ -13,4 +13,5 @@ public enum CheeseTypeSuffixed {
DEFAULT,
BRIE_CHEESE_TYPE,
ROQUEFORT_CHEESE_TYPE,
COLBY_JACK_CHEESE_TYPE
}

View File

@ -22,6 +22,8 @@ import static org.assertj.core.api.Assertions.assertThat;
CheeseTypeSuffixed.class,
CheeseTypePrefixed.class,
CheeseTypeCustomSuffix.class,
CheeseTypeLower.class,
CheeseTypeCapital.class
})
public class EnumNameTransformationStrategyTest {
@ -92,7 +94,7 @@ public class EnumNameTransformationStrategyTest {
kind = javax.tools.Diagnostic.Kind.ERROR,
line = 20,
message = "There is no registered EnumTransformationStrategy for 'custom'. Registered strategies are:" +
" prefix, stripPrefix, stripSuffix, suffix."
" prefix, stripPrefix, stripSuffix, suffix, case."
)
}
)
@ -109,4 +111,72 @@ public class EnumNameTransformationStrategyTest {
.isEqualTo( CheeseTypeCustomSuffix.brie_TYPE );
}
@ProcessorTest
@WithClasses({
CheeseCaseMapper.class
})
public void shouldConvertCaseOnEnumToEnumMapping() {
CheeseCaseMapper mapper = CheeseCaseMapper.INSTANCE;
assertThat( mapper.mapToLower( CheeseType.BRIE ) )
.isEqualTo( CheeseTypeLower.brie );
assertThat( mapper.mapToLowerInverse( CheeseTypeLower.brie ) )
.isEqualTo( CheeseType.BRIE );
assertThat( mapper.mapToLower( CheeseTypeCapital.Colby_Jack ) )
.isEqualTo( CheeseTypeLower.colby_jack );
assertThat( mapper.mapToUpper( CheeseTypeLower.roquefort ) )
.isEqualTo( CheeseType.ROQUEFORT );
assertThat( mapper.mapToUpper( CheeseTypeCapital.Colby_Jack ) )
.isEqualTo( CheeseType.COLBY_JACK );
assertThat( mapper.mapToUpperInverse( CheeseType.COLBY_JACK ) )
.isEqualTo( CheeseTypeCapital.Colby_Jack );
assertThat( mapper.mapToCapital( CheeseTypeLower.brie ) )
.isEqualTo( CheeseTypeCapital.Brie );
assertThat( mapper.mapToCapital( CheeseType.ROQUEFORT ) )
.isEqualTo( CheeseTypeCapital.Roquefort );
assertThat( mapper.mapToCapital( CheeseType.COLBY_JACK ) )
.isEqualTo( CheeseTypeCapital.Colby_Jack );
assertThat( mapper.mapToCapitalInverse( CheeseTypeCapital.Roquefort ) )
.isEqualTo( CheeseType.ROQUEFORT );
assertThat( mapper.mapToCapitalInverse( CheeseTypeCapital.Colby_Jack ) )
.isEqualTo( CheeseType.COLBY_JACK );
assertThat( mapper.mapToCapital( CheeseTypeLower.colby_jack ) )
.isEqualTo( CheeseTypeCapital.Colby_Jack );
}
@ProcessorTest
@WithClasses({
CheeseCaseMapper.class
})
public void shouldConvertCaseOnEnumToStringMapping() {
CheeseCaseMapper mapper = CheeseCaseMapper.INSTANCE;
assertThat( mapper.mapToLowerString( CheeseType.BRIE ) )
.isEqualTo( "brie" );
assertThat( mapper.mapToLowerString( CheeseType.COLBY_JACK ) )
.isEqualTo( "colby_jack" );
assertThat( mapper.mapToUpperString( CheeseType.ROQUEFORT ) )
.isEqualTo( "ROQUEFORT" );
assertThat( mapper.mapToUpperString( CheeseType.COLBY_JACK ) )
.isEqualTo( "COLBY_JACK" );
assertThat( mapper.mapToCapitalString( CheeseType.ROQUEFORT ) )
.isEqualTo( "Roquefort" );
assertThat( mapper.mapToCapitalString( CheeseType.COLBY_JACK ) )
.isEqualTo( "Colby_Jack" );
}
}