简体   繁体   English

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

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

I am using Mapstruct and I need to update an existing bean using @MappingTarget , but need to apply some complex logic to set the correct field in the target.我正在使用 Mapstruct,我需要使用@MappingTarget更新现有的 bean,但需要应用一些复杂的逻辑来设置目标中的正确字段。

Lets say I have a target bean that looks like this.可以说我有一个看起来像这样的目标 bean。 A user has a list of accounts, and one of those accounts is marked as favourite.用户有一个帐户列表,其中一个帐户被标记为收藏。

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

Account {
  String id;
  boolean favourite;
}

The DTO class contains the account ID of their favourite account. DTO 类包含他们最喜欢的帐户的帐户 ID。

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

I need to use some complex logic to update the correct Account in the list of accounts.我需要使用一些复杂的逻辑来更新帐户列表中的正确Account

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

The logic of finding and updating the correct Account to make it favourite is something like this:查找和更新正确Account以使其成为收藏夹的逻辑是这样的:

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

How can I tell Mapstruct to use this custom logic when updating a @MapingTarget ?我如何告诉 Mapstruct 在更新@MapingTarget时使用此自定义逻辑?

try:尝试:

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

You can use a decorator , to implement both:您可以使用装饰器来同时实现:

  • initialization of Account list Account列表初始化
  • favorite custom logic最喜欢的自定义逻辑

such as:如:

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

    }
}

In order to avoid duplicates I would suggest to use Set<Account> instead of List and implement Account.equals() accordingly.为了避免重复,我建议使用Set<Account>而不是List并相应地实施Account.equals()

An alternative (sligtly) more sophisticated approach could involve defining a String to Account mapper use it:另一种(稍微)更复杂的方法可能涉及定义一个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.

相关问题 MapStruct @MappingTarget 生成一个空方法 - MapStruct @MappingTarget generates an empty method 是否可以在 mapstruct 中从 Object 进行映射目标 Map? - is it possitble to do mappingTarget Map from Object in mapstruct? 如何让Eclipse使用Gradle生成MapStruct Mappers - How to get Eclipse to generate MapStruct Mappers using Gradle 如何测试在 Springboot 中使用 Mapstruct 映射器的服务 class 方法? - How to test Service class methods which uses Mapstruct mappers in Springboot? 如何在嵌套 Mapstruct 映射器中的模糊映射方法中指定 select? - How to specify select among ambiguous mapping methods in nested Mapstruct mappers? 不使用 MapStruct 中的 Setter 是否可以达到与 @MappingTarget 相同的效果? - Is it possible to achieve the same effect as @MappingTarget without using a Setter in MapStruct? 带有@MappingTarget 的 Mapstruct 不调用 lombok Builder build() - Mapstruct with @MappingTarget don't call lombok Builder build() 如何使 mapstruct 映射器返回 null 而不是所有字段设置为 null 的新对象 - How to make mapstruct mappers return null instead of new objects with all fields set to null Mapstruct mappers diamond inheritance,方法已定义 - Mapstruct mappers diamond inheritance, method is already defined 如何告诉MapReduce使用多少个映射器? - How to tell MapReduce how many mappers to use?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM