mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
Add EnumNamingStrategy SPI (#2100)
Add a new EnumNamingStrategy SPI which can be used for customising the way enums are matched by name. It is similar to the AccessorNamingStrategy such that it allows implementors to provide a custom way of defining a property. Related to #796, #1220, #1789 and #1667
This commit is contained in:
parent
7b5a54971f
commit
c23592a7fe
@ -199,6 +199,152 @@ 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).
|
||||
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`
|
||||
|
||||
.Normal Enum
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
public enum CheeseType {
|
||||
BRIE,
|
||||
ROQUEFORT;
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
.Custom marker enum
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
public enum CustomCheeseType implements CustomEnumMarker {
|
||||
|
||||
UNSPECIFIED,
|
||||
CUSTOM_BRIE,
|
||||
CUSTOM_ROQUEFORT;
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
We want `CheeseType` and `CustomCheeseType` to be mapped without the need to manually define the value mappings:
|
||||
|
||||
.Custom enum mapping
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
@Mapper
|
||||
public interface CheeseTypeMapper {
|
||||
|
||||
CheeseType map(CustomCheeseType cheese);
|
||||
|
||||
CustomCheeseType map(CheeseType cheese);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
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`:
|
||||
|
||||
.Custom enum naming strategy
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
public class CustomEnumNamingStrategy extends DefaultEnumNamingStrategy {
|
||||
|
||||
@Override
|
||||
public String getDefaultNullEnumConstant(TypeElement enumType) {
|
||||
if ( isCustomEnum( enumType ) ) {
|
||||
return "UNSPECIFIED";
|
||||
}
|
||||
|
||||
return super.getDefaultNullEnumConstant( enumType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnumConstant(TypeElement enumType, String enumConstant) {
|
||||
if ( isCustomEnum( enumType ) ) {
|
||||
return getCustomEnumConstant( enumConstant );
|
||||
}
|
||||
return super.getEnumConstant( enumType, enumConstant );
|
||||
}
|
||||
protected String getCustomEnumConstant(String enumConstant) {
|
||||
if ( "UNSPECIFIED".equals( enumConstant ) ) {
|
||||
return MappingConstantsGem.NULL;
|
||||
}
|
||||
return enumConstant.replace( "CUSTOM_", "" );
|
||||
}
|
||||
protected boolean isCustomEnum(TypeElement enumType) {
|
||||
for ( TypeMirror enumTypeInterface : enumType.getInterfaces() ) {
|
||||
if ( typeUtils.asElement( enumTypeInterface ).getSimpleName().contentEquals( "CustomEnumMarker" ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
The generated code then for the `CheeseMapper` looks like:
|
||||
|
||||
.Generated CheeseTypeMapper
|
||||
====
|
||||
[source, java, linenums]
|
||||
[subs="verbatim,attributes"]
|
||||
----
|
||||
public class CheeseTypeMapperImpl implements CheeseTypeMapper {
|
||||
|
||||
@Override
|
||||
public CheeseType map(CustomCheeseType cheese) {
|
||||
if ( cheese == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CheeseType cheeseType;
|
||||
|
||||
switch ( cheese ) {
|
||||
case UNRECOGNIZED: cheeseType = null;
|
||||
break;
|
||||
case CUSTOM_BRIE: cheeseType = CheeseType.BRIE;
|
||||
break;
|
||||
case CUSTOM_ROQUEFORT: cheeseType = CheeseType.ROQUEFORT;
|
||||
break;
|
||||
default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheese );
|
||||
}
|
||||
|
||||
return cheeseType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomCheeseType map(CheeseType cheese) {
|
||||
if ( cheese == null ) {
|
||||
return CustomCheeseType.UNSPECIFIED;
|
||||
}
|
||||
|
||||
CustomCheeseType customCheeseType;
|
||||
|
||||
switch ( cheese ) {
|
||||
case BRIE: customCheeseType = CustomCheeseType.CUSTOM_BRIE;
|
||||
break;
|
||||
case ROQUEFORT: customCheeseType = CustomCheeseType.CUSTOM_ROQUEFORT;
|
||||
break;
|
||||
default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheese );
|
||||
}
|
||||
|
||||
return customCheeseType;
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[[custom-enum-transformation-strategy]]
|
||||
=== Custom Enum Transformation Strategy
|
||||
|
@ -30,6 +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.EnumTransformationStrategy;
|
||||
import org.mapstruct.ap.spi.MappingExclusionProvider;
|
||||
|
||||
@ -105,6 +106,7 @@ public class MappingBuilderContext {
|
||||
private final Types typeUtils;
|
||||
private final FormattingMessager messager;
|
||||
private final AccessorNamingUtils accessorNaming;
|
||||
private final EnumNamingStrategy enumNamingStrategy;
|
||||
private final Map<String, EnumTransformationStrategy> enumTransformationStrategies;
|
||||
private final Options options;
|
||||
private final TypeElement mapperTypeElement;
|
||||
@ -121,6 +123,7 @@ public class MappingBuilderContext {
|
||||
Types typeUtils,
|
||||
FormattingMessager messager,
|
||||
AccessorNamingUtils accessorNaming,
|
||||
EnumNamingStrategy enumNamingStrategy,
|
||||
Map<String, EnumTransformationStrategy> enumTransformationStrategies,
|
||||
Options options,
|
||||
MappingResolver mappingResolver,
|
||||
@ -132,6 +135,7 @@ public class MappingBuilderContext {
|
||||
this.typeUtils = typeUtils;
|
||||
this.messager = messager;
|
||||
this.accessorNaming = accessorNaming;
|
||||
this.enumNamingStrategy = enumNamingStrategy;
|
||||
this.enumTransformationStrategies = enumTransformationStrategies;
|
||||
this.options = options;
|
||||
this.mappingResolver = mappingResolver;
|
||||
@ -186,6 +190,10 @@ public class MappingBuilderContext {
|
||||
return accessorNaming;
|
||||
}
|
||||
|
||||
public EnumNamingStrategy getEnumNamingStrategy() {
|
||||
return enumNamingStrategy;
|
||||
}
|
||||
|
||||
public Map<String, EnumTransformationStrategy> getEnumTransformationStrategies() {
|
||||
return enumTransformationStrategies;
|
||||
}
|
||||
|
@ -8,9 +8,11 @@ package org.mapstruct.ap.internal.model;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.util.Types;
|
||||
|
||||
@ -86,6 +88,12 @@ public class ValueMappingMethod extends MappingMethod {
|
||||
Type sourceType = first( method.getSourceParameters() ).getType();
|
||||
Type targetType = method.getResultType();
|
||||
|
||||
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()
|
||||
.getDefaultNullEnumConstant( targetType.getTypeElement() );
|
||||
}
|
||||
|
||||
// enum-to-enum
|
||||
if ( sourceType.isEnumType() && targetType.isEnumType() ) {
|
||||
mappingEntries.addAll( enumToEnumMapping( method, sourceType, targetType ) );
|
||||
@ -145,9 +153,7 @@ public class ValueMappingMethod extends MappingMethod {
|
||||
|
||||
// Start to fill the mappings with the defined value mappings
|
||||
for ( ValueMappingOptions valueMapping : valueMappings.regularValueMappings ) {
|
||||
String target =
|
||||
NULL.equals( valueMapping.getTarget() ) ? null : valueMapping.getTarget();
|
||||
mappings.add( new MappingEntry( valueMapping.getSource(), target ) );
|
||||
mappings.add( new MappingEntry( valueMapping.getSource(), valueMapping.getTarget() ) );
|
||||
unmappedSourceConstants.remove( valueMapping.getSource() );
|
||||
}
|
||||
|
||||
@ -160,32 +166,40 @@ public class ValueMappingMethod extends MappingMethod {
|
||||
Map<String, String> targetConstants = new LinkedHashMap<>();
|
||||
|
||||
boolean enumMappingInverse = enumMapping.isInverse();
|
||||
TypeElement targetTypeElement = method.getReturnType().getTypeElement();
|
||||
for ( String targetEnumConstant : method.getReturnType().getEnumConstants() ) {
|
||||
String targetNameEnum = getEnumConstant( targetTypeElement, targetEnumConstant );
|
||||
if ( enumMappingInverse ) {
|
||||
// If the mapping is inverse we have to change the target enum constant
|
||||
targetConstants.put(
|
||||
enumTransformationInvoker.transform( targetEnumConstant ),
|
||||
enumTransformationInvoker.transform( targetNameEnum ),
|
||||
targetEnumConstant
|
||||
);
|
||||
}
|
||||
else {
|
||||
targetConstants.put( targetEnumConstant, targetEnumConstant );
|
||||
targetConstants.put( targetNameEnum, targetEnumConstant );
|
||||
}
|
||||
}
|
||||
|
||||
TypeElement sourceTypeElement = sourceType.getTypeElement();
|
||||
for ( String sourceConstant : new ArrayList<>( unmappedSourceConstants ) ) {
|
||||
String sourceNameConstant = getEnumConstant( sourceTypeElement, sourceConstant );
|
||||
String targetConstant;
|
||||
if ( !enumMappingInverse ) {
|
||||
targetConstant = enumTransformationInvoker.transform( sourceConstant );
|
||||
targetConstant = enumTransformationInvoker.transform( sourceNameConstant );
|
||||
}
|
||||
else {
|
||||
targetConstant = sourceConstant;
|
||||
targetConstant = sourceNameConstant;
|
||||
}
|
||||
|
||||
if ( targetConstants.containsKey( targetConstant ) ) {
|
||||
mappings.add( new MappingEntry( sourceConstant, targetConstants.get( targetConstant ) ) );
|
||||
unmappedSourceConstants.remove( sourceConstant );
|
||||
}
|
||||
else if ( NULL.equals( targetConstant ) ) {
|
||||
mappings.add( new MappingEntry( sourceConstant, null ) );
|
||||
unmappedSourceConstants.remove( sourceConstant );
|
||||
}
|
||||
}
|
||||
|
||||
if ( valueMappings.defaultTarget == null && !unmappedSourceConstants.isEmpty() ) {
|
||||
@ -223,18 +237,18 @@ public class ValueMappingMethod extends MappingMethod {
|
||||
|
||||
// Start to fill the mappings with the defined valuemappings
|
||||
for ( ValueMappingOptions valueMapping : valueMappings.regularValueMappings ) {
|
||||
String target =
|
||||
NULL.equals( valueMapping.getTarget() ) ? null : valueMapping.getTarget();
|
||||
mappings.add( new MappingEntry( valueMapping.getSource(), target ) );
|
||||
mappings.add( new MappingEntry( valueMapping.getSource(), valueMapping.getTarget() ) );
|
||||
unmappedSourceConstants.remove( valueMapping.getSource() );
|
||||
}
|
||||
|
||||
// add mappings based on name
|
||||
if ( !valueMappings.hasMapAnyUnmapped ) {
|
||||
|
||||
TypeElement sourceTypeElement = sourceType.getTypeElement();
|
||||
// all remaining constants are mapped
|
||||
for ( String sourceConstant : unmappedSourceConstants ) {
|
||||
String targetConstant = enumTransformationInvoker.transform( sourceConstant );
|
||||
String sourceNameConstant = getEnumConstant( sourceTypeElement, sourceConstant );
|
||||
String targetConstant = enumTransformationInvoker.transform( sourceNameConstant );
|
||||
mappings.add( new MappingEntry( sourceConstant, targetConstant ) );
|
||||
}
|
||||
}
|
||||
@ -250,27 +264,35 @@ public class ValueMappingMethod extends MappingMethod {
|
||||
if ( sourceErrorOccurred || mandatoryMissing ) {
|
||||
return mappings;
|
||||
}
|
||||
Set<String> mappedSources = new LinkedHashSet<>();
|
||||
|
||||
// Start to fill the mappings with the defined valuemappings
|
||||
for ( ValueMappingOptions valueMapping : valueMappings.regularValueMappings ) {
|
||||
String target =
|
||||
NULL.equals( valueMapping.getTarget() ) ? null : valueMapping.getTarget();
|
||||
mappings.add( new MappingEntry( valueMapping.getSource(), target ) );
|
||||
mappedSources.add( valueMapping.getSource() );
|
||||
mappings.add( new MappingEntry( valueMapping.getSource(), valueMapping.getTarget() ) );
|
||||
unmappedSourceConstants.remove( valueMapping.getSource() );
|
||||
}
|
||||
|
||||
// add mappings based on name
|
||||
if ( !valueMappings.hasMapAnyUnmapped ) {
|
||||
|
||||
mappedSources.add( NULL );
|
||||
TypeElement targetTypeElement = targetType.getTypeElement();
|
||||
// all remaining constants are mapped
|
||||
for ( String sourceConstant : unmappedSourceConstants ) {
|
||||
String stringConstant = enumTransformationInvoker.transform( sourceConstant );
|
||||
mappings.add( new MappingEntry( stringConstant, sourceConstant ) );
|
||||
String sourceNameConstant = getEnumConstant( targetTypeElement, sourceConstant );
|
||||
String stringConstant = enumTransformationInvoker.transform( sourceNameConstant );
|
||||
if ( !mappedSources.contains( stringConstant ) ) {
|
||||
mappings.add( new MappingEntry( stringConstant, sourceConstant ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
private String getEnumConstant(TypeElement typeElement, String enumConstant) {
|
||||
return ctx.getEnumNamingStrategy().getEnumConstant( typeElement, enumConstant );
|
||||
}
|
||||
|
||||
private SelectionParameters getSelectionParameters(Method method, Types typeUtils) {
|
||||
BeanMappingGem beanMapping = BeanMappingGem.instanceOn( method.getExecutable() );
|
||||
if ( beanMapping != null ) {
|
||||
@ -377,6 +399,18 @@ public class ValueMappingMethod extends MappingMethod {
|
||||
);
|
||||
foundIncorrectMapping = true;
|
||||
}
|
||||
else if ( valueMappings.nullTarget == null && valueMappings.nullValueTarget != null
|
||||
&& !targetEnumConstants.contains( valueMappings.nullValueTarget ) ) {
|
||||
// if there is no nullTarget, but nullValueTarget has a value it means that there was an SPI
|
||||
// which returned an enum for the target enum
|
||||
ctx.getMessager().printMessage(
|
||||
method.getExecutable(),
|
||||
Message.VALUEMAPPING_NON_EXISTING_CONSTANT_FROM_SPI,
|
||||
valueMappings.nullValueTarget,
|
||||
method.getReturnType(),
|
||||
ctx.getEnumNamingStrategy()
|
||||
);
|
||||
}
|
||||
|
||||
return !foundIncorrectMapping;
|
||||
}
|
||||
@ -417,6 +451,7 @@ public class ValueMappingMethod extends MappingMethod {
|
||||
boolean hasMapAnyUnmapped = false;
|
||||
boolean hasMapAnyRemaining = false;
|
||||
boolean hasDefaultValue = false;
|
||||
boolean hasNullValue = false;
|
||||
|
||||
ValueMappings(List<ValueMappingOptions> valueMappings) {
|
||||
|
||||
@ -436,6 +471,7 @@ public class ValueMappingMethod extends MappingMethod {
|
||||
else if ( NULL.equals( valueMapping.getSource() ) ) {
|
||||
nullTarget = valueMapping;
|
||||
nullValueTarget = getValue( nullTarget );
|
||||
hasNullValue = true;
|
||||
}
|
||||
else {
|
||||
regularValueMappings.add( valueMapping );
|
||||
@ -489,7 +525,12 @@ public class ValueMappingMethod extends MappingMethod {
|
||||
|
||||
MappingEntry( String source, String target ) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
if ( !NULL.equals( target ) ) {
|
||||
this.target = target;
|
||||
}
|
||||
else {
|
||||
this.target = null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
|
@ -26,6 +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.EnumTransformationStrategy;
|
||||
|
||||
/**
|
||||
@ -98,6 +99,11 @@ public class DefaultModelElementProcessorContext implements ProcessorContext {
|
||||
return roundContext.getAnnotationProcessorContext().getEnumTransformationStrategies();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumNamingStrategy getEnumNamingStrategy() {
|
||||
return roundContext.getAnnotationProcessorContext().getEnumNamingStrategy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
return options;
|
||||
|
@ -101,6 +101,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
||||
typeUtils,
|
||||
messager,
|
||||
accessorNaming,
|
||||
context.getEnumNamingStrategy(),
|
||||
context.getEnumTransformationStrategies(),
|
||||
options,
|
||||
new MappingResolverImpl(
|
||||
|
@ -17,6 +17,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.version.VersionInformation;
|
||||
import org.mapstruct.ap.spi.EnumNamingStrategy;
|
||||
import org.mapstruct.ap.spi.EnumTransformationStrategy;
|
||||
|
||||
/**
|
||||
@ -55,6 +56,8 @@ public interface ModelElementProcessor<P, R> {
|
||||
|
||||
Map<String, EnumTransformationStrategy> getEnumTransformationStrategies();
|
||||
|
||||
EnumNamingStrategy getEnumNamingStrategy();
|
||||
|
||||
Options getOptions();
|
||||
|
||||
VersionInformation getVersionInformation();
|
||||
|
@ -24,6 +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.EnumTransformationStrategy;
|
||||
import org.mapstruct.ap.spi.FreeBuilderAccessorNamingStrategy;
|
||||
import org.mapstruct.ap.spi.ImmutablesAccessorNamingStrategy;
|
||||
@ -41,6 +43,7 @@ public class AnnotationProcessorContext implements MapStructProcessingEnvironmen
|
||||
|
||||
private BuilderProvider builderProvider;
|
||||
private AccessorNamingStrategy accessorNamingStrategy;
|
||||
private EnumNamingStrategy enumNamingStrategy;
|
||||
private boolean initialized;
|
||||
private Map<String, EnumTransformationStrategy> enumTransformationStrategies;
|
||||
|
||||
@ -110,6 +113,15 @@ public class AnnotationProcessorContext implements MapStructProcessingEnvironmen
|
||||
}
|
||||
this.accessorNaming = new AccessorNamingUtils( this.accessorNamingStrategy );
|
||||
|
||||
this.enumNamingStrategy = Services.get( EnumNamingStrategy.class, new DefaultEnumNamingStrategy() );
|
||||
this.enumNamingStrategy.init( this );
|
||||
if ( verbose ) {
|
||||
messager.printMessage(
|
||||
Diagnostic.Kind.NOTE,
|
||||
"MapStruct: Using enum naming strategy: "
|
||||
+ this.enumNamingStrategy.getClass().getCanonicalName()
|
||||
);
|
||||
}
|
||||
|
||||
this.enumTransformationStrategies = new LinkedHashMap<>();
|
||||
ServiceLoader<EnumTransformationStrategy> transformationStrategiesLoader = ServiceLoader.load(
|
||||
@ -238,6 +250,11 @@ public class AnnotationProcessorContext implements MapStructProcessingEnvironmen
|
||||
return accessorNamingStrategy;
|
||||
}
|
||||
|
||||
public EnumNamingStrategy getEnumNamingStrategy() {
|
||||
initialize();
|
||||
return enumNamingStrategy;
|
||||
}
|
||||
|
||||
public BuilderProvider getBuilderProvider() {
|
||||
initialize();
|
||||
return builderProvider;
|
||||
|
@ -158,6 +158,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 = \"<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_NON_EXISTING_CONSTANT_FROM_SPI( "Constant %s doesn't exist in enum type %s. Constant was returned from EnumNamingStrategy: %s"),
|
||||
VALUEMAPPING_NON_EXISTING_CONSTANT( "Constant %s doesn't exist in enum type %s." );
|
||||
// CHECKSTYLE:ON
|
||||
|
||||
|
@ -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.spi;
|
||||
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.util.Types;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class DefaultEnumNamingStrategy implements EnumNamingStrategy {
|
||||
|
||||
protected Elements elementUtils;
|
||||
protected Types typeUtils;
|
||||
|
||||
@Override
|
||||
public void init(MapStructProcessingEnvironment processingEnvironment) {
|
||||
this.elementUtils = processingEnvironment.getElementUtils();
|
||||
this.typeUtils = processingEnvironment.getTypeUtils();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultNullEnumConstant(TypeElement enumType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnumConstant(TypeElement enumType, String enumConstant) {
|
||||
return enumConstant;
|
||||
}
|
||||
}
|
@ -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.spi;
|
||||
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
import org.mapstruct.util.Experimental;
|
||||
|
||||
/**
|
||||
* A service provider interface for the mapping between different enum constants
|
||||
*
|
||||
* @author Arne Seime
|
||||
*/
|
||||
@Experimental("This SPI can have it's signature changed in subsequent releases")
|
||||
public interface EnumNamingStrategy {
|
||||
|
||||
/**
|
||||
* Initializes the enum value mapping strategy
|
||||
*
|
||||
* @param processingEnvironment environment for facilities
|
||||
*/
|
||||
default void init(MapStructProcessingEnvironment processingEnvironment) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default enum constant to use if the source is null.
|
||||
*
|
||||
* @param enumType the enum
|
||||
* @return enum value or null if there is no designated enum constant
|
||||
*/
|
||||
String getDefaultNullEnumConstant(TypeElement enumType);
|
||||
|
||||
/**
|
||||
* Map the enum constant to the value use for matching.
|
||||
* In case you want this enum constant to match to null return {@link org.mapstruct.MappingConstants#NULL}
|
||||
*
|
||||
* @param enumType the enum this constant belongs to
|
||||
* @param enumConstant constant to transform
|
||||
*
|
||||
* @return the transformed constant - or the original value from the parameter if no transformation is needed.
|
||||
* never return null
|
||||
*/
|
||||
String getEnumConstant(TypeElement enumType, String enumConstant);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public enum CheeseType {
|
||||
|
||||
BRIE,
|
||||
ROQUEFORT
|
||||
}
|
@ -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.spi;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.MappingConstants;
|
||||
import org.mapstruct.ValueMapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper
|
||||
public interface CustomCheeseMapper {
|
||||
|
||||
CustomCheeseMapper INSTANCE = Mappers.getMapper( CustomCheeseMapper.class );
|
||||
|
||||
CheeseType map(CustomCheeseType cheese);
|
||||
|
||||
CustomCheeseType map(CheeseType cheese);
|
||||
|
||||
String mapToString(CustomCheeseType cheeseType);
|
||||
|
||||
String mapToString(CheeseType cheeseType);
|
||||
|
||||
@ValueMapping(source = MappingConstants.ANY_REMAINING, target = "CUSTOM_BRIE")
|
||||
CustomCheeseType mapStringToCustom(String cheese);
|
||||
|
||||
@ValueMapping(source = MappingConstants.ANY_REMAINING, target = "BRIE")
|
||||
CheeseType mapStringToCheese(String cheese);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public enum CustomCheeseType implements CustomEnumMarker {
|
||||
|
||||
UNSPECIFIED,
|
||||
CUSTOM_BRIE,
|
||||
CUSTOM_ROQUEFORT,
|
||||
UNRECOGNIZED,
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public interface CustomEnumMarker {
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class CustomEnumNamingStrategy extends DefaultEnumNamingStrategy implements EnumNamingStrategy {
|
||||
|
||||
@Override
|
||||
public String getDefaultNullEnumConstant(TypeElement enumType) {
|
||||
if ( isCustomEnum( enumType ) ) {
|
||||
return "UNSPECIFIED";
|
||||
}
|
||||
|
||||
return super.getDefaultNullEnumConstant( enumType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnumConstant(TypeElement enumType, String enumConstant) {
|
||||
if ( isCustomEnum( enumType ) ) {
|
||||
return getCustomEnumConstant( enumConstant );
|
||||
}
|
||||
return super.getEnumConstant( enumType, enumConstant );
|
||||
}
|
||||
|
||||
protected String getCustomEnumConstant(String enumConstant) {
|
||||
if ( "UNRECOGNIZED".equals( enumConstant ) || "UNSPECIFIED".equals( enumConstant ) ) {
|
||||
return MappingConstantsGem.NULL;
|
||||
}
|
||||
|
||||
return enumConstant.replace( "CUSTOM_", "" );
|
||||
}
|
||||
|
||||
protected boolean isCustomEnum(TypeElement enumType) {
|
||||
for ( TypeMirror enumTypeInterface : enumType.getInterfaces() ) {
|
||||
if ( typeUtils.asElement( enumTypeInterface ).getSimpleName().contentEquals( "CustomEnumMarker" ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.WithServiceImplementation;
|
||||
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||
import org.mapstruct.ap.testutil.runner.GeneratedSource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@RunWith(AnnotationProcessorTestRunner.class)
|
||||
@WithClasses({
|
||||
CheeseType.class,
|
||||
CustomCheeseType.class,
|
||||
CustomEnumMarker.class,
|
||||
})
|
||||
@WithServiceImplementation(CustomEnumNamingStrategy.class)
|
||||
public class CustomEnumNamingStrategyTest {
|
||||
|
||||
@Rule
|
||||
public final GeneratedSource generatedSource = new GeneratedSource();
|
||||
|
||||
@Test
|
||||
@WithClasses({
|
||||
CustomCheeseMapper.class
|
||||
})
|
||||
public void shouldApplyCustomEnumNamingStrategy() {
|
||||
generatedSource.addComparisonToFixtureFor( CustomCheeseMapper.class );
|
||||
CustomCheeseMapper mapper = CustomCheeseMapper.INSTANCE;
|
||||
|
||||
// CheeseType -> CustomCheeseType
|
||||
assertThat( mapper.map( (CheeseType) null ) ).isEqualTo( CustomCheeseType.UNSPECIFIED );
|
||||
assertThat( mapper.map( CheeseType.BRIE ) ).isEqualTo( CustomCheeseType.CUSTOM_BRIE );
|
||||
assertThat( mapper.map( CheeseType.ROQUEFORT ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
|
||||
// CustomCheeseType -> CheeseType
|
||||
assertThat( mapper.map( (CustomCheeseType) null ) ).isNull();
|
||||
assertThat( mapper.map( CustomCheeseType.UNSPECIFIED ) ).isNull();
|
||||
assertThat( mapper.map( CustomCheeseType.CUSTOM_BRIE ) ).isEqualTo( CheeseType.BRIE );
|
||||
assertThat( mapper.map( CustomCheeseType.CUSTOM_ROQUEFORT ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.map( CustomCheeseType.UNRECOGNIZED ) ).isNull();
|
||||
|
||||
// CheeseType -> String
|
||||
assertThat( mapper.mapToString( (CheeseType) null ) ).isNull();
|
||||
assertThat( mapper.mapToString( CheeseType.BRIE ) ).isEqualTo( "BRIE" );
|
||||
assertThat( mapper.mapToString( CheeseType.ROQUEFORT ) ).isEqualTo( "ROQUEFORT" );
|
||||
|
||||
// CustomCheeseType -> String
|
||||
assertThat( mapper.mapToString( (CustomCheeseType) null ) ).isNull();
|
||||
assertThat( mapper.mapToString( CustomCheeseType.UNSPECIFIED ) ).isNull();
|
||||
assertThat( mapper.mapToString( CustomCheeseType.CUSTOM_BRIE ) ).isEqualTo( "BRIE" );
|
||||
assertThat( mapper.mapToString( CustomCheeseType.CUSTOM_ROQUEFORT ) ).isEqualTo( "ROQUEFORT" );
|
||||
assertThat( mapper.mapToString( CustomCheeseType.UNRECOGNIZED ) ).isNull();
|
||||
|
||||
// String - > CheeseType
|
||||
assertThat( mapper.mapStringToCheese( null ) ).isNull();
|
||||
assertThat( mapper.mapStringToCheese( "BRIE" ) ).isEqualTo( CheeseType.BRIE );
|
||||
assertThat( mapper.mapStringToCheese( "ROQUEFORT" ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCheese( "UNKNOWN" ) ).isEqualTo( CheeseType.BRIE );
|
||||
|
||||
// CustomCheeseType -> String
|
||||
assertThat( mapper.mapStringToCustom( null ) ).isEqualTo( CustomCheeseType.UNSPECIFIED );
|
||||
assertThat( mapper.mapStringToCustom( "UNRECOGNIZED" ) ).isEqualTo( CustomCheeseType.CUSTOM_BRIE );
|
||||
assertThat( mapper.mapStringToCustom( "BRIE" ) ).isEqualTo( CustomCheeseType.CUSTOM_BRIE );
|
||||
assertThat( mapper.mapStringToCustom( "ROQUEFORT" ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCustom( "UNKNOWN" ) ).isEqualTo( CustomCheeseType.CUSTOM_BRIE );
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithClasses({
|
||||
OverridesCustomCheeseMapper.class
|
||||
})
|
||||
public void shouldApplyDefinedMappingsInsteadOfCustomEnumNamingStrategy() {
|
||||
OverridesCustomCheeseMapper mapper = OverridesCustomCheeseMapper.INSTANCE;
|
||||
|
||||
// CheeseType -> CustomCheeseType
|
||||
assertThat( mapper.map( (CheeseType) null ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.map( CheeseType.BRIE ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.map( CheeseType.ROQUEFORT ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
|
||||
// CustomCheeseType -> CheeseType
|
||||
assertThat( mapper.map( (CustomCheeseType) null ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.map( CustomCheeseType.UNSPECIFIED ) ).isNull();
|
||||
assertThat( mapper.map( CustomCheeseType.CUSTOM_BRIE ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.map( CustomCheeseType.CUSTOM_ROQUEFORT ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.map( CustomCheeseType.UNRECOGNIZED ) ).isNull();
|
||||
|
||||
// CheeseType -> String
|
||||
assertThat( mapper.mapToString( (CheeseType) null ) ).isNull();
|
||||
assertThat( mapper.mapToString( CheeseType.BRIE ) ).isEqualTo( "BRIE" );
|
||||
assertThat( mapper.mapToString( CheeseType.ROQUEFORT ) ).isEqualTo( "BRIE" );
|
||||
|
||||
// CustomCheeseType -> String
|
||||
assertThat( mapper.mapToString( (CustomCheeseType) null ) ).isEqualTo( "ROQUEFORT" );
|
||||
assertThat( mapper.mapToString( CustomCheeseType.UNSPECIFIED ) ).isNull();
|
||||
assertThat( mapper.mapToString( CustomCheeseType.CUSTOM_BRIE ) ).isEqualTo( "BRIE" );
|
||||
assertThat( mapper.mapToString( CustomCheeseType.CUSTOM_ROQUEFORT ) ).isEqualTo( "BRIE" );
|
||||
assertThat( mapper.mapToString( CustomCheeseType.UNRECOGNIZED ) ).isNull();
|
||||
|
||||
// String - > CheeseType
|
||||
assertThat( mapper.mapStringToCheese( null ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCheese( "BRIE" ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCheese( "ROQUEFORT" ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCheese( "UNKNOWN" ) ).isEqualTo( CheeseType.BRIE );
|
||||
|
||||
// CustomCheeseType -> String
|
||||
assertThat( mapper.mapStringToCustom( null ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCustom( "UNRECOGNIZED" ) ).isEqualTo( CustomCheeseType.CUSTOM_BRIE );
|
||||
assertThat( mapper.mapStringToCustom( "BRIE" ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCustom( "ROQUEFORT" ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCustom( "UNKNOWN" ) ).isEqualTo( CustomCheeseType.CUSTOM_BRIE );
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class CustomErroneousEnumNamingStrategy extends DefaultEnumNamingStrategy implements EnumNamingStrategy {
|
||||
|
||||
@Override
|
||||
public String getDefaultNullEnumConstant(TypeElement enumType) {
|
||||
if ( isCustomEnum( enumType ) ) {
|
||||
return "INCORRECT";
|
||||
}
|
||||
|
||||
return super.getDefaultNullEnumConstant( enumType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEnumConstant(TypeElement enumType, String enumConstant) {
|
||||
if ( isCustomEnum( enumType ) ) {
|
||||
return getCustomEnumConstant( enumConstant );
|
||||
}
|
||||
return super.getEnumConstant( enumType, enumConstant );
|
||||
}
|
||||
|
||||
protected String getCustomEnumConstant(String enumConstant) {
|
||||
if ( "UNRECOGNIZED".equals( enumConstant ) || "UNSPECIFIED".equals( enumConstant ) ) {
|
||||
return MappingConstantsGem.NULL;
|
||||
}
|
||||
|
||||
return enumConstant.replace( "CUSTOM_", "" );
|
||||
}
|
||||
|
||||
protected boolean isCustomEnum(TypeElement enumType) {
|
||||
for ( TypeMirror enumTypeInterface : enumType.getInterfaces() ) {
|
||||
if ( typeUtils.asElement( enumTypeInterface ).getSimpleName().contentEquals( "CustomEnumMarker" ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.WithServiceImplementation;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@RunWith(AnnotationProcessorTestRunner.class)
|
||||
@WithClasses({
|
||||
CheeseType.class,
|
||||
CustomCheeseType.class,
|
||||
CustomEnumMarker.class,
|
||||
})
|
||||
@WithServiceImplementation(CustomErroneousEnumNamingStrategy.class)
|
||||
public class CustomErroneousEnumNamingStrategyTest {
|
||||
|
||||
@Test
|
||||
@WithClasses({
|
||||
CustomCheeseMapper.class
|
||||
})
|
||||
@ExpectedCompilationOutcome(value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
type = CustomCheeseMapper.class,
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
line = 23,
|
||||
messageRegExp = "Constant INCORRECT doesn't exist in enum type " +
|
||||
"org\\.mapstruct\\.ap\\.test\\.value\\.spi\\.CustomCheeseType." +
|
||||
" Constant was returned from EnumNamingStrategy: .*CustomErroneousEnumNamingStrategy@.*"
|
||||
),
|
||||
@Diagnostic(
|
||||
type = CustomCheeseMapper.class,
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
line = 30,
|
||||
messageRegExp = "Constant INCORRECT doesn't exist in enum type " +
|
||||
"org\\.mapstruct\\.ap\\.test\\.value\\.spi\\.CustomCheeseType." +
|
||||
" Constant was returned from EnumNamingStrategy: .*CustomErroneousEnumNamingStrategy@.*"
|
||||
)
|
||||
}
|
||||
)
|
||||
public void shouldThrowCompileErrorWhenDefaultEnumDoesNotExist() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithClasses({
|
||||
OverridesCustomCheeseMapper.class
|
||||
})
|
||||
public void shouldApplyDefinedMappingsInsteadOfCustomEnumNamingStrategy() {
|
||||
OverridesCustomCheeseMapper mapper = OverridesCustomCheeseMapper.INSTANCE;
|
||||
|
||||
// CheeseType -> CustomCheeseType
|
||||
assertThat( mapper.map( (CheeseType) null ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.map( CheeseType.BRIE ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.map( CheeseType.ROQUEFORT ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
|
||||
// CustomCheeseType -> CheeseType
|
||||
assertThat( mapper.map( (CustomCheeseType) null ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.map( CustomCheeseType.UNSPECIFIED ) ).isNull();
|
||||
assertThat( mapper.map( CustomCheeseType.CUSTOM_BRIE ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.map( CustomCheeseType.CUSTOM_ROQUEFORT ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.map( CustomCheeseType.UNRECOGNIZED ) ).isNull();
|
||||
|
||||
// CheeseType -> String
|
||||
assertThat( mapper.mapToString( (CheeseType) null ) ).isNull();
|
||||
assertThat( mapper.mapToString( CheeseType.BRIE ) ).isEqualTo( "BRIE" );
|
||||
assertThat( mapper.mapToString( CheeseType.ROQUEFORT ) ).isEqualTo( "BRIE" );
|
||||
|
||||
// CustomCheeseType -> String
|
||||
assertThat( mapper.mapToString( (CustomCheeseType) null ) ).isEqualTo( "ROQUEFORT" );
|
||||
assertThat( mapper.mapToString( CustomCheeseType.UNSPECIFIED ) ).isNull();
|
||||
assertThat( mapper.mapToString( CustomCheeseType.CUSTOM_BRIE ) ).isEqualTo( "BRIE" );
|
||||
assertThat( mapper.mapToString( CustomCheeseType.CUSTOM_ROQUEFORT ) ).isEqualTo( "BRIE" );
|
||||
assertThat( mapper.mapToString( CustomCheeseType.UNRECOGNIZED ) ).isNull();
|
||||
|
||||
// String - > CheeseType
|
||||
assertThat( mapper.mapStringToCheese( null ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCheese( "BRIE" ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCheese( "ROQUEFORT" ) ).isEqualTo( CheeseType.ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCheese( "UNKNOWN" ) ).isEqualTo( CheeseType.BRIE );
|
||||
|
||||
// CustomCheeseType -> String
|
||||
assertThat( mapper.mapStringToCustom( null ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCustom( "UNRECOGNIZED" ) ).isEqualTo( CustomCheeseType.CUSTOM_BRIE );
|
||||
assertThat( mapper.mapStringToCustom( "BRIE" ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCustom( "ROQUEFORT" ) ).isEqualTo( CustomCheeseType.CUSTOM_ROQUEFORT );
|
||||
assertThat( mapper.mapStringToCustom( "UNKNOWN" ) ).isEqualTo( CustomCheeseType.CUSTOM_BRIE );
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.MappingConstants;
|
||||
import org.mapstruct.ValueMapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper
|
||||
public interface OverridesCustomCheeseMapper {
|
||||
|
||||
OverridesCustomCheeseMapper INSTANCE = Mappers.getMapper( OverridesCustomCheeseMapper.class );
|
||||
|
||||
@ValueMapping(source = "CUSTOM_BRIE", target = "ROQUEFORT")
|
||||
@ValueMapping(source = MappingConstants.NULL, target = "ROQUEFORT")
|
||||
CheeseType map(CustomCheeseType cheese);
|
||||
|
||||
@ValueMapping(source = "BRIE", target = "CUSTOM_ROQUEFORT")
|
||||
@ValueMapping(source = MappingConstants.NULL, target = "CUSTOM_ROQUEFORT")
|
||||
CustomCheeseType map(CheeseType cheese);
|
||||
|
||||
@ValueMapping(source = "CUSTOM_ROQUEFORT", target = "BRIE")
|
||||
@ValueMapping(source = MappingConstants.NULL, target = "ROQUEFORT")
|
||||
String mapToString(CustomCheeseType cheeseType);
|
||||
|
||||
@ValueMapping(source = "ROQUEFORT", target = "BRIE")
|
||||
String mapToString(CheeseType cheeseType);
|
||||
|
||||
@ValueMapping(source = MappingConstants.ANY_REMAINING, target = "CUSTOM_BRIE")
|
||||
@ValueMapping(source = "BRIE", target = "CUSTOM_ROQUEFORT")
|
||||
@ValueMapping(source = MappingConstants.NULL, target = "CUSTOM_ROQUEFORT")
|
||||
CustomCheeseType mapStringToCustom(String cheese);
|
||||
|
||||
@ValueMapping(source = MappingConstants.ANY_REMAINING, target = "BRIE")
|
||||
@ValueMapping(source = "BRIE", target = "ROQUEFORT")
|
||||
@ValueMapping(source = MappingConstants.NULL, target = "ROQUEFORT")
|
||||
CheeseType mapStringToCheese(String cheese);
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
import javax.annotation.processing.Generated;
|
||||
|
||||
@Generated(
|
||||
value = "org.mapstruct.ap.MappingProcessor",
|
||||
date = "2020-05-16T12:53:12+0200",
|
||||
comments = "version: , compiler: javac, environment: Java 14.0.1 (Oracle Corporation)"
|
||||
)
|
||||
public class CustomCheeseMapperImpl implements CustomCheeseMapper {
|
||||
|
||||
@Override
|
||||
public CheeseType map(CustomCheeseType cheese) {
|
||||
if ( cheese == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CheeseType cheeseType;
|
||||
|
||||
switch ( cheese ) {
|
||||
case UNSPECIFIED: cheeseType = null;
|
||||
break;
|
||||
case CUSTOM_BRIE: cheeseType = CheeseType.BRIE;
|
||||
break;
|
||||
case CUSTOM_ROQUEFORT: cheeseType = CheeseType.ROQUEFORT;
|
||||
break;
|
||||
case UNRECOGNIZED: cheeseType = null;
|
||||
break;
|
||||
default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheese );
|
||||
}
|
||||
|
||||
return cheeseType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomCheeseType map(CheeseType cheese) {
|
||||
if ( cheese == null ) {
|
||||
return CustomCheeseType.UNSPECIFIED;
|
||||
}
|
||||
|
||||
CustomCheeseType customCheeseType;
|
||||
|
||||
switch ( cheese ) {
|
||||
case BRIE: customCheeseType = CustomCheeseType.CUSTOM_BRIE;
|
||||
break;
|
||||
case ROQUEFORT: customCheeseType = CustomCheeseType.CUSTOM_ROQUEFORT;
|
||||
break;
|
||||
default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheese );
|
||||
}
|
||||
|
||||
return customCheeseType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapToString(CustomCheeseType cheeseType) {
|
||||
if ( cheeseType == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String string;
|
||||
|
||||
switch ( cheeseType ) {
|
||||
case UNSPECIFIED: string = null;
|
||||
break;
|
||||
case CUSTOM_BRIE: string = "BRIE";
|
||||
break;
|
||||
case CUSTOM_ROQUEFORT: string = "ROQUEFORT";
|
||||
break;
|
||||
case UNRECOGNIZED: string = null;
|
||||
break;
|
||||
default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheeseType );
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapToString(CheeseType cheeseType) {
|
||||
if ( cheeseType == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String string;
|
||||
|
||||
switch ( cheeseType ) {
|
||||
case BRIE: string = "BRIE";
|
||||
break;
|
||||
case ROQUEFORT: string = "ROQUEFORT";
|
||||
break;
|
||||
default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheeseType );
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomCheeseType mapStringToCustom(String cheese) {
|
||||
if ( cheese == null ) {
|
||||
return CustomCheeseType.UNSPECIFIED;
|
||||
}
|
||||
|
||||
CustomCheeseType customCheeseType;
|
||||
|
||||
switch ( cheese ) {
|
||||
case "BRIE": customCheeseType = CustomCheeseType.CUSTOM_BRIE;
|
||||
break;
|
||||
case "ROQUEFORT": customCheeseType = CustomCheeseType.CUSTOM_ROQUEFORT;
|
||||
break;
|
||||
default: customCheeseType = CustomCheeseType.CUSTOM_BRIE;
|
||||
}
|
||||
|
||||
return customCheeseType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CheeseType mapStringToCheese(String cheese) {
|
||||
if ( cheese == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CheeseType cheeseType;
|
||||
|
||||
switch ( cheese ) {
|
||||
case "BRIE": cheeseType = CheeseType.BRIE;
|
||||
break;
|
||||
case "ROQUEFORT": cheeseType = CheeseType.ROQUEFORT;
|
||||
break;
|
||||
default: cheeseType = CheeseType.BRIE;
|
||||
}
|
||||
|
||||
return cheeseType;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user