Spring WebFlux中使用Lombok时POJO无法序列化问题排查
问题描述
我开发了一个用于学习WebClient用法的简单响应式Web应用,仅包含一个PostController,它将请求委托给外部API,获取响应后序列化再返回给客户端。但运行时出现序列化失败的错误。
错误信息
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.example.spring_webclient_lombok_demo.entity.Post and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
代码示例
PostController.java
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.client.WebClient; import com.example.spring_webclient_lombok_demo.entity.Post; import reactor.core.publisher.Mono; @RestController @RequestMapping("/posts") public class PostController { @Autowired private WebClient webClient; @GetMapping("") public Mono<List<Post>> getPosts() { return webClient.get() .uri("/posts") .retrieve() .bodyToFlux(Post.class) .collectList(); } @GetMapping("{postId}") public Mono<Post> getPostById(@PathVariable int postId) { return webClient.get() .uri("/posts/{id}", postId) .retrieve() .bodyToMono(Post.class); } }
Post.java
import java.util.Objects; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor public class Post { private int userId; private int id; private String title; private String body; // 注释掉的显式构造、getter/setter等方法... }
SpringWebclientLombokDemoApplication.java
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.reactive.function.client.WebClient; @SpringBootApplication public class SpringWebclientLombokDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringWebclientLombokDemoApplication.class, args); } @Bean public WebClient getWebClient() { return WebClient.builder() .baseUrl("https://jsonplaceholder.typicode.com") .build(); } }
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.4.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>spring-webclient-lombok-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>spring-webclient-lombok-demo</name> <description>Demo spring project for practicing Webclient and Lombok</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </path> </annotationProcessorPaths> </configuration> </plugin> <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> </plugins> </build> </project>
原因分析
- 缺少无参构造函数:Jackson反序列化Java对象时,默认需要类提供无参构造函数。你在Post类上添加了
@AllArgsConstructor,这会让Lombok只生成全参构造,而不会自动生成无参构造;虽然@Data注解包含getter、setter等,但不会在存在显式构造(包括Lombok生成的全参构造)的情况下生成无参构造,导致Jackson无法实例化Post类,进而认为该类没有可序列化的属性。 - IDE注解处理器未启用:如果IDE没有启用Lombok插件或者注解处理功能,编译时Lombok不会生成对应的getter、setter和构造函数,运行时自然会出现序列化失败。
解决方案
- 补充无参构造注解:在Post类上添加
@NoArgsConstructor,和@Data、@AllArgsConstructor配合使用,确保Lombok生成无参构造:
@Data @NoArgsConstructor @AllArgsConstructor public class Post { private int userId; private int id; private String title; private String body; }
- 检查IDE配置:
- 确保IDE安装了Lombok插件(比如IDEA的Lombok插件)。
- 开启注解处理功能:IDEA中进入
Settings -> Build, Execution, Deployment -> Compiler -> Annotation Processors,勾选Enable annotation processing。
- 验证编译结果:执行
mvn clean compile,然后查看target/classes下的Post.class文件,反编译确认是否生成了无参构造、getter和setter方法。
内容的提问来源于stack exchange,提问作者Shri
相关产品推荐
相关产品推荐

