繁体   English   中英

Mapstruct:如何通过@MappingTarget 使用自定义映射器

[英]Mapstruct: How to use custom mappers with @MappingTarget

我正在使用 Mapstruct,我需要使用@MappingTarget更新现有的 bean,但需要应用一些复杂的逻辑来设置目标中的正确字段。

可以说我有一个看起来像这样的目标 bean。 用户有一个帐户列表,其中一个帐户被标记为收藏。

UserDetails {
  String name;
  List<Account> accounts;
}

Account {
  String id;
  boolean favourite;
}

DTO 类包含他们最喜欢的帐户的帐户 ID。

UserDetialsDTO {
  String name;
  String favouriteAccountId;
  List<String> accountIds;
}

我需要使用一些复杂的逻辑来更新帐户列表中的正确Account

UserDetails fromDto(UserDetialsDTO dto, @MappingTarget UserDetails userDetails);

查找和更新正确Account以使其成为收藏夹的逻辑是这样的:

userDetails.accounts
           .stream()
           .forEach(acct -> acct.setFavourite(dto.favouriteAccountId.equals(acct.id))) ;

我如何告诉 Mapstruct 在更新@MapingTarget时使用此自定义逻辑?

尝试:

    @Mapper 
    public interface MyMapper {

         @Mapping( target = "accounts", ignore = true ) 
         void fromDto(UserDetialsDTO dto, @MappingTarget UserDetails userDetails);

         @AfterMapping
         default void handleAccounts(UserDetialsDTO dto, @MappingTarget UserDetails userDetails) {
             userDetails.accounts
               .stream()
               .forEach(acct -> acct.setFavourite(dto.favouriteAccountId.equals(acct.id))) ;
         }
    }

您可以使用装饰器来同时实现:

  • Account列表初始化
  • 最喜欢的自定义逻辑

如:

@Mapper
@DecoratedWith(MyMapperDecorator.class)
public interface MyMapper {
    void fromDto(UserDetialsDTO dto, @MappingTarget UserDetails userDetails);
}

public class MyMapperDecorator implements MyMapper{

    @Override
    public void fromDto(final UserDetialsDTO dto, final UserDetails userDetails) {
        if(dto == null){
            return;
        }

        dto.getAccountIds().forEach(a -> {
            final Account account = new Account();
            account.setId(a);
            account.setFavourite(a.equals(dto.getFavouriteAccountId()));
            userDetails.getAccounts().add(new Account());
        });

    }
}

为了避免重复,我建议使用Set<Account>而不是List并相应地实施Account.equals()

另一种(稍微)更复杂的方法可能涉及定义一个StringAccount映射器使用它:

@Mapper(uses = AccountMapper.class)
@DecoratedWith(MyMapperDecorator.class)
interface MyMapper {

    MyMapper INSTANCE = Mappers.getMapper( MyMapper.class );

    @Mapping(target = "accounts", source="accountIds")
    abstract void update(UserDetialsDTO dto, @MappingTarget UserDetails userDetails);

}

public abstract class MyMapperDecorator implements MyMapper{

    private final MyMapper delegate;

    MyMapperDecorator(final MyMapper delegate){
        this.delegate = delegate;
    }

    @Override
    public void update(final UserDetialsDTO dto, final UserDetails userDetails) {
        if(dto == null){
            return;
        }

        delegate.update(dto, userDetails);

        userDetails.accounts
                .stream()
                .forEach(acct -> acct.setFavourite(dto.favouriteAccountId.equals(acct.id))) ;

    }
}

@Mapper
public interface AccountMapper {
    Account fromString(String id);

    void update(String id, @MappingTarget Account account);
}

暂无
暂无

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

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