具有条件和 nullValuePropertyMappingStrategy 的 Mapstruct 映射

Mapstruct mapping with condition and nullValuePropertyMappingStrategy

如果标题不清楚,我很抱歉,让我通过示例代码说清楚:

UpdateProfileDto

public class UpdateProfileDto {

    @NotEmpty
    private String firstName;

    @NotEmpty
    private String lastName;

    @Size(max = 20)
    private String currentPassword;

    @Size(max = 20)
    private String newPassword;

    @Size(max = 20)
    private String confirmNewPassword;

    // getters and setters
}

编码映射

@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface EncodedMapping {
}

PasswordEncoderMapper

public class PasswordEncoderMapper {
    protected final PasswordEncoder passwordEncoder;

    public PasswordEncoderMapper(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @EncodedMapping
    public String encode(String value) {
        return passwordEncoder.encode(value);
    }
}

UserMapper

@Mapper(config = MapperConfig.class, componentModel = "spring", uses = PasswordEncoderMapper.class)
public interface UserMapper {

    @Mappings({
            @Mapping(target = "firstName", source = "firstName"),
            @Mapping(target = "lastName", source = "lastName"),
            @Mapping(target = "fullName", expression = "java(user.getFirstName() + \" \" + user.getLastName())"),
            @Mapping(target = "password",
                    source = "newPassword",
                    nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE,
                    qualifiedBy = EncodedMapping.class)
    })
    void updateUserFromDto(UpdateUserProfileDto updateUserProfileDto, @MappingTarget User user);
}

生成的 UserMapperImpl

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2020-03-11T13:51:34+0800",
    comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_231 (Oracle Corporation)"
)
@Component
public class UserMapperImpl implements UserMapper {

    @Autowired
    private PasswordEncoderMapper passwordEncoderMapper;

    @Override
    public void updateUserFromDto(UpdateUserProfileDto updateUserProfileDto, User user) {
        if ( updateUserProfileDto == null ) {
            return;
        }

        if ( updateUserProfileDto.getFirstName() != null ) {
            user.setFirstName( updateUserProfileDto.getFirstName() );
        }
        else {
            user.setFirstName( null );
        }
        if ( updateUserProfileDto.getLastName() != null ) {
            user.setLastName( updateUserProfileDto.getLastName() );
        }
        else {
            user.setLastName( null );
        }
        if ( updateUserProfileDto.getNewPassword() != null ) {
            user.setPassword( passwordEncoderMapper.encode( updateUserProfileDto.getNewPassword() ) );
        }

        user.setFullName( user.getFirstName() + " " + user.getLastName() );
    }
}

从生成的 UserMapperImpl 中,我不仅要检查 newPassword 是否具有值...还要检查 currentPasswordnewPassword 是否具有值并继续user.setPassword().

我的意思是这样的:

...
if ( updateUserProfileDto.getCurrentPassword() != null && updateUserProfileDto.getNewPassword() != null ) {
    user.setPassword( passwordEncoderMapper.encode( updateUserProfileDto.getNewPassword() ) );
}
...

问题

如何更改我的映射器接口 UserMapper 以便在设置目标 user.password 之前检查 currentPasswordnewPassword 并且仍将使用 PasswordEncoderMapper.encode(password)?

如果我尝试使用 expression 而不是 source 并检查 currentPasswordnewPassword 是否都有值,然后将 user.password 设置为 newPassword。否则,它不会对 user.passwordusing NullValuePropertyMappingStrategy 做任何事情......但似乎不允许混合 expressionNullValuePropertyMappingStrategy.

谢谢!

我将从以下方法开始

@Mapper(config = MapperConfig.class, componentModel = "spring")
public abstract class UserMapper { // using class instead of interface to be able to inject beans

    @Autowired
    private PasswordEncoderMapper passwordEncoderMapper;

    @Mappings({
            // your non-password mappings
    })
    void updateUserFromDto(UpdateUserProfileDto updateUserProfileDto, @MappingTarget User user);


    @AfterMapping
    void setPassword(UpdateUserProfileDto updateUserProfileDto, @MappingTarget User user) {
        if (updateUserProfileDto.getCurrentPassword() != null && updateUserProfileDto.getNewPassword() != null) {
            user.setPassword(passwordEncoderMapper.encode( updateUserProfileDto.getNewPassword()));
        }
    }
}