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

Jackson序列化Hibernate懒加载代理类报错问题排查

问题描述

已检查所有实体模型,所有属性均具备getter和setter方法。通过添加配置spring.jackson.serialization.fail-on-empty-beans=false可临时规避报错,但这仅为隐藏异常的权宜之计,想了解该问题的根本原因是什么?

异常详情

org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.auzmor.platform.models.results.notes.NoteResult["mentions"]->java.util.ArrayList[0]->com.auzmor.platform.models.entities.Employee_$$_jvst80f_13["handler"])

错误请求信息

ServletWebRequest: uri=/api/v1/notes;client=0:0:0:0:0:0:0:1;user=com.auzmor.platform.configurations.auth.CustomPrincipal@3d7c4c43
错误信息:Type definition error: [simple type, class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.auzmor.platform.models.results.notes.NoteResult["mentions"]->java.util.ArrayList[0]->com.auzmor.platform.models.entities.Employee_$$jvst80f_13["handler"])
错误原因:com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.auzmor.platform.models.results.notes.NoteResult["mentions"]->java.util.ArrayList[0]->com.auzmor.platform.models.entities.Employee
$$_jvst80f_13["handler"])

相关实体类代码

CandidateComment

@Data
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "candidate_comments")
@DynamicInsert
@javax.persistence.Entity
@DynamicUpdate
@ToString
public class CandidateComment extends Entity implements Serializable {

    @ApiModelProperty(notes="Text of the note")
    @Size(min = MIN_SIZE, message="text should have at least 1 characters")
    @Size(max = MAX_TEXT_SIZE, message="text should not exceed 2048 characters")
    private String text;

    private boolean isExternalAgency;

    @JsonBackReference
    @OneToMany(mappedBy = "comment", fetch = FetchType.EAGER ,cascade = CascadeType.ALL)
    @JsonIgnoreProperties("comment")
    protected List<CommentMention> mentions;


    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "author_id", insertable = false, updatable = false)
    @JsonIgnoreProperties({"fullName","mobile"})
    protected Employee author;

    @JsonIgnore
    @Column(name = "author_id")
    protected Long authorPK;


    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "candidate_id", insertable = false, updatable = false)
    protected Candidate candidate;

    @JsonIgnore
    @Column(name = "candidate_id")
    protected Long candidatePK;

}

CommentMention

@Getter
@Setter
@AllArgsConstructor
@Table(name = "comment_mentions")
@DynamicInsert
@javax.persistence.Entity
@DynamicUpdate
@NoArgsConstructor
public class CommentMention extends BaseEntity implements Serializable {

    @JsonBackReference
    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "comment_id", insertable = false, updatable = false)
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    protected CandidateComment comment;

    @JsonIgnore
    @Column(name = "comment_id")
    protected Long commentPK;

    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "user_id", insertable = false, updatable = false)
    @JsonIgnoreProperties({"fullName","mobile"})
    protected Employee user;

    @JsonIgnore
    @Column(name = "user_id")
    protected Long userPK;

}

根本原因分析

从异常的引用链可以明确问题根源:

  1. CommentMention中的user字段采用FetchType.LAZY懒加载策略,Hibernate会为Employee实体生成代理类(如Employee_$$_jvst80f_13),该代理类包含handler属性(类型为JavassistLazyInitializer),用于控制懒加载的初始化逻辑。
  2. 当Spring MVC序列化NoteResult为JSON时,Jackson遍历到mentions列表中的CommentMention对象,进而访问其user属性。此时user的代理对象未被初始化(未触发数据库查询加载真实数据),Jackson会尝试序列化代理对象的所有属性,包括handler。
  3. JavassistLazyInitializer类没有Jackson可识别的可序列化属性(无公开字段或可被检测到的getter方法),而Jackson默认的FAIL_ON_EMPTY_BEANS特性会对这类对象抛出序列化异常。

你添加的临时配置只是关闭了异常检测,跳过空对象序列化,但并未解决代理对象被错误序列化的核心问题。


解决方案

1. 配置Jackson Hibernate模块(推荐)

添加Jackson专门处理Hibernate懒加载的模块(如jackson-datatype-hibernate5),它能自动识别Hibernate代理对象,只序列化真实实体数据,忽略代理相关属性:

  • Maven依赖:
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>
  • Spring配置注册模块:
@Configuration
public class JacksonConfig {
    @Bean
    public Module hibernateModule() {
        return new Hibernate5Module();
    }
}

2. 修正实体的@JsonIgnoreProperties配置

在CommentMention的user字段上,添加忽略代理相关属性的配置:

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "fullName","mobile"})
protected Employee user;

让Jackson序列化时跳过handler和hibernateLazyInitializer属性,避免触发异常。

3. 确保懒加载关联在序列化前初始化

在业务逻辑层提前触发懒加载关联的初始化:

// 调用任意get方法触发懒加载
commentMention.getUser().getId();
// 或使用Hibernate工具类初始化
Hibernate.initialize(commentMention.getUser());

也可以在JPQL查询中使用FETCH JOIN,一次性加载关联的Employee数据:

SELECT cm FROM CommentMention cm JOIN FETCH cm.user WHERE ...

4. 移除临时配置

不要长期使用spring.jackson.serialization.fail-on-empty-beans=false,它会掩盖其他真实的空对象序列化问题,导致业务异常无法及时发现。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:33:23