Quantcast
Channel: Baeldung
Viewing all articles
Browse latest Browse all 4535

Mapping Enum to String Using MapStruct

$
0
0

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.

       

Viewing all articles
Browse latest Browse all 4535

Trending Articles