You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot微服务InvalidDefinitionException问题求助

问题描述

我开发了一个Spring Boot微服务,调用接口http://localhost:8080/user/utenti/时触发如下错误:

InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.application.dto.UserDto["applicationRoleID"]->com.poste.anagrafica.entity.Role$HibernateProxy$N0iZZA2I["hibernateLazyInitializer"])

数据库结构

数据库结构

Entity类(User)

@Entity
@Table(name = "USERS")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class User implements Serializable {
@Id
@Column(name = "user_id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "created_date")
private LocalDateTime createdDate;

@Column(name = "deleted", nullable = false)
private Long number;

@Column(name = "modified_date")
private LocalDateTime modifiedDate;

@Column(name = "birth_place")
private String birthPlace;

@Column(name = "birthday")
private Date birthDay;

@Column(name = "canNominate")
private Long canNominate;

@Column(name = "email")
private String email;

@Column(name = "firstName")
private String firstName;

@Column(name= "fiscalCode")
private String fiscalCode;

@Column(name = "hiringDate")
private Date hiringDate;

@Column(name ="last_name")
private String lastName;

@Column(name = "matricola")
private String matricola;

@Column(name = "position")
private String position;

@Column(name = "registration_number")
private String registrationNumber;

@Column(name = "replaced")
private Long replaced;

@Column(name = "terminationDate")
private Date terminationDate;

@Column(name = "user_status")
private String userStatus;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "application_role_id")
private Role applicationRoleID;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "company_id")
private Company companyID;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "direction_id")
private Direction directions ;


@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "level_id")
private Levels levelID;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "referent_id")
private User referentID;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "role_id")
private Role roleID;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "task_id")
private EmployeeTask taskID;
}

UserDTO类

@Data
public class UserDto {


private Long userId;


private LocalDateTime createdDate;

private Long number;

private LocalDateTime modifiedDate;


private String birthPlace;


private Date birthDay;


private Long canNominate;


private String email;

private String firstName;


private String fiscalCode;


private Date hiringDate;

private String lastName;


private String matricola;


private String position;

private String registrationNumber;


private Long replaced;


private Date terminationDate;


private String userStatus;


private Role applicationRoleID;


private Company companyID;


private Direction directions ;



private Levels levelID;

private User referentID;


private Role role;

private EmployeeTask taskID;
}

Controller类

@RestController
 @RequestMapping("/user")
 @Log
 public class UserController {

private static final Logger logger = LoggerFactory.getLogger(UserController.class);

@Autowired
UserService userService;

@GetMapping(value = "/cerca/{registration_number}", produces = "application/json")
public ResponseEntity<List<UserDto>> listUserByRegistrationNumber(@PathVariable("registration_number") String registrationNumber)
        throws ChangeSetPersister.NotFoundException
{
    log.info("****** Ottengo l'user con numeroRegistrazione " + registrationNumber + " *******");

    List<UserDto> user = userService.SelByRegistrationNumber(registrationNumber);



    return new ResponseEntity<List<UserDto>>(user, HttpStatus.OK);
}

@GetMapping(value = "/utenti", produces = "application/json")
public ResponseEntity<List<UserDto>> listAllUsers ()throws ChangeSetPersister.NotFoundException{


    List<UserDto> user = userService.SelTutti();



    return new ResponseEntity<List<UserDto>>(user, HttpStatus.OK);

}
}

application.properties配置

spring.datasource.url = jdbc:oracle:thin:@192.134.2.82:1521/orcl

spring.datasource.username =admin
spring.datasource.password =zzzx
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver



# JPA settings
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect
spring.jpa.hibernate.use-new-id-generator-mappings=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

解决方案

这个错误核心是Hibernate懒加载代理对象无法被Jackson序列化:使用FetchType.LAZY关联实体时,Hibernate会生成ByteBuddy代理类替代真实实体,Jackson序列化这些代理时会访问内部的hibernateLazyInitializer属性,而该属性无对应序列化器,导致报错。

以下是几种可行解决办法,按推荐优先级排序:

1. DTO中避免直接引用Entity类(最推荐)

当前UserDto直接引用Role、Company等Entity类是问题根源。正确做法是为关联实体创建对应DTO,仅暴露需要返回的字段:

比如创建RoleDto:

@Data
public class RoleDto {
    private Long id;
    private String roleName;
    // 其他需要返回的字段
}

修改UserDto中的关联字段:

// 替换原有的Role applicationRoleID;
private RoleDto applicationRoleID;
// 同理将Company、Direction等字段替换为对应DTO

在Service层转换时,手动复制Entity属性到DTO,或用MapStruct工具简化转换,彻底避免序列化代理对象的问题。

2. 禁用Jackson的FAIL_ON_EMPTY_BEANS特性

在Spring Boot配置中添加以下内容,让Jackson忽略空对象的序列化错误:

spring.jackson.serialization.fail-on-empty-beans=false

或通过配置类手动配置:

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        return mapper;
    }
}

此方法简单但属于治标不治本,可能隐藏其他序列化问题,不推荐长期使用。

3. 强制加载懒加载关联对象

在Service层查询User时,使用JOIN FETCH强制加载需要的关联实体,避免生成代理对象:

// 在UserRepository的查询方法中使用JOIN FETCH
@Query("SELECT u FROM User u JOIN FETCH u.applicationRoleID JOIN FETCH u.companyID ...")
List<User> findAllWithAssociations();

适合关联实体较少的场景,但关联层级复杂时会导致查询语句臃肿,还可能引发N+1查询问题。

4. 使用Hibernate的@JsonIgnoreProperties注解

在Entity类的懒加载字段上添加注解,让Jackson忽略代理对象的内部属性:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "application_role_id")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private Role applicationRoleID;

无需修改DTO,但如果关联实体本身有空字段,仍可能触发序列化问题,且会暴露整个Entity的字段,不符合DTO设计原则。


内容的提问来源于stack exchange,提问作者Michele Raso

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 20:50:30