mapstruct/documentation/src/main/asciidoc/chapter-8-mapping-values.asciidoc
Jasper Vandemalle 4480e0f367 Fix minor typos
2020-10-03 00:35:28 +02:00

265 lines
9.5 KiB
Plaintext

[[mapping-enum-types]]
== Mapping Values
=== Mapping enum to enum types
MapStruct supports the generation of methods which map one Java enum type into another.
By default, each constant from the source enum is mapped to a constant with the same name in the target enum type. If required, a constant from the source enum may be mapped to a constant with another name with help of the `@ValueMapping` annotation. Several constants from the source enum can be mapped to the same constant in the target type.
The following shows an example:
.Enum mapping method
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
@Mapper
public interface OrderMapper {
OrderMapper INSTANCE = Mappers.getMapper( OrderMapper.class );
@ValueMappings({
@ValueMapping(source = "EXTRA", target = "SPECIAL"),
@ValueMapping(source = "STANDARD", target = "DEFAULT"),
@ValueMapping(source = "NORMAL", target = "DEFAULT")
})
ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
}
----
====
.Enum mapping method result
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
// GENERATED CODE
public class OrderMapperImpl implements OrderMapper {
@Override
public ExternalOrderType orderTypeToExternalOrderType(OrderType orderType) {
if ( orderType == null ) {
return null;
}
ExternalOrderType externalOrderType_;
switch ( orderType ) {
case EXTRA: externalOrderType_ = ExternalOrderType.SPECIAL;
break;
case STANDARD: externalOrderType_ = ExternalOrderType.DEFAULT;
break;
case NORMAL: externalOrderType_ = ExternalOrderType.DEFAULT;
break;
case RETAIL: externalOrderType_ = ExternalOrderType.RETAIL;
break;
case B2B: externalOrderType_ = ExternalOrderType.B2B;
break;
default: throw new IllegalArgumentException( "Unexpected enum constant: " + orderType );
}
return externalOrderType_;
}
}
----
====
By default an error will be raised by MapStruct in case a constant of the source enum type does not have a corresponding constant with the same name in the target type and also is not mapped to another constant via `@ValueMapping`. This ensures that all constants are mapped in a safe and predictable manner. The generated
mapping method will throw an IllegalStateException if for some reason an unrecognized source value occurs.
MapStruct also has a mechanism for mapping any remaining (unspecified) mappings to a default. This can be used only once in a set of value mappings and only applies to the source. It comes in two flavors: `<ANY_REMAINING>` and `<ANY_UNMAPPED>`. They cannot be used at the same time.
In case of source `<ANY_REMAINING>` MapStruct will continue to map a source enum constant to a target enum constant with the same name. The remainder of the source enum constants will be mapped to the target specified in the `@ValueMapping` with `<ANY_REMAINING>` source.
MapStruct will *not* attempt such name based mapping for `<ANY_UNMAPPED>` and directly apply the target specified in the `@ValueMapping` with `<ANY_UNMAPPED>` source to the remainder.
MapStruct is able to handle `null` sources and `null` targets by means of the `<NULL>` keyword.
[TIP]
====
Constants for `<ANY_REMAINING>`, `<ANY_UNMAPPED>` and `<NULL>` are available in the `MappingConstants` class.
====
Finally `@InheritInverseConfiguration` and `@InheritConfiguration` can be used in combination with `@ValueMappings`. `<ANY_REMAINING>` and `<ANY_UNMAPPED>` will be ignored in that case.
.Enum mapping method, <NULL> and <ANY_REMAINING>
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
@Mapper
public interface SpecialOrderMapper {
SpecialOrderMapper INSTANCE = Mappers.getMapper( SpecialOrderMapper.class );
@ValueMappings({
@ValueMapping( source = MappingConstants.NULL, target = "DEFAULT" ),
@ValueMapping( source = "STANDARD", target = MappingConstants.NULL ),
@ValueMapping( source = MappingConstants.ANY_REMAINING, target = "SPECIAL" )
})
ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
}
----
====
.Enum mapping method result, <NULL> and <ANY_REMAINING>
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
// GENERATED CODE
public class SpecialOrderMapperImpl implements SpecialOrderMapper {
@Override
public ExternalOrderType orderTypeToExternalOrderType(OrderType orderType) {
if ( orderType == null ) {
return ExternalOrderType.DEFAULT;
}
ExternalOrderType externalOrderType_;
switch ( orderType ) {
case STANDARD: externalOrderType_ = null;
break;
case RETAIL: externalOrderType_ = ExternalOrderType.RETAIL;
break;
case B2B: externalOrderType_ = ExternalOrderType.B2B;
break;
default: externalOrderType_ = ExternalOrderType.SPECIAL;
}
return externalOrderType_;
}
}
----
====
*Note:* MapStruct would have refrained from mapping the `RETAIL` and `B2B` when `<ANY_UNMAPPED>` was used instead of `<ANY_REMAINING>`.
[WARNING]
====
The mapping of enum to enum via the `@Mapping` annotation is *DEPRECATED*. It will be removed from future versions of MapStruct. Please adapt existing enum mapping methods to make use of `@ValueMapping` instead.
====
=== Mapping enum-to-String or String-to-enum
MapStruct supports enum to a String mapping along the same lines as is described in <<Mapping enum to enum types, enum-to-enum types>>. There are similarities and differences:
*enum to `String`*
1. Similarity: All not explicit defined mappings will result in each source enum constant value being mapped a `String` value with the same constant value.
2. Similarity: `<ANY_UNMAPPED`> stops after handling defined mapping and proceeds to the switch/default clause value.
3. Difference: `<ANY_REMAINING>` will result in an error. It acts on the premise that there is name similarity between enum constants in source and target which does not make sense for a String type.
4. Difference: Given 1. and 3. there will never be unmapped values.
*`String` to enum*
1. Similarity: All not explicit defined mappings will result in the target enum constant mapped from the `String` value when that matches the target enum constant name.
2. Similarity: `<ANY_UNMAPPED`> stops after handling defined mapping and proceeds to the switch/default clause value.
3. Similarity: `<ANY_REMAINING>` will create a mapping for each target enum constant and proceed to the switch/default clause value.
4. Difference: A switch/default value needs to be provided to have a determined outcome (enum has a limited set of values, `String` has unlimited options). Failing to specify `<ANY_REMAINING>` or `<ANY_UNMAPPED`> will result in a warning.
=== Custom name transformation
When no `@ValueMapping`(s) are defined then each constant from the source enum is mapped to a constant with the same name in the target enum type.
However, there are cases where the source enum needs to be transformed before doing the mapping.
E.g. a suffix needs to be applied to map from the source into the target enum.
.Enum types
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
public enum CheeseType {
BRIE,
ROQUEFORT
}
public enum CheeseTypeSuffixed {
BRIE_TYPE,
ROQUEFORT_TYPE
}
----
====
.Enum mapping method with custom name transformation strategy
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
@Mapper
public interface CheeseMapper {
CheeseMapper INSTANCE = Mappers.getMapper( CheeseMapper.class );
@EnumMapping(nameTransformationStrategy = "suffix", configuration = "_TYPE")
CheeseTypeSuffixed map(CheeseType cheese);
@InheritInverseConfiguration
CheeseType map(CheeseTypeSuffix cheese);
}
----
====
.Enum mapping method with custom name transformation strategy result
====
[source, java, linenums]
[subs="verbatim,attributes"]
----
// GENERATED CODE
public class CheeseSuffixMapperImpl implements CheeseSuffixMapper {
@Override
public CheeseTypeSuffixed map(CheeseType cheese) {
if ( cheese == null ) {
return null;
}
CheeseTypeSuffixed cheeseTypeSuffixed;
switch ( cheese ) {
case BRIE: cheeseTypeSuffixed = CheeseTypeSuffixed.BRIE_TYPE;
break;
case ROQUEFORT: cheeseTypeSuffixed = CheeseTypeSuffixed.ROQUEFORT_TYPE;
break;
default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheese );
}
return cheeseTypeSuffixed;
}
@Override
public CheeseType map(CheeseTypeSuffixed cheese) {
if ( cheese == null ) {
return null;
}
CheeseType cheeseType;
switch ( cheese ) {
case BRIE_TYPE: cheeseType = CheeseType.BRIE;
break;
case ROQUEFORT_TYPE: cheeseType = CheeseType.ROQUEFORT;
break;
default: throw new IllegalArgumentException( "Unexpected enum constant: " + cheese );
}
return cheeseType;
}
}
----
====
MapStruct provides the following out of the box enum name transformation strategies:
* _suffix_ - Applies a suffix on the source enum
* _stripSuffix_ - Strips a suffix from the source enum
* _prefix_ - Applies a prefix on the source enum
* _stripPrefix_ - Strips a prefix from the source enum
It is also possible to register custom strategies.
For more information on how to do that have a look at <<custom-enum-transformation-strategy>>