防止mapstruct使用对象映射函数列表中的单对象映射函数
Prevent mapstruct from using the single object mapping function in list of object mapping function
我有 2 个微服务:我们称它们为 A 和 B。
B 处理的实体,其中引用了 A 的实体,被实现为简单的 Long id(例如 groupId)
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "WorkShifts")
@AllArgsConstructor
@Builder(toBuilder = true)
public class WorkShiftEntity extends BaseEntitySerial {
@Column(name = "group_id")
private Long groupId;
private String description;
@Column(name = "start_time")
private Time startTime;
@Column(name = "end_time")
private Time endTime;
@Column(name = "work_shift")
private Integer workShift;
}
我想实现的是使用mapstruct填充B(由A持有)缺失的组数据。
到目前为止,我尝试使用 @AfterMapping 函数从 A 请求丢失的数据。我的映射器是:
@Mapper(componentModel = "spring", uses = LocalTimeMapper.class, builder = @Builder(disableBuilder = true), config = CommonMapperConfig.class)
public abstract class WorkShiftMapper extends BaseMapper implements IBaseMapper<WorkShiftEntity, WorkShiftDTO, Long>, LogSupport {
@Autowired
RestTemplate restTemplate;
@Mapping(target = "groupId", source = "group.id")
public abstract WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO);
@AfterMapping
public void afterEntityToDto(final WorkShiftEntity workShiftEntity, @MappingTarget final WorkShiftDTO workShiftDTO) {
if (workShiftEntity == null) {
return;
}
GroupDTO groupDTO = EcofinderUtils.getGroupDTO(restTemplate, workShiftEntity.getGroupId());
try {
GenericUtils.enhanceDTOForAttributeWithDTO(workShiftDTO, groupDTO, "group");
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
@AfterMapping
public void afterEntityToDtoList(final List<WorkShiftEntity> workShiftEntity, @MappingTarget final List<WorkShiftDTO> workShiftDTO) {
if (workShiftEntity == null || workShiftEntity.size() == 0) {
return;
}
List<GroupDTO> groups = EcofinderUtils.getAllGroupDTOById(restTemplate, workShiftEntity.stream().map(WorkShiftEntity::getGroupId).distinct().toList());
try {
//Compile the resulting DTOs with the data got from the registry
//Group
GenericUtils.enhanceDTOListWithDataFromDTOJoiningEntities(workShiftDTO, groups, workShiftEntity, "group", "groupId");
} catch (AppException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
}
给我映射函数的实现接口是:
public interface IBaseMapper<T extends BaseEntity<K>, D extends IBaseDTO<K>, K extends Serializable> {
D entityToDto(T entity);
List<D> entityToDtoList(List<T> entity);
T dtoToEntity(D dto);
}
生成代码的问题在于,将实体列表映射到 DTO 列表的函数对每个实体都使用了 entityToDto,导致对 A 的 n 个请求。之后,另一个 @AfterMapping 函数被调用(收集所有 ID 并仅在一个请求中提取所有数据的请求,这是映射列表时唯一应该使用的请求)。
//GENERATED CODE BY MAPSTRUCT
@Override
public WorkShiftDTO entityToDto(WorkShiftEntity workShiftEntity) {
if ( workShiftEntity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( workShiftEntity.getId() );
workShiftDTO.setDescription( workShiftEntity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );
afterEntityToDto( workShiftEntity, workShiftDTO );
return workShiftDTO;
}
@Override
public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
//more code...
List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
for ( WorkShiftEntity workShiftEntity : entity ) {
list.add( entityToDto( workShiftEntity ) );
}
afterEntityToDtoList( entity, list );
return list;
}
有没有办法让 mapstruct 实现 entityToDto 函数两次,其中一个版本使用 @AfterMapping 函数而另一个版本不使用,以使 entityToDtoList 函数使用没有 @AfterMapping 调用的版本?
类似于:
@Override
public WorkShiftDTO entityToDto(WorkShiftEntity workShiftEntity) {
if ( workShiftEntity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( workShiftEntity.getId() );
workShiftDTO.setDescription( workShiftEntity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );
afterEntityToDto( workShiftEntity, workShiftDTO );
return workShiftDTO;
}
public WorkShiftDTO entityToDtoNoAfter(WorkShiftEntity workShiftEntity) {
if ( workShiftEntity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( workShiftEntity.getId() );
workShiftDTO.setDescription( workShiftEntity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );
return workShiftDTO;
}
@Override
public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
//more code...
List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
for ( WorkShiftEntity workShiftEntity : entity ) {
list.add( entityToDtoNoAfter( workShiftEntity ) );
}
afterEntityToDtoList( entity, list );
return list;
}
欢迎其他方法,我只觉得这个更自然。
提前致谢!
经过大约两天的深入研究和多次尝试,我认为我找到了一个不错的解决方案。
我可以给函数起一个名字,这样它们的工作方式就像它们具有特定的范围一样。
映射器界面变为:
public interface IBaseMapper<T extends BaseEntity<K>, D extends IBaseDTO<K>, K extends Serializable> {
@BeanMapping(qualifiedByName = "EntityToDTO")
D entityToDto(T entity);
@Named("EntityToDTOList")
public abstract D entityToDTOListEntity(T entity);
@IterableMapping(qualifiedByName = "EntityToDTOList")
List<D> entityToDtoList(List<T> entity);
T dtoToEntity(D dto);
}
这样我就可以将我需要的所有功能组合在一起。
映射器摘要class:
@Mapping(target = "groupId", source = "group.id")
public abstract WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO);
@AfterMapping
@Named("EntityToDTO")
public void afterEntityToDto(final WorkShiftEntity workShiftEntity, @MappingTarget final WorkShiftDTO workShiftDTO) {
if (workShiftEntity == null) {
return;
}
GroupDTO groupDTO = EcofinderUtils.getGroupDTO(restTemplate, workShiftEntity.getGroupId());
try {
GenericUtils.enhanceDTOForAttributeWithDTO(workShiftDTO, groupDTO, "group");
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
@AfterMapping
@Named("EntityToDTOList")
public void afterEntityToDtoList(final List<WorkShiftEntity> workShiftEntity, @MappingTarget final List<WorkShiftDTO> workShiftDTO) {
if (workShiftEntity == null || workShiftEntity.size() == 0) {
return;
}
List<GroupDTO> groups = EcofinderUtils.getAllGroupDTOById(restTemplate, workShiftEntity.stream().map(WorkShiftEntity::getGroupId).distinct().toList());
try {
//Compile the resulting DTOs with the data got from the registry
//Group
GenericUtils.enhanceDTOListWithDataFromDTOJoiningEntities(workShiftDTO, groups, workShiftEntity, "group", "groupId");
} catch (AppException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
这样做,生成的Impl class是:
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-05-20T15:08:38+0200",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 17.0.1 (Oracle Corporation)"
)
@Component
public class WorkShiftMapperImpl extends WorkShiftMapper {
@Autowired
private LocalTimeMapper localTimeMapper;
@Override
public WorkShiftDTO entityToDto(WorkShiftEntity entity) {
if ( entity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( entity.getId() );
workShiftDTO.setDescription( entity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( entity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( entity.getEndTime() ) );
workShiftDTO.setWorkShift( entity.getWorkShift() );
afterEntityToDto( entity, workShiftDTO );
return workShiftDTO;
}
@Override
public WorkShiftDTO entityToDTOListEntity(WorkShiftEntity entity) {
if ( entity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( entity.getId() );
workShiftDTO.setDescription( entity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( entity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( entity.getEndTime() ) );
workShiftDTO.setWorkShift( entity.getWorkShift() );
return workShiftDTO;
}
@Override
public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
if ( entity == null ) {
return null;
}
List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
for ( WorkShiftEntity workShiftEntity : entity ) {
list.add( entityToDTOListEntity( workShiftEntity ) );
}
afterEntityToDtoList( entity, list );
return list;
}
@Override
public WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO) {
if ( workShiftDTO == null ) {
return null;
}
WorkShiftEntity workShiftEntity = new WorkShiftEntity();
workShiftEntity.setGroupId( workShiftDTOGroupId( workShiftDTO ) );
workShiftEntity.setId( workShiftDTO.getId() );
workShiftEntity.setDescription( workShiftDTO.getDescription() );
workShiftEntity.setStartTime( localTimeMapper.map( workShiftDTO.getStartTime() ) );
workShiftEntity.setEndTime( localTimeMapper.map( workShiftDTO.getEndTime() ) );
workShiftEntity.setWorkShift( workShiftDTO.getWorkShift() );
return workShiftEntity;
}
private Long workShiftDTOGroupId(WorkShiftDTO workShiftDTO) {
if ( workShiftDTO == null ) {
return null;
}
GroupDTO group = workShiftDTO.getGroup();
if ( group == null ) {
return null;
}
Long id = group.getId();
if ( id == null ) {
return null;
}
return id;
}
}
这正是我要找的。
我有 2 个微服务:我们称它们为 A 和 B。
B 处理的实体,其中引用了 A 的实体,被实现为简单的 Long id(例如 groupId)
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "WorkShifts")
@AllArgsConstructor
@Builder(toBuilder = true)
public class WorkShiftEntity extends BaseEntitySerial {
@Column(name = "group_id")
private Long groupId;
private String description;
@Column(name = "start_time")
private Time startTime;
@Column(name = "end_time")
private Time endTime;
@Column(name = "work_shift")
private Integer workShift;
}
我想实现的是使用mapstruct填充B(由A持有)缺失的组数据。 到目前为止,我尝试使用 @AfterMapping 函数从 A 请求丢失的数据。我的映射器是:
@Mapper(componentModel = "spring", uses = LocalTimeMapper.class, builder = @Builder(disableBuilder = true), config = CommonMapperConfig.class)
public abstract class WorkShiftMapper extends BaseMapper implements IBaseMapper<WorkShiftEntity, WorkShiftDTO, Long>, LogSupport {
@Autowired
RestTemplate restTemplate;
@Mapping(target = "groupId", source = "group.id")
public abstract WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO);
@AfterMapping
public void afterEntityToDto(final WorkShiftEntity workShiftEntity, @MappingTarget final WorkShiftDTO workShiftDTO) {
if (workShiftEntity == null) {
return;
}
GroupDTO groupDTO = EcofinderUtils.getGroupDTO(restTemplate, workShiftEntity.getGroupId());
try {
GenericUtils.enhanceDTOForAttributeWithDTO(workShiftDTO, groupDTO, "group");
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
@AfterMapping
public void afterEntityToDtoList(final List<WorkShiftEntity> workShiftEntity, @MappingTarget final List<WorkShiftDTO> workShiftDTO) {
if (workShiftEntity == null || workShiftEntity.size() == 0) {
return;
}
List<GroupDTO> groups = EcofinderUtils.getAllGroupDTOById(restTemplate, workShiftEntity.stream().map(WorkShiftEntity::getGroupId).distinct().toList());
try {
//Compile the resulting DTOs with the data got from the registry
//Group
GenericUtils.enhanceDTOListWithDataFromDTOJoiningEntities(workShiftDTO, groups, workShiftEntity, "group", "groupId");
} catch (AppException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
}
给我映射函数的实现接口是:
public interface IBaseMapper<T extends BaseEntity<K>, D extends IBaseDTO<K>, K extends Serializable> {
D entityToDto(T entity);
List<D> entityToDtoList(List<T> entity);
T dtoToEntity(D dto);
}
生成代码的问题在于,将实体列表映射到 DTO 列表的函数对每个实体都使用了 entityToDto,导致对 A 的 n 个请求。之后,另一个 @AfterMapping 函数被调用(收集所有 ID 并仅在一个请求中提取所有数据的请求,这是映射列表时唯一应该使用的请求)。
//GENERATED CODE BY MAPSTRUCT
@Override
public WorkShiftDTO entityToDto(WorkShiftEntity workShiftEntity) {
if ( workShiftEntity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( workShiftEntity.getId() );
workShiftDTO.setDescription( workShiftEntity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );
afterEntityToDto( workShiftEntity, workShiftDTO );
return workShiftDTO;
}
@Override
public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
//more code...
List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
for ( WorkShiftEntity workShiftEntity : entity ) {
list.add( entityToDto( workShiftEntity ) );
}
afterEntityToDtoList( entity, list );
return list;
}
有没有办法让 mapstruct 实现 entityToDto 函数两次,其中一个版本使用 @AfterMapping 函数而另一个版本不使用,以使 entityToDtoList 函数使用没有 @AfterMapping 调用的版本?
类似于:
@Override
public WorkShiftDTO entityToDto(WorkShiftEntity workShiftEntity) {
if ( workShiftEntity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( workShiftEntity.getId() );
workShiftDTO.setDescription( workShiftEntity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );
afterEntityToDto( workShiftEntity, workShiftDTO );
return workShiftDTO;
}
public WorkShiftDTO entityToDtoNoAfter(WorkShiftEntity workShiftEntity) {
if ( workShiftEntity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( workShiftEntity.getId() );
workShiftDTO.setDescription( workShiftEntity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );
return workShiftDTO;
}
@Override
public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
//more code...
List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
for ( WorkShiftEntity workShiftEntity : entity ) {
list.add( entityToDtoNoAfter( workShiftEntity ) );
}
afterEntityToDtoList( entity, list );
return list;
}
欢迎其他方法,我只觉得这个更自然。
提前致谢!
经过大约两天的深入研究和多次尝试,我认为我找到了一个不错的解决方案。
我可以给函数起一个名字,这样它们的工作方式就像它们具有特定的范围一样。 映射器界面变为:
public interface IBaseMapper<T extends BaseEntity<K>, D extends IBaseDTO<K>, K extends Serializable> {
@BeanMapping(qualifiedByName = "EntityToDTO")
D entityToDto(T entity);
@Named("EntityToDTOList")
public abstract D entityToDTOListEntity(T entity);
@IterableMapping(qualifiedByName = "EntityToDTOList")
List<D> entityToDtoList(List<T> entity);
T dtoToEntity(D dto);
}
这样我就可以将我需要的所有功能组合在一起。
映射器摘要class:
@Mapping(target = "groupId", source = "group.id")
public abstract WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO);
@AfterMapping
@Named("EntityToDTO")
public void afterEntityToDto(final WorkShiftEntity workShiftEntity, @MappingTarget final WorkShiftDTO workShiftDTO) {
if (workShiftEntity == null) {
return;
}
GroupDTO groupDTO = EcofinderUtils.getGroupDTO(restTemplate, workShiftEntity.getGroupId());
try {
GenericUtils.enhanceDTOForAttributeWithDTO(workShiftDTO, groupDTO, "group");
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
@AfterMapping
@Named("EntityToDTOList")
public void afterEntityToDtoList(final List<WorkShiftEntity> workShiftEntity, @MappingTarget final List<WorkShiftDTO> workShiftDTO) {
if (workShiftEntity == null || workShiftEntity.size() == 0) {
return;
}
List<GroupDTO> groups = EcofinderUtils.getAllGroupDTOById(restTemplate, workShiftEntity.stream().map(WorkShiftEntity::getGroupId).distinct().toList());
try {
//Compile the resulting DTOs with the data got from the registry
//Group
GenericUtils.enhanceDTOListWithDataFromDTOJoiningEntities(workShiftDTO, groups, workShiftEntity, "group", "groupId");
} catch (AppException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
getLogger().error(e.getMessage());
}
}
这样做,生成的Impl class是:
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-05-20T15:08:38+0200",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 17.0.1 (Oracle Corporation)"
)
@Component
public class WorkShiftMapperImpl extends WorkShiftMapper {
@Autowired
private LocalTimeMapper localTimeMapper;
@Override
public WorkShiftDTO entityToDto(WorkShiftEntity entity) {
if ( entity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( entity.getId() );
workShiftDTO.setDescription( entity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( entity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( entity.getEndTime() ) );
workShiftDTO.setWorkShift( entity.getWorkShift() );
afterEntityToDto( entity, workShiftDTO );
return workShiftDTO;
}
@Override
public WorkShiftDTO entityToDTOListEntity(WorkShiftEntity entity) {
if ( entity == null ) {
return null;
}
WorkShiftDTO workShiftDTO = new WorkShiftDTO();
workShiftDTO.setId( entity.getId() );
workShiftDTO.setDescription( entity.getDescription() );
workShiftDTO.setStartTime( localTimeMapper.map( entity.getStartTime() ) );
workShiftDTO.setEndTime( localTimeMapper.map( entity.getEndTime() ) );
workShiftDTO.setWorkShift( entity.getWorkShift() );
return workShiftDTO;
}
@Override
public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
if ( entity == null ) {
return null;
}
List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
for ( WorkShiftEntity workShiftEntity : entity ) {
list.add( entityToDTOListEntity( workShiftEntity ) );
}
afterEntityToDtoList( entity, list );
return list;
}
@Override
public WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO) {
if ( workShiftDTO == null ) {
return null;
}
WorkShiftEntity workShiftEntity = new WorkShiftEntity();
workShiftEntity.setGroupId( workShiftDTOGroupId( workShiftDTO ) );
workShiftEntity.setId( workShiftDTO.getId() );
workShiftEntity.setDescription( workShiftDTO.getDescription() );
workShiftEntity.setStartTime( localTimeMapper.map( workShiftDTO.getStartTime() ) );
workShiftEntity.setEndTime( localTimeMapper.map( workShiftDTO.getEndTime() ) );
workShiftEntity.setWorkShift( workShiftDTO.getWorkShift() );
return workShiftEntity;
}
private Long workShiftDTOGroupId(WorkShiftDTO workShiftDTO) {
if ( workShiftDTO == null ) {
return null;
}
GroupDTO group = workShiftDTO.getGroup();
if ( group == null ) {
return null;
}
Long id = group.getId();
if ( id == null ) {
return null;
}
return id;
}
}
这正是我要找的。