Spring Boot3+Java17中Lombok与MapStruct属性映射错误排查
问题
编译报错如下:
19:48 C:\Users\xxxxx\Documents\workspace\eshop\src\main\java\com\eshop\mapper\ProductMapper.java:19:48 java: No property named "product.name" exists in source parameter(s). Did you mean "null"? C:\Users\xxxxx\Documents\workspace\eshop\src\main\java\com\eshop\mapper\ProductMapper.java:20:55 java: No property named "product.description" exists in source parameter(s). Did you mean "null"? C:\Users\xxxxx\Documents\workspace\eshop\src\main\java\com\eshop\mapper\ProductMapper.java:21:53 java: No property named "product.id" exists in source parameter(s). Did you mean "null"?
相关代码
ProductMapper
package com.eshop.mapper; import com.eshop.domain.entity.Product; import com.eshop.domain.entity.ProductVariant; import com.eshop.dto.request.body.ProductCreationBody; import com.eshop.dto.request.response.ProductGetDetailsResponse; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; import java.util.List; @Mapper(componentModel = "spring") public interface ProductMapper { ProductGetDetailsResponse map(Product product); @Mappings({ @Mapping(target = "name", source = "product.name"), @Mapping(target = "description", source = "product.description"), @Mapping(target = "productId", source = "product.id"), }) ProductGetDetailsResponse map(ProductVariant productVariant); Product map(ProductCreationBody productCreationRequestBody); List<ProductGetDetailsResponse> map(List<ProductVariant> products); }
待映射对象
ProductGetDetailsResponse
package com.eshop.dto.request.response; import lombok.*; @Getter @Setter @NoArgsConstructor @AllArgsConstructor @ToString public class ProductGetDetailsResponse { private Long id; private Long productId; private String name; private String description; private String imageUrl; private String color; private String size; private String price; private String discount; private String displayOrder; }
ProductVariant实体类
package com.eshop.domain.entity; import com.eshop.domain.enums.ProductGender; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.io.Serializable; import java.time.LocalDate; @Entity @Table(name = "product_variant", uniqueConstraints = { @UniqueConstraint(columnNames = {"product_id", "productColor", "productSize"}) }) @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class ProductVariant implements Serializable { private static final Long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Enumerated(EnumType.STRING) private ProductGender productGender; private String productColor; private String productSize; private Integer unitsInStock; private String imageUrl; private Double price; private Integer discount; private LocalDate discountStartDate; private LocalDate discountEndDate; private Integer displayOrder; @ManyToOne @JoinColumn(name = "product_id") private Product product; }
Product实体类
package com.eshop.domain.entity; import com.eshop.domain.enums.ProductStatus; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; import java.io.Serializable; import java.util.Date; import java.util.Set; @Table(name = "products", uniqueConstraints = { @UniqueConstraint(columnNames = "name") }) @Entity @Getter @Setter @AllArgsConstructor @NoArgsConstructor @ToString public class Product implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(unique = true) private String name; private String description; @Enumerated(EnumType.STRING) private ProductStatus status; @ManyToOne @JoinColumn(name = "store_id") private Store store; @CreationTimestamp @Column(name = "created_at") private Date createdAt; @UpdateTimestamp @Column(name = "updated_at") private Date updatedAt; @OneToMany(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private Set<ProductVariant> productVariants; @ManyToOne @JoinColumn(name = "subCategory_id") private SubCategory subCategory; }
pom.xml配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.eshop</groupId> <artifactId>eshop</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>eshop</name> <description>eshop</description> <properties> <java.version>17</java.version> <version.lombok>1.18.26</version.lombok> <version.mapstruct>1.3.1.Final</version.mapstruct> <version.mapstruct-lombok>0.2.0</version.mapstruct-lombok> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.0.4</version> </dependency> <dependency> <groupId>org.openapitools</groupId> <artifactId>openapi-generator-maven-plugin</artifactId> <version>6.4.0</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-envers</artifactId> <version>6.1.7.Final</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${version.lombok}</version> <optional>true</optional> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${version.mapstruct}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok-mapstruct-binding</artifactId> <version>${version.mapstruct-lombok}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>17</source> <target>17</target> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${version.lombok}</version> </path> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${version.mapstruct}</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok-mapstruct-binding</artifactId> <version>${version.mapstruct-lombok}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build> </project>
已尝试调整pom依赖顺序、降级Lombok和MapStruct版本,问题未解决。此前问题曾突然消失,添加DTO字段后复现。执行clean install可正常生成相关类,但运行应用时仍触发错误。
解决方案
- 升级MapStruct版本:当前使用的MapStruct 1.3.1.Final不兼容Spring Boot 3和Java 17,将版本升级到1.5.5.Final(稳定兼容版本),保持
lombok-mapstruct-binding版本为0.2.0即可。 - 调整注解处理器顺序:在
maven-compiler-plugin的annotationProcessorPaths中,确保lombok路径放在mapstruct-processor之前,保证Lombok先生成getter/setter,MapStruct能正确识别实体属性。 - 检查IDE注解处理器配置:如果使用IntelliJ IDEA,开启「Enable annotation processing」,路径:
Settings -> Build, Execution, Deployment -> Compiler -> Annotation Processors。 - 清理缓存并强制构建:执行
mvn clean install -U强制更新依赖,同时清理IDE缓存(File -> Invalidate Caches... -> Invalidate and Restart)。 - 修正映射表达式:在
ProductMapper的map(ProductVariant)方法中,显式指定完整参数路径,避免MapStruct解析歧义:
@Mappings({ @Mapping(target = "name", source = "productVariant.product.name"), @Mapping(target = "description", source = "productVariant.product.description"), @Mapping(target = "productId", source = "productVariant.product.id"), }) ProductGetDetailsResponse map(ProductVariant productVariant);
对于ProductVariant中与DTO字段名一致的属性(如id、imageUrl等),无需手动配置映射,MapStruct会自动匹配。
内容的提问来源于stack exchange,提问作者Massimo Deiana
相关产品推荐
相关产品推荐

