How to Set Target Property Values to Null in MapStruct
In mapping scenarios, we may encounter situations where certain fields should be explicitly set to null during the mapping process, even when the source property has a non-null value. MapStruct provides ways to control how null values are handled for target properties. This article explores how to set null values intentionally for target properties in MapStruct.
1. Example Setup
MapStruct is a compile-time code generator that simplifies object mappings between Java beans. By default, MapStruct copies the value from the source to the target if it is not null, and ignores null source properties unless configured otherwise. However, sometimes we want to explicitly set a target property to null. For example:
- When mapping partial updates and applying specific null-handling logic.
- When updating an entity, and certain fields must be reset.
- When mapping between different layers and clearing sensitive or irrelevant data.
Here’s an example of two Java classes, a UserDto (source) and a User (target). Each time we update a User from UserDTO, we want to set the lastLoginIp field to null.
public class UserDTO {
private String username;
private String email;
public UserDTO() {
}
public UserDTO(String username, String email) {
this.username = username;
this.email = email;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "UserDTO{" + "username=" + username + ", email=" + email + '}';
}
}
public class User {
private String username;
private String email;
private String lastLoginIp;
public User() {
}
public User(String username, String email, String lastLoginIp) {
this.username = username;
this.email = email;
this.lastLoginIp = lastLoginIp;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getLastLoginIp() {
return lastLoginIp;
}
public void setLastLoginIp(String lastLoginIp) {
this.lastLoginIp = lastLoginIp;
}
@Override
public String toString() {
return "User{" + "username=" + username + ", email=" + email + ", lastLoginIp=" + lastLoginIp + '}';
}
}
2. Using @Mapping(target = "propertyName", expression = "java(null)")
If we always want the target property to be set to null when mapping, the simplest way is to use the expression attribute of the @Mapping annotation.
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
@Mapping(target = "lastLoginIp", expression = "java(null)")
void updateUser(UserDTO dto, @MappingTarget User user);
}
@MappingTarget allows updating an existing User object rather than creating a new one, and the expression java(null) ensures that the lastLoginIp field is explicitly set to null each time the mapper is used. We can check and test how the mapper works in practice:
public class MapstructNullDemo {
public static void main(String[] args) {
User user = new User();
user.setUsername("thomas");
user.setEmail("old@email.com");
user.setLastLoginIp("192.168.1.10");
UserDTO dto = new UserDTO();
dto.setUsername("thomas");
dto.setEmail("thomas@newmail.com");
// Perform the mapping
UserMapper.INSTANCE.updateUser(dto, user);
IO.println("Username: " + user.getUsername());
IO.println("Email: " + user.getEmail());
IO.println("Last Login IP: " + user.getLastLoginIp());
}
}
Output:
Username: thomas Email: thomas@newmail.com Last Login IP: null
If we want to set a property to null only under certain conditions, we can handle that using a default method or custom logic.
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
@Mapping(target = "email", expression = "java(mapEmail(dto.getEmail()))")
void updateUser(UserDTO dto, @MappingTarget User user);
default String mapEmail(String email) {
if (email != null && email.endsWith("@test.com")) {
return null; // Hide test emails
}
return email;
}
}
Here, the mapEmail() method defines conditional mapping logic. If the email ends with @test.com, the target property is explicitly set to null.
Testing the Mapper
Let’s test our mapper to verify the null-handling behavior:
public class MapstructNullDemo {
public static void main(String[] args) {
User user = new User();
user.setUsername("thomas");
user.setEmail("old@email.com");
user.setLastLoginIp("192.168.1.10");
UserDTO dto = new UserDTO();
dto.setUsername("thomas");
dto.setEmail("thomas@test.com");
UserMapper.INSTANCE.updateUser(dto, user);
IO.println("Username: " + user.getUsername());
IO.println("Email: " + user.getEmail());
IO.println("Last Login IP: " + user.getLastLoginIp());
}
}
Output:
Username: thomas Email: null Last Login IP: 192.168.1.10
3. Using @Mapping(target = "field", ignore = true) and @AfterMapping
Sometimes we might want to set the field to null after applying additional logic. We can ignore it in the main mapping and set it to null afterward using @AfterMapping.
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
@Mapping(target = "lastLoginIp", ignore = true)
void updateUser(UserDTO dto, @MappingTarget User user);
@AfterMapping
default void resetLoginIp(@MappingTarget User user) {
user.setLastLoginIp(null);
}
}
Using ignore = true prevents MapStruct from automatically mapping lastLoginIp, and the @AfterMapping method runs immediately after the update, allowing us to reset or modify specific fields. We can even add conditional logic here, for example, to set the field to null only under certain conditions.
4. Using NullValuePropertyMappingStrategy.SET_TO_NULL
The NullValuePropertyMappingStrategy lets us define how MapStruct behaves when source fields are null. Setting the strategy to SET_TO_NULL ensures that any null value in the DTO will nullify the target property.
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_NULL)
@Mapping(target = "lastLoginIp", expression = "java(null)")
void updateUser(UserDTO dto, @MappingTarget User user);
}
SET_TO_NULLensures that whenever a source property isnull, the corresponding target property will also be set tonull.- Other available strategies include:
IGNORE: Leaves the target property unchanged if the source isnull(default behavior).SET_TO_DEFAULT: Sets the property to its default value (e.g.,0for primitives,falsefor booleans).
Let’s test our mapper to verify the null-handling behavior:
public class MapstructNullDemo {
public static void main(String[] args) {
User user = new User();
user.setUsername("thomas");
user.setEmail("old@email.com");
user.setLastLoginIp("192.168.1.10");
UserDTO dto = new UserDTO();
dto.setUsername("thomas");
dto.setEmail(null); // this should nullify the User's email
UserMapper.INSTANCE.updateUser(dto, user);
IO.println("Username: " + user.getUsername());
IO.println("Email: " + user.getEmail()); // null
IO.println("Last Login IP: " + user.getLastLoginIp());
}
}
Output:
Username: thomas Email: null Last Login IP: null
This approach is ideal when we want null values in the DTO to clear corresponding entity fields during updates.
5. Conclusion
In this article, we learned how to set a target property to null when updating an entity from a DTO using MapStruct. We explored three strategies: using expression = "java(null)" to always set a field to null, using ignore = true with @AfterMapping for more flexible post-processing, and using NullValuePropertyMappingStrategy.SET_TO_NULL to automatically propagate null values during mapping.
6. Download the Source Code
This article explored how to use Java MapStruct to set a null value for a specific property.
You can download the full source code of this example here: java mapstruct set null value property

