首页 > 解决方案 > 强制 MapStruct 使用自定义方法而不是 dto 值

问题描述

我有一个要映射的 UserDTO 和 User 实体。创建新用户时,某些字段(例如:password, modifiedBy)必须通过某种自定义方法生成(例如:password随机生成和编码,但modifiedBy用户名是从安全服务中检索的)。为此,我将一些服务自动连接到映射器中。它们中的许多返回String并且 MapStruct 无法理解在每种情况下使用哪个,而只是使用它在所有接受String作为输入的东西上找到的第一个。

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

@Mapping(target = "password", qualifiedByName = "PASS")
User mapUser(UserDto dto);

@Named("PASS")
default String getPass(PasswordEncoder passwordEncoder){
    return passwordEncoder.encode(some_random_generator);
    }
}

这会生成仅使用PasswordEncoder任何接受的 setter 中的方法的代码,String并且getPass(...)根本不使用方法。但是我需要它只在现场使用我的getPass(...)方法。password

标签: javaspring-bootmapstruct

解决方案


目前无法将使用的映射器或服务传递给默认方法。为此打开了mapstruct /mapstruct#1637。你也不能真正这样做@Mapper( uses = PasswordEncoder.class ),因为这会导致所有内容StringString通过PasswordEncoder. 但是,您可以做的是创建自己的自定义PasswordEncoderMapper@Named在其上使用,这样您就可以控制。

这看起来像这样:

@Qualifier // org.mapstruct.Qualifier
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface EncodedMapping {
}

public class PasswordEncoderMapper {

    protected final PasswordEncoder passwordEncoder;

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

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

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

    @Mapping(target = "password", qualifiedBy = EncodedMapping.class)
    User mapUser(UserDto dto);
}

关于modifiedBy财产。您应该将其作为@ObjectFactoryor 的一部分使用表达式。

使用表达式可以如下所示:

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

    @Mapping(target = "password", qualifiedBy = EncodedMapping.class)
    @Mapping(target = "modifiedBy", expression = "java(SecurityUtils.getCurrentUserId())")
    User mapUser(UserDto dto);
}

推荐阅读