Spring Boot CRUD应用运行时出现序列化异常求助
Spring Boot CRUD应用序列化异常排查
异常信息
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.project.TodoApp.entity.Employee$HibernateProxy$1NCHjs6v["hibernateLazyInitializer"]) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.15.3.jar:2.15.3] at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1308) ~[jackson-databind-2.15.3.jar:2.15.3] at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:414) ~[jackson-databind-2.15.3.jar:2.15.3] at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:53) ~[jackson-databind-2.15.3.jar:2.15.3] at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:30) ~[jackson-databind-2.15.3.jar:2.15.3]
相关代码
EmployeeController
@PutMapping(path = "\"/update\"") public Employee updateEmployee(@RequestBody EmployeeUpdateDTO employeeUpdateDTO) { return employeeService.updateEmployees(employeeUpdateDTO); }
EmployeeService
public interface EmployeeService { Employee updateEmployees(EmployeeUpdateDTO employeeUpdateDTO); }
EmployeeServiceIMPL
public Employee updateEmployees(EmployeeUpdateDTO employeeUpdateDTO) { if(employeeRepo.existsById(employeeUpdateDTO.getEmployeeid())) { Employee employee = employeeRepo.getById(employeeUpdateDTO.getEmployeeid()); employee.setEmployeename(employeeUpdateDTO.getEmployeename()); employee.setAddress(employeeUpdateDTO.getAddress()); employee.setMobile(employeeUpdateDTO.getMobile()); employee.setActivestate(employeeUpdateDTO.isActivestate()); employeeRepo.save(employee); return employee; } else { System.out.println("\"Employee ID Not Found\""); } return null; }
EmployeeUpdateDTO
@AllArgsConstructor @NoArgsConstructor @Data public class EmployeeUpdateDTO { private Long employeeid; private String employeename; private String address; private int mobile; private boolean activestate; }
pom.xml依赖
<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>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> <scope>provided</scope> </dependency>
问题原因
异常核心是Jackson无法序列化Hibernate生成的懒加载代理对象。employeeRepo.getById()返回的不是实际的Employee实体,而是Hibernate通过ByteBuddy生成的代理类,这个代理包含hibernateLazyInitializer属性,Jackson默认不知道如何序列化该属性,从而抛出异常。
解决方案
方案1:替换getById为findById
getById()是懒加载方法,返回代理对象;findById()会立即查询数据库返回实际实体(包装在Optional中)。修改Service实现:
public Employee updateEmployees(EmployeeUpdateDTO employeeUpdateDTO) { return employeeRepo.findById(employeeUpdateDTO.getEmployeeid()) .map(employee -> { employee.setEmployeename(employeeUpdateDTO.getEmployeename()); employee.setAddress(employeeUpdateDTO.getAddress()); employee.setMobile(employeeUpdateDTO.getMobile()); employee.setActivestate(employeeUpdateDTO.isActivestate()); return employeeRepo.save(employee); }) .orElseGet(() -> { System.out.println("Employee ID Not Found"); return null; }); }
方案2:在实体类添加Jackson忽略注解
在Employee实体类上添加@JsonIgnoreProperties,忽略Hibernate懒加载相关属性:
@Entity @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) public class Employee { // 实体字段和方法 }
方案3:禁用Jackson的FAIL_ON_EMPTY_BEANS特性(不推荐)
在Spring Boot配置类中添加配置,禁止空对象序列化失败,但这会隐藏其他潜在的序列化问题:
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); return objectMapper; } }
方案4:使用OpenEntityManagerInViewFilter(谨慎使用)
启用该过滤器可以延长EntityManager生命周期到视图渲染阶段,避免懒加载问题,但可能导致性能问题和N+1查询:
在application.properties中添加:
spring.jpa.open-in-view=true
内容的提问来源于stack exchange,提问作者creative one2018
相关产品推荐
相关产品推荐

