我在 Spring Boot 应用程序中使用以下 Lombok 和 Mapstruct 版本:
这就是我的 pom.xml 中注释处理器路径的配置方式:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>21</source>
<target>21</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
我有一个 Java 记录作为 DTO,表示结果页面,并具有泛型类型 T(@Builder 和 @With 是 Lombok 注释):
@Builder
@With
public record PageDto<T extends BaseDto>(
int pageNumber,
int pageSize,
int pageNumberOfElements,
long totalElements,
int totalPages,
List<T> content
) {
public PageDto {
if(content == null) {
content = new ArrayList<>();
}
}
}
我使用Mapstruct将Spring接口org.springframework.data.domain.Page映射到我的PageDto,如下所示:
public interface BaseMapper<M extends BaseEntity, D extends BaseDto> {
@Mapping(target = "pageNumber", expression = "java(entity.getNumber())")
@Mapping(target = "pageSize", expression = "java(entity.getSize())")
@Mapping(target = "pageNumberOfElements", expression = "java(entity.getNumberOfElements())")
@Mapping(target = "totalElements", expression = "java(entity.getTotalElements())")
@Mapping(target = "totalPages", expression = "java(entity.getTotalPages())")
@Mapping(target = "content", source = "content")
PageDto<D> toDto(Page<M> entity);
}
@Mapper(componentModel = "spring")
public interface UserMapper extends BaseMapper<UserEntity, UserDto> {}
但是生成的 Mapstruct 代码存在编译时错误:
T cannot be resolved to a type
。
Bellow 是生成的具体 Mapstruct
UserMapperImpl
:
public class UserMapperImpl implements UserMapper {
@Override
public PageDto<UserDto> toDto(Page<UserEntity> entity) {
if ( entity == null ) {
return null;
}
//this line causes a compile-time error: T cannot be resolved to a type
PageDto.PageDtoBuilder<T> pageDto = PageDto.builder();
if ( entity.hasContent() ) {
pageDto.content( userEntityListToBaseDtoList( entity.getContent() ) );
}
pageDto.pageNumber( entity.getNumber() );
pageDto.pageSize( entity.getSize() );
pageDto.pageNumberOfElements( entity.getNumberOfElements() );
pageDto.totalElements( entity.getTotalElements() );
pageDto.totalPages( entity.getTotalPages() );
return pageDto.build();
}
}
这是生成错误的行:
PageDto.PageDtoBuilder<T> pageDto = PageDto.builder();
看起来 Mapstruct 没有解析泛型类型 T。
正确的生成代码应该是PageDto.PageDtoBuilder<UserDto> pageDto = PageDto.builder();
我该如何解决这个问题?
提前致谢。
在网上搜索了一些类似的问题,但没有找到。
这是因为 MapStruct 与 Lombok 的
@Builder
和 @With
注释一起使用时生成代码和处理泛型类型的方式。需要明确告知 MapStruct 泛型类型 T
。
重构 PageDto
以避免直接将 Lombok 的 @Builder
与泛型一起使用。
Lombok 的 @Builder 已知泛型问题。处理此问题的一种方法是创建一个如下所示的自定义构建器:
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PageDto<T extends BaseDto> {
private int pageNumber;
private int pageSize;
private int pageNumberOfElements;
private long totalElements;
private int totalPages;
private List<T> content = new ArrayList<>();
public static <T extends BaseDto> PageDtoBuilder<T> builder() {
return new PageDtoBuilder<>();
}
public static class PageDtoBuilder<T extends BaseDto> {
private int pageNumber;
private int pageSize;
private int pageNumberOfElements;
private long totalElements;
private int totalPages;
private List<T> content;
PageDtoBuilder() {
}
public PageDtoBuilder<T> pageNumber(int pageNumber) {
this.pageNumber = pageNumber;
return this;
}
public PageDtoBuilder<T> pageSize(int pageSize) {
this.pageSize = pageSize;
return this;
}
public PageDtoBuilder<T> pageNumberOfElements(int pageNumberOfElements) {
this.pageNumberOfElements = pageNumberOfElements;
return this;
}
public PageDtoBuilder<T> totalElements(long totalElements) {
this.totalElements = totalElements;
return this;
}
public PageDtoBuilder<T> totalPages(int totalPages) {
this.totalPages = totalPages;
return this;
}
public PageDtoBuilder<T> content(List<T> content) {
this.content = content;
return this;
}
public PageDto<T> build() {
return new PageDto<>(pageNumber, pageSize, pageNumberOfElements, totalElements, totalPages, content);
}
}
}
然后更新映射器:
@Mapper(componentModel = "spring")
public interface UserMapper extends BaseMapper<UserEntity, UserDto> {
@Override
@Mapping(target = "pageNumber", expression = "java(entity.getNumber())")
@Mapping(target = "pageSize", expression = "java(entity.getSize())")
@Mapping(target = "pageNumberOfElements", expression = "java(entity.getNumberOfElements())")
@Mapping(target = "totalElements", expression = "java(entity.getTotalElements())")
@Mapping(target = "totalPages", expression = "java(entity.getTotalPages())")
@Mapping(target = "content", source = "content")
PageDto<UserDto> toDto(Page<UserEntity> entity);
}
自定义构建器模式可确保在创建
T
实例时使用正确的泛型类型 PageDto
。
通过显式定义UserMapper
中的映射,MapStruct可以正确生成实现代码。