Заставить MapStruct использовать пользовательский метод вместо значения dto - PullRequest
0 голосов
/ 21 января 2019

У меня есть сущность 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 в любом установщике, который принимает методы String и getPass(...), вообще не используется. Однако мне нужно использовать мой метод getPass(...) только для поля password.

1 Ответ

0 голосов
/ 21 января 2019

В настоящее время невозможно передать используемый маппер или сервис методу по умолчанию.Для этого есть mapstruct / mapstruct # 1637 .Также вы не можете сделать @Mapper( uses = PasswordEncoder.class ), так как это приведет к тому, что все String до String будут отображены через 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 собственности.Вы должны сделать это как часть @ObjectFactory или с помощью выражения.

С выражением это может выглядеть так:

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