SpringBoot getOne 报错 hibernateLazyInitializer

具体重现的例子参照这个Tag: https://github.com/icbd/SpringBoardToDo/releases/tag/q.getOne

报错如下:

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: org.springboardtodo.model.TaskqfPD64HV["hibernateLazyInitializer"])

为什么

如果换用 findById 会发现就没有报错了, 这又是为什么.

/**
     * Retrieves an entity by its id.
     *
     * @param id must not be {@literal null}.
     * @return the entity with the given id or {@literal Optional#empty()} if none found.
     * @throws IllegalArgumentException if {@literal id} is {@literal null}.
     */
    Optional findById(ID id);
    /**
     * Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is
     * implemented this is very likely to always return an instance and throw an
     * {@link javax.persistence.EntityNotFoundException} on first access. Some of them will reject invalid identifiers
     * immediately.
     *
     * @param id must not be {@literal null}.
     * @return a reference to the entity with the given identifier.
     * @see EntityManager#getReference(Class, Object) for details on when an exception is thrown.
     */
    T getOne(ID id);

他们除了返回类型不同, 再就是, findById 是 EAGER 加载; getOne 是 LAZY 加载, 得到的是一个实体的引用, 这导致 Hibernate 用于维护懒加载逻辑的属性也被 Jackson 读去做序列化, Jackson 不会做就抛异常了.

怎么办

  • 方法1:
    换用 findById.
    大部分情况下你感觉不到他们的差别, 除非你只想用该Entity的Id而不关心其他具体属性的时候, 才会特别想用 getOne, 具体参考 Difference between getOne and findById in Spring Data JPA?

  • 方法2:
    让 Jackson 忽略异常.
    application.properties里添加配置:

spring.jackson.serialization.fail-on-empty-beans=false
  • 方法3:
    让 Jackson 忽略额外的属性.
@Entity
@JsonIgnoreProperties(ignoreUnknown = true, value = {"hibernateLazyInitializer", "handler", "fieldHandler"})
public class User {
  //...
}
  • 方法4:
    使用 Jackson 插件: https://github.com/FasterXML/jackson-datatype-hibernate
    它使得Jackson序列化的时候忽略所有的懒加载的属性, 实现了按需加载, 也就自然解决了这个问题.

  • 方法5:
    把原始的 Entity 转为 DTO 再对外暴露.
    具体参见: https://mapstruct.org/

其他参考

https://blog.csdn.net/lihushiwoa/article/details/21973695
https://blog.csdn.net/jxchallenger/article/details/79307062
jackson-datatype-hibernate5

你可能感兴趣的:(SpringBoot getOne 报错 hibernateLazyInitializer)