1. Introduction
MapStruct is an efficient, type-safe library that simplifies data mapping between Java objects, eliminating the need for manual conversion logic.
In this tutorial, we’ll explore the use of MapStruct to map an enum to a string.
2. Mapping an Enum to a String
Using Java enums as strings rather than ordinals simplifies data exchange with external APIs, making data retrieval easier and enhancing readability in a UI.
Suppose that we want to convert the DayOfWeek enum to a string.
DayOfWeek is an enum in the Java Date-Time API that represents the seven days of the week, from Monday to Sunday.
Let’s implement the MapStruct mapper:
@Mapper
public interface DayOfWeekMapper {
DayOfWeekMapper INSTANCE = Mappers.getMapper(DayOfWeekMapper.class);
String toString(DayOfWeek dayOfWeek);
// additional mapping methods as needed
}
The DayOfWeekMapper interface is a MapStruct mapper, designated by @Mapper. We define the toString() method that accepts a DayOfWeek enum and converts it into a string representation. By default, MapStruct uses the name() method to get string values for enums:
class DayOfWeekMapperUnitTest {
private DayOfWeekMapper dayOfWeekMapper = DayOfWeekMapper.INSTANCE;
@ParameterizedTest
@CsvSource({"MONDAY,MONDAY", "TUESDAY,TUESDAY", "WEDNESDAY,WEDNESDAY", "THURSDAY,THURSDAY",
"FRIDAY,FRIDAY", "SATURDAY,SATURDAY", "SUNDAY,SUNDAY"})
void whenDayOfWeekMapped_thenGetsNameString(DayOfWeek source, String expected) {
String target = dayOfWeekMapper.toString(source);
assertEquals(expected, target);
}
}
This verifies that toString() maps DayOfWeek enum values to their expected string names. This style of parameterized test also lets us test all possible mutations from a single test.
2.1. Handling null
Now, let’s look at how MapStruct handles null. By default, MapStruct maps a null source to a null target. However, this behavior can be modified.
Straightaway, let’s verify that the mapper returns a null result for a null input:
@Test
void whenNullDayOfWeekMapped_thenGetsNullResult() {
String target = dayOfWeekMapper.toString(null);
assertNull(target);
}
MapStruct provides MappingConstants.NULL to manage null values:
@Mapper
public interface DayOfWeekMapper {
@ValueMapping(target = "MONDAY", source = MappingConstants.NULL)
String toStringWithDefault(DayOfWeek dayOfWeek);
}
For a null value, this mapping returns the default value MONDAY:
@Test
void whenNullDayOfWeekMappedWithDefaults_thenReturnsDefault() {
String target = dayOfWeekMapper.toStringWithDefault(null);
assertEquals("MONDAY", target);
}
3. Mapping a String to an Enum
Now, let’s look at a mapper method to convert the strings back to enums:
@Mapper
public interface DayOfWeekMapper {
DayOfWeek nameStringToDayOfWeek(String day);
}
This mapper converts a string representing a day of the week into the corresponding DayOfWeek enum value:
@ParameterizedTest
@CsvSource(
{"MONDAY,MONDAY", "TUESDAY,TUESDAY", "WEDNESDAY,WEDNESDAY", "THURSDAY,THURSDAY",
"FRIDAY,FRIDAY", "SATURDAY,SATURDAY", "SUNDAY,SUNDAY"})
void whenNameStringMapped_thenGetsDayOfWeek(String source, DayOfWeek expected) {
DayOfWeek target = dayOfWeekMapper.nameStringToDayOfWeek(source);
assertEquals(expected, target);
}
We verify that nameStringToDayOfWeek() maps a day’s string representation to its corresponding enum.
3.1. Handling Unmapped Values
MapStruct throws an error if a string does not match the enum name or another constant via @ValueMapping. Generally, this is done to ensure that all values are mapped safely and predictably. The mapping method created by MapStruct throws an IllegalStateException if an unrecognized source value occurs:
@Test
void whenInvalidNameStringMapped_thenThrowsIllegalArgumentException() {
String source = "Mon";
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
dayOfWeekMapper.nameStringToDayOfWeek(source);
});
assertTrue(exception.getMessage().equals("Unexpected enum constant: " + source));
}
To change this behavior, MapStruct also provides MappingConstants.ANY_UNMAPPED. This instructs MapStruct to map any unmapped source values to the target constant values:
@Mapper
public interface DayOfWeekMapper {
@ValueMapping(target = "MONDAY", source = MappingConstants.ANY_UNMAPPED)
DayOfWeek nameStringToDayOfWeekWithDefaults(String day);
}
Finally, this @ValueMapping annotation sets the default behavior for unmapped sources. Thus, any unmapped input defaults to MONDAY:
@ParameterizedTest
@CsvSource({"Mon,MONDAY"})
void whenInvalidNameStringMappedWithDefaults_thenReturnsDefault(String source, DayOfWeek expected) {
DayOfWeek target = dayOfWeekMapper.nameStringToDayOfWeekWithDefaults(source);
assertEquals(expected, target);
}
4. Mapping an Enum to a Custom String
Now, let’s also convert the enum into a custom short representation of DayOfWeek like “Mon”, “Tue”, and so on:
@Mapper
public interface DayOfWeekMapper {
@ValueMapping(target = "Mon", source = "MONDAY")
@ValueMapping(target = "Tue", source = "TUESDAY")
@ValueMapping(target = "Wed", source = "WEDNESDAY")
@ValueMapping(target = "Thu", source = "THURSDAY")
@ValueMapping(target = "Fri", source = "FRIDAY")
@ValueMapping(target = "Sat", source = "SATURDAY")
@ValueMapping(target = "Sun", source = "SUNDAY")
String toShortString(DayOfWeek dayOfWeek);
}
Conversely, this toShortString() mapping configuration uses @ValueMapping to convert DayOfWeek enums to abbreviated strings:
@ParameterizedTest
@CsvSource(
{"MONDAY,Mon", "TUESDAY,Tue", "WEDNESDAY,Wed", "THURSDAY,Thu",
"FRIDAY,Fri", "SATURDAY,Sat", "SUNDAY,Sun"})
void whenDayOfWeekMapped_thenGetsShortString(DayOfWeek source, String expected) {
String target = dayOfWeekMapper.toShortString(source);
assertEquals(expected, target);
}
5. Mapping a Custom String to an Enum
Finally, we’ll see how to convert the abbreviated string into the DayOfWeek enum:
@Mapper
public interface DayOfWeekMapper {
@InheritInverseConfiguration(name = "toShortString")
DayOfWeek shortStringToDayOfWeek(String day);
}
Furthermore, the @InheritInverseConfiguration annotation defines a reverse mapping, which allows shortStringToDayOfWeek() to inherit its configuration from the toShortString() method, converting abbreviated day names to corresponding DayOfWeek enums:
@ParameterizedTest
@CsvSource(
{"Mon,MONDAY", "Tue,TUESDAY", "Wed,WEDNESDAY", "Thu,THURSDAY",
"Fri,FRIDAY", "Sat,SATURDAY", "Sun,SUNDAY"})
void whenShortStringMapped_thenGetsDayOfWeek(String source, DayOfWeek expected) {
DayOfWeek target = dayOfWeekMapper.shortStringToDayOfWeek(source);
assertEquals(expected, target);
}
6. Conclusion
In this article, we learned how to map enum-to-string with MapStruct’s @ValueMapping annotation. We also used @InheritInverseConfiguration to keep things consistent when mapping back and forth. Using these tricks, we smoothly tackle enum-to-string conversions and keep our code clear and easy to maintain.
As always, the complete code samples for this article can be found over on GitHub.