eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Partner – LambdaTest – NPI EA (cat=Testing)
announcement - icon

Regression testing is an important step in the release process, to ensure that new code doesn't break the existing functionality. As the codebase evolves, we want to run these tests frequently to help catch any issues early on.

The best way to ensure these tests run frequently on an automated basis is, of course, to include them in the CI/CD pipeline. This way, the regression tests will execute automatically whenever we commit code to the repository.

In this tutorial, we'll see how to create regression tests using Selenium, and then include them in our pipeline using GitHub Actions:, to be run on the LambdaTest cloud grid:

>> How to Run Selenium Regression Tests With GitHub Actions

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

1. Overview

Enumerations, or enums, are a powerful and widely used feature in the Java programming language. In certain scenarios, we may need to convert one enum type to another. This requirement could arise when we are integrating different libraries or frameworks, utilizing microservices from different platforms, or working with legacy code that is challenging to update.

In this article, we’ll explore different techniques for mapping or converting one enum to another in Java. We’ll examine both built-in mechanisms and external libraries that can assist.

2. Defining the Model

When it comes to converting enums, we can encounter two main cases where different implementation techniques can be used. The first case involves unrelated enums with different sets of values. The second case involves enums with the same values but representing different classes from a Java perspective. We cannot simply cast instances of such classes and still need to perform a mapping.

To illustrate these techniques, let’s define two data models. The first model represents a scenario where the enums have the same values:

public enum OrderStatus {
    PENDING, APPROVED, PACKED, DELIVERED;
}
public enum CmsOrderStatus {
    PENDING, APPROVED, PACKED, DELIVERED;
}

And the second model represents a scenario where the enums have different values:

public enum UserStatus {
    PENDING, ACTIVE, BLOCKED, INACTIVATED_BY_SYSTEM, DELETED;
}
public enum ExternalUserStatus {
    ACTIVE, INACTIVE
}

3. Using Java Core

Most enum conversions can be achieved using the core capabilities of the Java language without the need for external libraries.

3.1. Using Switch

One of the most straightforward options is to use the switch mechanism. By creating proper conditions for each enum constant, we can determine the corresponding converted value. The syntax of switch statements has evolved with different Java versions. Depending on the project’s Java version, the switch can be implemented differently.

Starting from Java 12, a new switch feature was introduced, including switch expressions and multiple case values. This allows us to directly return the result of the switch and combine multiple values into a single case. Java 12 has a preview version of this feature (we can use it, but additional configuration is needed), whereas a permanent version is available from Java 14.

Let’s see an implementation example:

public ExternalUserStatus toExternalUserStatusViaSwitchStatement() {
    return switch (this) {
        case PENDING, BLOCKED, INACTIVATED_BY_SYSTEM, DELETED -> ExternalUserStatus.INACTIVE;
        case ACTIVE -> ExternalUserStatus.ACTIVE;
    };
}

However, a plain switch statement can still be used with an older version of Java:

public ExternalUserStatus toExternalUserStatusViaRegularSwitch() {
    switch (this) {
    case PENDING:
    case BLOCKED:
    case INACTIVATED_BY_SYSTEM:
    case DELETED:
        return ExternalUserStatus.INACTIVE;
    case ACTIVE:
        return ExternalUserStatus.ACTIVE;
    }
    return null;
}

The test snippet below demonstrates how this works:

@Test
void whenUsingSwitchStatement_thenEnumConverted() {
    UserStatus userStatusDeleted = UserStatus.DELETED;
    UserStatus userStatusPending = UserStatus.PENDING;
    UserStatus userStatusActive = UserStatus.ACTIVE;

    assertEquals(ExternalUserStatus.INACTIVE, userStatusDeleted.toExternalUserStatusViaSwitchStatement());
    assertEquals(ExternalUserStatus.INACTIVE, userStatusPending.toExternalUserStatusViaSwitchStatement());
    assertEquals(ExternalUserStatus.ACTIVE, userStatusActive.toExternalUserStatusViaSwitchStatement());
}

@Test
void whenUsingSwitch_thenEnumConverted() {
    UserStatus userStatusDeleted = UserStatus.DELETED;
    UserStatus userStatusPending = UserStatus.PENDING;
    UserStatus userStatusActive = UserStatus.ACTIVE;

    assertEquals(ExternalUserStatus.INACTIVE, userStatusDeleted.toExternalUserStatusViaRegularSwitch());
    assertEquals(ExternalUserStatus.INACTIVE, userStatusPending.toExternalUserStatusViaRegularSwitch());
    assertEquals(ExternalUserStatus.ACTIVE, userStatusActive.toExternalUserStatusViaRegularSwitch());
}

It’s worth mentioning that this conversion logic doesn’t necessarily need to reside in the enum class itself, but it’s better to encapsulate the logic if possible.

3.2. Using Member Variables

Another way to convert enums is to leverage the possibility of defining fields inside enums. By specifying an externalUserStatus field in UserStatus and providing the desired value in the constant declaration, we can define an explicit mapping for each enum value. In this approach, the conversion method returns the externalUserStatus value.

The UserStatus definition will look like this:

public enum UserStatusWithFieldVariable {
    PENDING(ExternalUserStatus.INACTIVE),
    ACTIVE(ExternalUserStatus.ACTIVE),
    BLOCKED(ExternalUserStatus.INACTIVE),
    INACTIVATED_BY_SYSTEM(ExternalUserStatus.INACTIVE),
    DELETED(ExternalUserStatus.INACTIVE);

    private final ExternalUserStatus externalUserStatus;

    UserStatusWithFieldVariable(ExternalUserStatus externalUserStatus) {
        this.externalUserStatus = externalUserStatus;
    }
}

And conversion method will return the externalUserStatus value:

public ExternalUserStatus toExternalUserStatus() {
    return externalUserStatus;
}

3.3. Using EnumMap

The methods described above works well for all kind of enums that can be modified. However, in situations where we cannot update the source code or prefer to keep the conversion logic outside of the enum itself, the EnumMap class can be useful.

EnumMap will help us to make independent mapping:

public class UserStatusMapper {
    public static EnumMap<UserStatus, ExternalUserStatus> statusesMap;
    static {
        statusesMap = new EnumMap<>(UserStatus.class);
        statusesMap.put(UserStatus.PENDING, ExternalUserStatus.INACTIVE);
        statusesMap.put(UserStatus.BLOCKED, ExternalUserStatus.INACTIVE);
        statusesMap.put(UserStatus.DELETED, ExternalUserStatus.INACTIVE);
        statusesMap.put(UserStatus.INACTIVATED_BY_SYSTEM, ExternalUserStatus.INACTIVE);
        statusesMap.put(UserStatus.ACTIVE, ExternalUserStatus.ACTIVE);
    }
}

EnumMap is specifically optimized for use with enums as map keys, and it’s better to avoid using other types of maps.

3.4. Using Enum Name

When converting between enums with the same values, we can rely on the valueOf() method provided by Java. This method returns the enum value based on the provided enum name. However, it’s important to note that the provided name must exactly match the identifier used to declare the enum constant. If the provided name isn’t found among the declared constants, an IllegalArgumentException will be thrown.

It’s important to use the enum name approach with caution, especially when working with enums from external libraries or services that are beyond our control. Mismatches between the two enums can lead to runtime errors and can potentially break the service.

To show explained approach, we’ll use OrderStatus and CmsOrderStatus entities:

public CmsOrderStatus toCmsOrderStatus() {
    return CmsOrderStatus.valueOf(this.name());
}

3.5. Using Ordinal Approach

The ordinal approach is an interesting but tricky technique that relies on the internal implementation of enums. Internally, enums are represented as an array of constants, allowing us to iterate through the values and access them using indices.

Let’s see how we can use ordinal() functionality to convert OrderStatus to CmsOrderStatus:

public CmsOrderStatus toCmsOrderStatusOrdinal() {
    return CmsOrderStatus.values()[this.ordinal()];
}

And test shows the usage:

@Test
void whenUsingOrdinalApproach_thenEnumConverted() {
    OrderStatus orderStatusApproved = OrderStatus.APPROVED;
    OrderStatus orderStatusDelivered = OrderStatus.DELIVERED;
    OrderStatus orderStatusPending = OrderStatus.PENDING;

    assertEquals(CmsOrderStatus.APPROVED, orderStatusApproved.toCmsOrderStatusOrdinal());
    assertEquals(CmsOrderStatus.DELIVERED, orderStatusDelivered.toCmsOrderStatusOrdinal());
    assertEquals(CmsOrderStatus.PENDING, orderStatusPending.toCmsOrderStatusOrdinal());
}

It’s important to note that the ordinal approach has its limitations. It may not show any issues during compilation, but it’s prone to runtime failures when enums become incompatible in terms of sizes. Even if the sizes of the enums remain compatible, changes in their values or indexing can result in erroneous and inconsistent behavior.

Although the ordinal approach is suitable for certain scenarios, it’s generally advisable to use more stable methods. As stated in the Java documentation:

the ordinal approach is primarily designed for use in sophisticated enum-based data structures such as java.util.EnumSet and java.util.EnumMap.

4. Using MapStruct

MapStruct is a popular library used for mapping between entities, and it also can be useful for enum conversions.

4.1. Maven Dependency

Let’s add the MapStruct dependency to our pom.xml. We need the MapStruct library as a dependency and MapStruct Processor as an annotation processor:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.5.1</version>
    <configuration>
        <source>17</source>
        <target>17</target>
        <annotationProcessorPaths>
            <path>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>1.5.5.Final</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

We can find the latest versions of MapStruct and its processor in the Maven Central repository.

4.2. Usage

MapStruct generates implementation based on annotations defined in an interface. We can use this lib in both cases when enum values are completely different, as well as in the case when values are the same. If no specific mapping is specified, MapStruct automatically tries to map based on a match between constants’ names. At the same time, we can configure the explicit mapping between values in our enums. With the newer MapStruct version, we should use @ValueMapping for enums instead of @Mapping.

Considering our model, mapping for OrderStatus and CmsOrderStatus can be defined without any manual mapping. Mapping between UserStatus and ExternalUserStatus requires additional configuration where enum names don’t match:

@Mapper
public interface EnumMapper {

    CmsOrderStatus map(OrderStatus orderStatus);

    @ValueMapping(source = "PENDING", target = "INACTIVE")
    @ValueMapping(source = "BLOCKED", target = "INACTIVE")
    @ValueMapping(source = "INACTIVATED_BY_SYSTEM", target = "INACTIVE")
    @ValueMapping(source = "DELETED", target = "INACTIVE")
    ExternalUserStatus map(UserStatus userStatus);
}

At the same time, mapping for UserStatus.ACTIVE and ExternalUserStatus.ACTIVE will be generated automatically.

Apart from that, we can utilize MappingConstants.ANY_REMAINING feature that will put default value (in our case ExternalUserStatus.INACTIVE) for an enum constant that is not yet mapped at the end of mapping:

@ValueMapping(source = MappingConstants.ANY_REMAINING, target = "INACTIVE")
ExternalUserStatus mapDefault(UserStatus userStatus);

5. Best Practices and Use Cases

The choice of a suitable conversion strategy depends on the specific requirements of a project. Factors such as the similarity between enum constants, access to the source code, and how often the enums may change should be considered.

When we have access to the enum’s source code, the switch and member variables approaches are recommended. These approaches allow us to encapsulate the conversion logic in a single location, providing better code organization. Additionally, the switch approach can be extended to use some external properties and perform more complex mapping logic. However, it’s important to note that using the switch approach can lead to lengthy and difficult-to-manage code in scenarios with heavy conditions and huge enums.

When we don’t have access to the source code or want to clearly visualize the mapping without lengthy switch statements, the EnumMap approach is a good option. EnumMap allows us to define explicit mappings between enums without the need for extensive switch statements. It’s particularly useful when the conversion logic is straightforward.

The enum name approach should only be used when the source and target enum names are identical. In cases where there might be a name mismatch, it’s preferable to extend the mapping method by incorporating additional logic and defining default behavior. This ensures that the conversion can gracefully handle mismatches and unexpected situations.

The ordinal approach, while useful in scenarios where mapping logic is based on indexing, should generally be avoided due to its inherent risks. Both the enum name and ordinal approaches require a resilient implementation to account for changes in enum sizes or values.

Alternatively, to avoid maintaining complex switch statements or maps, MapStruct can be used to automate the process. It can handle both enums with identical names and those with completely different names, allowing us to define additional mapping logic and default behaviors.

Regardless of the chosen approach, it’s crucial to update the mappings as soon as the enums are changed. If updating the mappings is not feasible, ensure that the code is designed to handle enum changes appropriately, either by falling back to default mapping values or by gracefully handling new enum values as they arise. This approach ensures the longevity and stability of enum conversions.

6. Conclusion

In this article, we explored various techniques for mapping enums in Java. We discussed both built-in mechanisms and the use of MapStruct. Depending on specific use cases and requirements, different techniques may be more suitable than others. It’s recommended to consider multiple factors when choosing a conversion strategy, such as the similarity between enum constants, access to source code, and the potential for enum changes.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – LS – NPI (cat=Java)
announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)
1 Comment
Oldest
Newest
Inline Feedbacks
View all comments