String Mapping with MapStruct
MapStruct is a compile-time code generator that simplifies the implementation of mappings between Java bean types. One common requirement in real-world applications is converting various data types—such as objects, enums, and dates—into String representations. Let us delve into understanding MapStruct string mapping in Java and how it simplifies transforming complex domain objects into DTO-friendly string representations.
1. Introduction to MapStruct
MapStruct is a compile-time, annotation-based Java framework designed to simplify object-to-object mapping. It automatically generates type-safe and high-performance mapper implementations, eliminating the need for reflection or complex runtime logic. By defining mapping rules declaratively through annotations, MapStruct helps developers reduce boilerplate code, improve maintainability, and catch mapping errors early during compilation. It is especially useful when converting between domain models and Data Transfer Objects (DTOs) in layered architectures.
1.1 Why Use MapStruct?
MapStruct provides a compile-time approach to object mapping, which makes it significantly faster and safer than reflection-based mapping frameworks. Since the mapper implementations are generated during compilation, there is no runtime overhead and mapping errors are detected early. Compared to manual mapping, MapStruct drastically reduces boilerplate code while keeping mappings explicit and readable. Unlike runtime mappers such as ModelMapper, MapStruct produces plain Java code that is easy to debug, test, and optimize, making it well-suited for high-performance and large-scale applications.
2. Code Example
This example demonstrates how to use MapStruct to map a domain model to a DTO while handling type conversions such as Long to String, enum to string, and date formatting. It highlights compile-time generated mappers with custom, null-safe conversions.
2.1 MapStruct Dependency
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>stable__jar__version</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>stable__jar__version</version>
<scope>provided</scope>
</dependency>
These dependencies enable MapStruct annotations and trigger the annotation processor during compilation, which generates the mapper implementation automatically. The processor dependency is marked as provided because it is only required at compile time and not at runtime.
2.2 Source Domain Model
// Person.java
import java.time.LocalDate;
public class Person {
private Long id;
private String name;
private Status status;
private LocalDate birthDate;
// getters and setters
}
This class represents the source domain model used within the application’s business layer. It defines a Person entity with strongly typed fields, including a Long identifier, a Status enum for representing state, and a LocalDate for date-safe birth date handling. Using domain-appropriate types (such as LocalDate instead of String) ensures type safety, clearer intent, and easier validation before the object is mapped to a DTO.
2.3 Status Enum Definition
// Status.java
public enum Status {
ACTIVE,
INACTIVE
}
This enum defines a fixed set of allowed values for a person’s status, preventing invalid states at compile time. Enums are commonly used in domain models to represent controlled vocabularies, and when mapped to DTOs they are often converted into strings for easier serialization, transport, or client-side compatibility.
2.4 Target Data Transfer Object (DTO)
// PersonDTO.java
public class PersonDTO {
private String id;
private String name;
private String status;
private String birthDate;
// getters and setters
}
The PersonDTO class represents the target data transfer object intended for external use, such as APIs or UI layers. All fields are defined as String values to simplify serialization formats like JSON and to decouple external consumers from internal domain types. This separation allows the internal model to evolve independently while keeping a stable external contract.
2.5 MapStruct Mapper Configuration
// PersonMapper.java
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
@Mapping(
source = "birthDate",
target = "birthDate",
dateFormat = "yyyy-MM-dd"
)
PersonDTO toDto(Person person);
// Null-safe Long → String
default String map(Long value) {
return value == null ? "N/A" : value.toString();
}
// Enum → String (custom)
default String map(Status status) {
return status == null ? "UNKNOWN" : status.name();
}
}
This MapStruct mapper defines how a Person entity is converted into a PersonDTO. The @Mapper annotation instructs MapStruct to generate the implementation at compile time, while the explicit @Mapping configuration formats the LocalDate into a standardized string. The default map methods provide custom, null-safe conversions for Long and Status, ensuring consistent string outputs and preventing null-related runtime issues during mapping.
2.6 Application Execution (Main Class)
// Application.java
import java.time.LocalDate;
public class Application {
public static void main(String[] args) {
Person person = new Person();
person.setId(1L);
person.setName("Alice");
person.setStatus(Status.ACTIVE);
person.setBirthDate(LocalDate.of(1995, 5, 20));
PersonDTO dto = PersonMapper.INSTANCE.toDto(person);
System.out.println(dto.getId());
System.out.println(dto.getName());
System.out.println(dto.getStatus());
System.out.println(dto.getBirthDate());
}
}
This class demonstrates the complete mapping flow in action. A Person object is instantiated and populated with domain data, then passed to the MapStruct-generated mapper to produce a PersonDTO. The printed output confirms that numeric, enum, and date fields have been correctly transformed into their string representations according to the defined mapping rules.
2.7 Code Execution and Output
$ mvn clean compile $ mvn exec:java -Dexec.mainClass="Application"
This command sequence compiles the project and executes the Application class. During compilation, MapStruct generates the concrete implementation of the PersonMapper interface. At runtime, the main method creates a Person object, invokes the mapper, and prints the mapped DTO fields to the console.
1 Alice ACTIVE 1995-05-20
The output confirms that the mapping was successful: the numeric Long ID is converted to a String, the enum value is mapped to its name, and the LocalDate is formatted according to the specified yyyy-MM-dd pattern. This verifies that both MapStruct’s automatic mappings and the custom conversion methods are functioning as intended.
3. Conclusion
Mapping to String in MapStruct is both powerful and flexible. Simple conversions work out of the box, while more advanced scenarios—such as enum handling, date formatting, and null safety—can be addressed using annotations and custom methods. By leveraging MapStruct’s compile-time generation, you get type safety, excellent performance, and clean, maintainable mapping code.

