防止更新时在 Mapstruct 中进行空检查
Prevent null check in Mapstruct on update
我正在努力更新表单。请考虑这个例子:
// Entity with which I need to perform CRUD operations
public class User {
private String name;
private String email;
private String phone;
private String address;
}
我发送给UI的是UserDTO:
public class UserDTO {
private String name;
private ContactDataDTO contactDataDTO;
}
public class ContactDataDTO {
private String email;
private String phone;
private String address;
}
我的映射器:
@Mapper
public interface UserMapper {
@Mappings({
@Mapping(source="email", target="contactDataDTO.email"),
@Mapping(source="phone", target="contactDataDTO.phone"),
@Mapping(source="address", target="contactDataDTO.address")
})
UserDTO userToUserDTO(User user);
@InheritInverseConfiguration
User updateUserFromUserDTO(UserDTO userDTO, @MappingTarget User user);
}
userToUserDTO() 按预期工作,但生成的 userDTOToUser() 对我来说似乎很奇怪:
@Override
public User updateUserFromUserDTO(UserDTO userDTO, User user) {
if ( userDTO == null ) {
return null;
}
String address = userDTOContactDataDTOAddress( userDTO );
if ( address != null ) {
user.setAddress( address );
}
String phone = userDTOContactDataDTOPhone( userDTO );
if ( phone != null ) {
user.setPhone( phone );
}
String email = userDTOContactDataDTOEmail( userDTO );
if ( email != null ) {
user.setEmail( email );
}
user.setName( userDTO.getName() );
return user;
}
有问题的用例:
- 填写用户的所有字段。
- 再次打开表单并清除 phone 字段。
- 这意味着我将像这样向后端发送:
userDTO: {
name: 'John Doe';
contactDataDTO: {
email: 'johndoe@gmail.com',
phone: null,
address: 'Home'
}
}
所以,user.phone 不会更新,因为我在生成的代码中对它进行了空检查。
我认为 NullValueCheckStrategy 是我需要的,但是没有适合我的选项。
目前,我看到的唯一选择是编写自己的 userDTOToUser() 实现,不进行空值检查。
也许您可以建议更好的解决方案,因为对我来说,从具有非原始源的 DTO 进行目标更新的任何映射器中都可能发生这个问题。
可运行演示:https://repl.it/@aksankin/SlateblueUnimportantStack
非常感谢。
可能 Optional<> 就是您要搜索的内容。在这种情况下,空字段为 null,如果 null 是从 UI 发送的,则为 Optional;对于实际值,则为 Optional。但是您可能需要为请求和响应创建不同的 DTO。
如果您希望 null
对您有一定的价值,那么您正在寻找 source presence checking。然后,您可以在 DTO 的 setPhone
中控制它是否已设置,并添加将使用该标志的 hasPhone
。那么MapStruct在设置值的时候会使用存在性检查的方式。
尝试:
@Mapper( )
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper( UserMapper.class );
@Mappings({
@Mapping(source="email", target="contactDataDTO.email"),
@Mapping(source="phone", target="contactDataDTO.phone"),
@Mapping(source="address", target="contactDataDTO.address")
})
UserDTO userToUserDTO(User user);
default void updateUserFromUserDTO(UserDTO userDTO, User user) {
intUpdateUserFromUserDTO( userDTO, userDTO.getContactDataDTO(), user );
}
void intUpdateUserFromUserDTO(UserDTO userDTO, ContactDataDTO contactDataDTO, @MappingTarget User user);
}
(注意:我返回的是void isa类型,严格来说不需要)
我正在努力更新表单。请考虑这个例子:
// Entity with which I need to perform CRUD operations
public class User {
private String name;
private String email;
private String phone;
private String address;
}
我发送给UI的是UserDTO:
public class UserDTO {
private String name;
private ContactDataDTO contactDataDTO;
}
public class ContactDataDTO {
private String email;
private String phone;
private String address;
}
我的映射器:
@Mapper
public interface UserMapper {
@Mappings({
@Mapping(source="email", target="contactDataDTO.email"),
@Mapping(source="phone", target="contactDataDTO.phone"),
@Mapping(source="address", target="contactDataDTO.address")
})
UserDTO userToUserDTO(User user);
@InheritInverseConfiguration
User updateUserFromUserDTO(UserDTO userDTO, @MappingTarget User user);
}
userToUserDTO() 按预期工作,但生成的 userDTOToUser() 对我来说似乎很奇怪:
@Override
public User updateUserFromUserDTO(UserDTO userDTO, User user) {
if ( userDTO == null ) {
return null;
}
String address = userDTOContactDataDTOAddress( userDTO );
if ( address != null ) {
user.setAddress( address );
}
String phone = userDTOContactDataDTOPhone( userDTO );
if ( phone != null ) {
user.setPhone( phone );
}
String email = userDTOContactDataDTOEmail( userDTO );
if ( email != null ) {
user.setEmail( email );
}
user.setName( userDTO.getName() );
return user;
}
有问题的用例:
- 填写用户的所有字段。
- 再次打开表单并清除 phone 字段。
- 这意味着我将像这样向后端发送:
userDTO: {
name: 'John Doe';
contactDataDTO: {
email: 'johndoe@gmail.com',
phone: null,
address: 'Home'
}
}
所以,user.phone 不会更新,因为我在生成的代码中对它进行了空检查。
我认为 NullValueCheckStrategy 是我需要的,但是没有适合我的选项。 目前,我看到的唯一选择是编写自己的 userDTOToUser() 实现,不进行空值检查。 也许您可以建议更好的解决方案,因为对我来说,从具有非原始源的 DTO 进行目标更新的任何映射器中都可能发生这个问题。
可运行演示:https://repl.it/@aksankin/SlateblueUnimportantStack
非常感谢。
可能 Optional<> 就是您要搜索的内容。在这种情况下,空字段为 null,如果 null 是从 UI 发送的,则为 Optional;对于实际值,则为 Optional。但是您可能需要为请求和响应创建不同的 DTO。
如果您希望 null
对您有一定的价值,那么您正在寻找 source presence checking。然后,您可以在 DTO 的 setPhone
中控制它是否已设置,并添加将使用该标志的 hasPhone
。那么MapStruct在设置值的时候会使用存在性检查的方式。
尝试:
@Mapper( )
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper( UserMapper.class );
@Mappings({
@Mapping(source="email", target="contactDataDTO.email"),
@Mapping(source="phone", target="contactDataDTO.phone"),
@Mapping(source="address", target="contactDataDTO.address")
})
UserDTO userToUserDTO(User user);
default void updateUserFromUserDTO(UserDTO userDTO, User user) {
intUpdateUserFromUserDTO( userDTO, userDTO.getContactDataDTO(), user );
}
void intUpdateUserFromUserDTO(UserDTO userDTO, ContactDataDTO contactDataDTO, @MappingTarget User user);
}
(注意:我返回的是void isa类型,严格来说不需要)