Mastering Object Mapping in Spring Boot with @Mapper and @Mapping
In Spring Boot, if you’re working with data transfer objects (DTOs) or entity mapping between layers (e.g., between service and persistence layers), using a mapping framework like MapStruct can be helpful. The @Mapper
and @Mapping
annotations are part of MapStruct, a code generator that simplifies the process of mapping between Java objects.
Key Concepts of MapStruct:
- @Mapper:
This annotation is applied to an interface or abstract class. It indicates that this interface is a Mapper, and the MapStruct processor will automatically generate an implementation for it.
@Mapper
public interface UserMapper {
UserDTO toDto(User entity);
User toEntity(UserDTO dto);
}
In this example, UserMapper
is a mapper interface that will map a User
entity to UserDTO
and vice versa.
@Mapping:
This annotation is used inside a Mapper interface when you want to explicitly define how fields in one object map to fields in another. It is used when the fields don’t have a direct match or if additional logic is required.
@Mapper
public interface UserMapper {
@Mapping(source = "name", target = "fullName")
@Mapping(source = "address.street", target = "streetName")
UserDTO toDto(User entity);
@Mapping(source = "fullName", target = "name")
@Mapping(source = "streetName", target = "address.street")
User toEntity(UserDTO dto);
}
In this case, @Mapping
explicitly tells MapStruct how to map fields that don't have the same names (name
to fullName
and address.street
to streetName
).
Example Use Case:
Suppose you have the following classes:
Entity Class:
public class User {
private String name;
private Address address;
// Getters and Setters
}
public class Address {
private String street;
private String city;
// Getters and Setters
}
DTO Class:
public class UserDTO {
private String fullName;
private String streetName;
// Getters and Setters
}
Mapper Interface with MapStruct:
@Mapper
public interface UserMapper {
@Mapping(source = "name", target = "fullName")
@Mapping(source = "address.street", target = "streetName")
UserDTO toDto(User user);
@Mapping(source = "fullName", target = "name")
@Mapping(source = "streetName", target = "address.street")
User toEntity(UserDTO userDTO);
}
How it works:
- The
@Mapper
tells MapStruct to create an implementation of this interface. - The
@Mapping
annotation explicitly defines how to map fields from the source object to the target object. - MapStruct automatically generates the code needed to map between
User
andUserDTO
.
Configuration in Spring Boot:
- Add the MapStruct dependency in your
pom.xml
:
<dependencies> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>1.5.0.Final</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.5.0.Final</version> <scope>provided</scope> </dependency> </dependencies>
- Enable the MapStruct processor in Spring Boot. You don’t have to do anything special for Spring Boot if you use Maven or Gradle. MapStruct automatically integrates into the build process.
- Inject the Mapper into your service layer using Spring’s
@Autowired
or constructor injection:
@Service public class UserService { private final UserMapper userMapper; @Autowired public UserService(UserMapper userMapper) { this.userMapper = userMapper; } public UserDTO getUserDto(User user) { return userMapper.toDto(user); } }
This is how @Mapper
and @Mapping
annotations work in Spring Boot using MapStruct for object mapping.