简体   繁体   English

我可以扩展 MapStruct 方法吗?

[英]Can I extend MapStruct methods?

I'm developing a library and I expect the library to have a mapper like so:我正在开发一个图书馆,我希望图书馆有一个像这样的映射器:

import org.mapstruct.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import spring.graphql.rest.rql.core.nodes.PropertyNode;
import spring.graphql.rest.rql.core.nodes.TraversalMapper;
import spring.graphql.rest.rql.example.dto.AccountDto;
import spring.graphql.rest.rql.example.models.Account;

import java.util.*;

@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
        nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, uses = {TraversalMapper.class})
public abstract class AccountMapper {

    @Autowired
    @Qualifier("accountMapperImpl")
    protected AccountMapper accountMapper;

    @Autowired
    protected PostMapper postMapper;

    @Autowired
    protected PersonMapper personMapper;

    @Autowired
    protected CommentMapper commentMapper;

    @IterableMapping(qualifiedByName = "dynamicAccounts")
    public abstract Set<AccountDto> rqlToAccountDtos(Set<Account> entity, @Context StringBuilder currentPath, @Context List<PropertyNode> propertyNodes, @Context List<String> properties, @Context String property);

    // TODO: Implement automatic generation/addition of these mappers
    @Named("dynamicAccounts")
    @Mapping(target = "friends", expression = "java(properties.contains(\"friends\") ? accountMapper.rqlToAccountDtos(entity.getFriends(), currentPath, propertyNodes, properties, \"friends\") : null)")
    @Mapping(target = "posts", expression = "java(properties.contains(\"posts\") ? postMapper.toPostDtos(entity.getPosts(), currentPath, propertyNodes, properties, \"posts\") : null)")
    @Mapping(target = "comments", expression = "java(properties.contains(\"comments\") ? commentMapper.toCommentDtos(entity.getComments(), currentPath, propertyNodes, properties, \"comments\") : null)")
    @Mapping(target = "person", expression = "java(properties.contains(\"person\") ? personMapper.toPersonDto(entity.getPerson(), currentPath, propertyNodes, properties, \"person\") : null)")
    public abstract AccountDto rqlToAccountDto(Account entity, @Context StringBuilder currentPath, @Context List<PropertyNode> propertyNodes, @Context List<String> properties, @Context String property);

    @Named("dynamicAccountsDefaultCollection")
    public Set<AccountDto> toAccountDtosDefault(Collection<Account> entity, @Context List<PropertyNode> propertyNodes) {
        return rqlToAccountDtos(new HashSet<>(entity), new StringBuilder(), propertyNodes, new ArrayList<>(), "");
    }

    @Named("dynamicAccountsDefault")
    public AccountDto toAccountDtoDefault(Account entity, @Context List<PropertyNode> propertyNodes) {
        return rqlToAccountDto(entity, new StringBuilder(), propertyNodes, new ArrayList<>(), "");
    }
}

Which is meant for internal remapping.这用于内部重新映射。 Now, I'd like to add a feature where the user can "override" this method, in the sense that they could for example add a statement to ignore the password of the account, while also calling the internal methods.现在,我想添加一个用户可以“覆盖”此方法的功能,例如,他们可以添加一条语句来忽略帐户的密码,同时还调用内部方法。

Few examples as reference points:几个例子作为参考点:

import org.mapstruct.*;
import spring.graphql.rest.rql.core.nodes.PropertyNode;
import spring.graphql.rest.rql.example.dto.AccountDto;
import spring.graphql.rest.rql.example.models.Account;

import java.util.List;

@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
        nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public abstract class RealAccountMapper extends AccountMapper {

    @Mapping(target = "username", ignore = true)
    public abstract AccountDto toAccountDtoDefault(Account entity, @Context List<PropertyNode> propertyNodes);
}

@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
        nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public abstract class RealAccountMapper {

    @Mapping(target = "username", ignore = true)
    @Mapper(uses = AccountMapper.class, qualifiedByName = "dynamicAccountsDefault")
    public abstract AccountDto toAccountDto(Account entity, @Context List<PropertyNode> propertyNodes);
}

The user should be able to define a property to ignore, or for example add with a specified source.用户应该能够定义要忽略的属性,或者例如添加指定的源。 From what I experimented, even without the overrides and such, it just generates a separate mapping method, instead of even trying to reuse the other one.根据我的实验,即使没有覆盖等,它也只会生成一个单独的映射方法,而不是尝试重用另一个。

Is this possible without needing to implement custom methods on the user side which would call the internal methods?这可能不需要在用户端实现自定义方法来调用内部方法吗? If not, is there a particular reason, or has it just not come up as a possible feature in MapStruct?如果没有,是否有特殊原因,或者它只是没有在 MapStruct 中作为可能的功能出现?

MapStruct generates code during compilation. MapStruct 在编译期间生成代码。 This means that it is not possible to ignore certain properties and invoke another mapper for this, because the other mapper already has that implemented .这意味着不可能忽略某些属性并为此调用另一个映射器,因为另一个映射器已经实现了。

As a new feature we could add something to the @Mapper that would basically merge the configuration from the parent mapper.作为一项新功能,我们可以向@Mapper添加一些东西,基本上可以合并来自父映射器的配置。

eg例如

@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
        nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE, methodOverrideStrategy = OverrideStrategy.MERGE)
public abstract class RealAccountMapper extends AccountMapper {

    @Override
    @Mapping(target = "username", ignore = true)
    public abstract AccountDto toAccountDtoDefault(Account entity, @Context List<PropertyNode> propertyNodes);
}

This would mean that if this new methodOverrideStrategy (the name is not final) would mean that MapStruct will perform a merge of the annotation on the toAccountDtoDefault method.这意味着如果这个新的methodOverrideStrategy (名称不是最终的)意味着 MapStruct 将在toAccountDtoDefault方法上执行注释的合并。

For MapStruct it would be as if the user has written.对于 MapStruct,就好像用户已经编写了一样。

    @Named("dynamicAccountsDefault")
    @Override
    @Mapping(target = "username", ignore = true)
    public abstract AccountDto toAccountDtoDefault(Account entity, @Context List<PropertyNode> propertyNodes);

I would suggest that you raise this as a feature request in the MapStruct issue tracker .我建议您将此作为 MapStruct问题跟踪器中的功能请求提出。

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

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