我可以扩展 MapStruct 方法吗?
Can I extend MapStruct methods?
我正在开发一个库,我希望该库有一个像这样的映射器:
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<>(), "");
}
}
用于内部重新映射。现在,我想添加一个用户可以“覆盖”此方法的功能,例如,他们可以添加一条语句来忽略帐户密码,同时还调用内部方法。
举几个例子作为参考:
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);
}
用户应该能够定义一个 属性 来忽略,或者例如添加指定的来源。根据我的实验,即使没有覆盖等,它也只是生成一个单独的映射方法,而不是尝试重用另一个。
这是否可能不需要在用户端实现调用内部方法的自定义方法?如果不是,是否有特殊原因,或者它只是没有作为 MapStruct 中可能的功能出现?
MapStruct 在编译期间生成代码。这意味着不可能忽略某些属性并为此调用另一个映射器,因为另一个映射器已经实现了。
作为一项新功能,我们可以向 @Mapper
添加一些内容,这基本上会合并来自父映射器的配置。
例如
@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);
}
这意味着如果这个新的 methodOverrideStrategy
(名称不是最终名称)将意味着 MapStruct 将在 toAccountDtoDefault
方法上执行注释合并。
对于 MapStruct,就好像用户已经写了一样。
@Named("dynamicAccountsDefault")
@Override
@Mapping(target = "username", ignore = true)
public abstract AccountDto toAccountDtoDefault(Account entity, @Context List<PropertyNode> propertyNodes);
我建议您在 MapStruct issue tracker 中将此作为功能请求提出。
我正在开发一个库,我希望该库有一个像这样的映射器:
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<>(), "");
}
}
用于内部重新映射。现在,我想添加一个用户可以“覆盖”此方法的功能,例如,他们可以添加一条语句来忽略帐户密码,同时还调用内部方法。
举几个例子作为参考:
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);
}
用户应该能够定义一个 属性 来忽略,或者例如添加指定的来源。根据我的实验,即使没有覆盖等,它也只是生成一个单独的映射方法,而不是尝试重用另一个。
这是否可能不需要在用户端实现调用内部方法的自定义方法?如果不是,是否有特殊原因,或者它只是没有作为 MapStruct 中可能的功能出现?
MapStruct 在编译期间生成代码。这意味着不可能忽略某些属性并为此调用另一个映射器,因为另一个映射器已经实现了。
作为一项新功能,我们可以向 @Mapper
添加一些内容,这基本上会合并来自父映射器的配置。
例如
@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);
}
这意味着如果这个新的 methodOverrideStrategy
(名称不是最终名称)将意味着 MapStruct 将在 toAccountDtoDefault
方法上执行注释合并。
对于 MapStruct,就好像用户已经写了一样。
@Named("dynamicAccountsDefault")
@Override
@Mapping(target = "username", ignore = true)
public abstract AccountDto toAccountDtoDefault(Account entity, @Context List<PropertyNode> propertyNodes);
我建议您在 MapStruct issue tracker 中将此作为功能请求提出。