简体   繁体   English

强制MapStruct使用自定义方法而不是dto值

[英]Force MapStruct to use custom method instead of dto value

I have a UserDTO and User entity which I want to map. 我有一个要映射的UserDTO和User实体。 When creating a new User some fields (for example: password , modifiedBy ) must be generated by some custom method (for example: password is randomly generated and encoded, but modifiedBy username is retrieved from security service). 创建新用户时,必须通过某些自定义方法来生成某些字段(例如: passwordmodifiedBy )(例如: password是随机生成和编码的,但是从安全服务中检索了modifiedBy用户名)。 For this I autowire some services into the mapper. 为此,我将一些服务自动连接到了映射器中。 Many of them return String and MapStruct cannot understand which one to use in each case and just uses the first it found on everything that accepts String as input. 它们中的许多返回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);
    }
}

This generates code that just uses method from PasswordEncoder in any setter that accepts String and getPass(...) method is not used at all. 这会生成仅使用接受任何String setter中的PasswordEncoder中的方法的代码,并且getPass(...)不使用getPass(...)方法。 However I need it to use my getPass(...) method on password field only. 但是我需要它仅在password字段上使用我的getPass(...)方法。

Currently it is not possible to pass the used mapper or service to a default method. 当前无法将使用的映射器或服务传递给默认方法。 There is mapstruct/mapstruct#1637 open for that. 为此打开了mapstruct / mapstruct#1637 Also you can't really do @Mapper( uses = PasswordEncoder.class ) as that would lead to all String to String to be mapped via the PasswordEncoder . 另外,您实际上不能做@Mapper( uses = PasswordEncoder.class )因为这将导致所有StringString都通过PasswordEncoder映射。 What you can do though is to create your own custom PasswordEncoderMapper and use @Named on it, this way you would be in control. 但是,您可以做的是创建自己的自定义PasswordEncoderMapper并在其上使用@Named ,这样您就可以控制自己。

This can look like this: 看起来可能像这样:

@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);
}

Regarding the modifiedBy property. 关于modifiedBy属性。 You should do that as part of an @ObjectFactory or by using an expression. 您应该将其作为@ObjectFactory一部分或通过使用表达式来执行。

With an expression this can look like: 使用表达式可以看起来像:

@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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM