没有为org.hibernate.proxy.pojo.javassist.Javassist类找到序列化器?


94

我正在处理SpringMVCHibernate&,JSON但出现此错误。

HTTP Status 500 - Could not write JSON: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.SerializationFeature.FAIL_ON_EMPTY_BEANS) ) 

请在下面检查我的实体

    @Entity
@Table(name="USERS")
public class User {

    @Id
    @GeneratedValue
    @Column(name="USER_ID")
    private Integer userId;

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

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


    @Column(name="USER_MIDDLE_NAME")
    private String middleName;

    @Column(name="USER_EMAIL_ID")
    private String emailId;

    @Column(name="USER_PHONE_NO")
    private Integer phoneNo;

    @Column(name="USER_PASSWORD")
    private String password;

    @Column(name="USER_CONF_PASSWORD")
    private String  confPassword;

    @Transient
    private String token;

    @Column(name="USER_CREATED_ON")
    private Date createdOn;

    @OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
    @Fetch(value = FetchMode.SUBSELECT)
    @JoinTable(name = "USER_ROLES", joinColumns = { @JoinColumn(name = "USER_ID") }, inverseJoinColumns = { @JoinColumn(name = "ROLE_ID") })
    private List<ActifioRoles> userRole = new ArrayList<ActifioRoles>();


    @OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL,mappedBy="userDetails")
    @Fetch(value = FetchMode.SUBSELECT)
    private List<com.actifio.domain.Address> userAddress = new ArrayList<com.actifio.domain.Address>();

    @OneToOne(cascade=CascadeType.ALL)
    private Tenant tenantDetails;


    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEmailId() {
        return emailId;
    }
    public void setEmailId(String emailId) {
        this.emailId = emailId;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getConfPassword() {
        return confPassword;
    }
    public void setConfPassword(String confPassword) {
        this.confPassword = confPassword;
    }
    public Date getCreatedOn() {
        return createdOn;
    }
    public void setCreatedOn(Date createdOn) {
        this.createdOn = createdOn;
    }

    public List<ActifioRoles> getUserRole() {
        return userRole;
    }

    public void setUserRole(List<ActifioRoles> userRole) {
        this.userRole = userRole;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
        this.middleName = middleName;
    }
    public Integer getPhoneNo() {
        return phoneNo;
    }
    public void setPhoneNo(Integer phoneNo) {
        this.phoneNo = phoneNo;
    }

    public List<com.actifio.domain.Address> getUserAddress() {
        return userAddress;
    }
    public void setUserAddress(List<com.actifio.domain.Address> userAddress) {
        this.userAddress = userAddress;
    }
    public Tenant getTenantDetails() {
        return tenantDetails;
    }
    public void setTenantDetails(Tenant tenantDetails) {
        this.tenantDetails = tenantDetails;
    }
    public String getToken() {
        return token;
    }
    public void setToken(String token) {
        this.token = token;
    }

    }

我该如何解决?


请显示
堆栈跟踪

在不了解代码要做什么的情况下,调试起来有些困难,但是由于您使用的是Jackson和Hibernate ,因此您可能想查看github.com/FasterXML/jackson-datatype-hibernate
geoand

您是否正在尝试通过此类制作JSON?在这种情况下,JSON序列化程序将尝试写入所有属性,以及多对多关系的HashSet;这会导致一个懒惰的初始化程序异常
Angelo Immediata 2014年


@ user2963481 ...很好,非常有帮助的问题,兄弟。
Brain

Answers:


192

通过休眠代理对象进行延迟加载时,我遇到了类似的问题。通过用以下方式注释具有延迟加载的私有属性的类来解决此问题:

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})

我假设您可以在代理对象上添加打破JSON序列化到该批注的属性。

问题在于实体是延迟加载的,序列化是在实体完全加载之前发生的。

Hibernate.initialize(<your getter method>);

3
它也对我有用...这种奇怪行为有什么解释吗?
维克多

7
@ ankur-singhal您应该强调在嵌套类而不是调用类上需要此批注。
达尔文

1
Yahooo ...有效。我尝试了几次并工作。我和BoooM尝试了几种方法。工作了
Brain

2
谢谢也为我工作。您需要将此注释添加到访问具有延迟加载bean的其他实体的实体。
Shafqat Shafi '18

3
我认为这不是解决此问题的正确方法。当我们进行序列化时,我们期望将完整的子对象或该子对象的至少主键返回到结果中。添加这些注释只会抑制错误,但不会为您提供所需的结果。
阿南·瓦迪亚

84

只是为了添加这个,我遇到了同样的问题,但是提供的答案不起作用。我通过采取异常的建议并将其添加到application.properties文件中来对其进行修复...

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

我在Hibernate 4.3中使用Spring Boot v1.3

现在,它将整个对象和嵌套对象序列化。

编辑:2018

由于这仍然引起评论,因此我将在此处进行澄清。这绝对只会隐藏错误。性能影响在那里。当时,我需要一些东西来交付并在以后进行处理(通过不再使用spring来完成)。是的,如果您确实想解决此问题,请听其他人的话。如果您只是想暂时解决,请继续使用此答案。这是一个糟糕的主意,但可能对您有用。记录下来,此后再也没有发生崩溃或问题。但这可能是导致SQL性能噩梦的根源。


8
解决了问题,但是json将包含两个额外的不需要的属性"handler":{},"hibernateLazyInitializer":{}
prettyvoid

大!也固定在这里,这就是答案
Hinotori

@prettyvoid为什么存在额外的属性?
罗伯特·月亮

12
@RobertMoon如果您想摆脱它们,您可以通过@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
prettyvoid '16

@prettyvoid谢谢。我发现另一个解决方案是将LAZY更改为EAGER。它对演奏有影响吗?
罗伯特·月亮

68

正如先前答案中正确建议的那样,延迟加载意味着从数据库中获取对象时,不会获取嵌套的对象(以后可能会在需要时获取)。

现在,Jackson尝试序列化嵌套对象(==使它成为JSON),但是由于找到JavassistLazyInitializer而不是普通对象而失败。这是您看到的错误。现在,如何解决呢?

如CP510之前建议的那样,一种选择是通过以下配置行来抑制错误:

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

但这是在处理症状,而不是原因。为了优雅地解决它,您需要确定是否需要JSON中的此对象?

  1. 如果您需要JSON中的对象,请FetchType.LAZY从导致它的字段中删除该选项(它也可能是某些嵌套对象中的字段,不仅是您要获取的根实体中的字段)。

  2. 如果不需要JSON中的对象,请使用来注释此字段的getter(或字段本身,如果您也不需要接受传入的值)@JsonIgnore,例如:

    // this field will not be serialized to/from JSON @JsonIgnore private NestedType secret;

如果您有更复杂的需求(例如,使用同一实体的不同REST控制器的规则不同),则可以使用杰克逊视图过滤,或者对于非常简单的用例,可以分别获取嵌套的对象。


15
这是最好的答案。解决问题的根源,不要只是掩盖症状,让下一个程序员必须应对。
安德鲁(Andrew)

2
你是我的英雄。
Lay Leangsros,

非常感谢您解释错误的原因并提供了两个有意义的解决方案
Mauricio Poppe

谢谢,但是我看到springfox-swagger仍然给我错误RangeError: Maximum call stack size exceeded
Pra_A

18

您可以使用Jackson的附加模块来处理Hibernate延迟加载。

有关https://github.com/FasterXML/jackson-datatype-hibernate的更多信息,请分别支持休眠3和休眠4。


7
这应该是正确的答案。所有其他答案都是隐藏问题而不是解决问题。
艾哈迈德·哈桑宁

但是如何使用这个模块呢?有什么指南吗?
阿南·瓦迪亚

配置jackson-datatype-hibernate的方法:stackoverflow.com/q/33727017
Chase

13

我认为问题在于您检索实体的方式。

也许您正在执行以下操作:

Person p = (Person) session.load(Person.class, new Integer(id));

尝试使用方法 get代替load

Person p = (Person) session.get(Person.class, new Integer(id));

问题在于,使用load方法时,您只会得到一个代理,而没有真正的对象。代理对象尚未加载属性,因此在进行序列化时,没有要序列化的属性。使用get方法,您实际上获得了真实的对象,实际上该对象可以被序列化。


2
当我使用getOne而不是findOne时,发生了一个非常类似的错误。就我而言,我的接口存储库正在扩展JpaRepository。findOne运作良好,没有任何Json注释或application.properties发生更改
James Freitas

像James Freitas一样,我还发现getOne导致了问题,例如,使用findById-解决了问题,而无需在应用程序属性中使用注释或上面的给定行
MY

1
我的同事澄清了这一点,并告诉我:“基本区别是getOne是延迟加载的,而findOne不是。”-显然这意味着前者实际上并没有从db获取数据行,而只是创建了引用。后者实际上是获得行,而这通常是需要的情况
MY

@JamesFreitas是的!谢谢!还要感谢卡洛斯(Carlos)带领詹姆斯得出了这个不错的结论!
Filip Savic

9

这个对我有用

@JsonIgnoreProperties({"hibernateLazyInitializer","handler"})

例如

@Entity
@Table(name = "user")
@Data
@NoArgsConstructor
@JsonIgnoreProperties({"hibernateLazyInitializer","handler"})
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private Date created;

}

5

有两种方法可以解决此问题。

方式1

添加 spring.jackson.serialization.fail-on-empty-beans=falseapplication.properties

方式二

join fetch在JPQL查询中使用以检索父对象数据,请参见下文:

@Query(value = "select child from Child child join fetch child.parent Parent ",
           countQuery = "select count(*) from Child child join child.parent parent ")
public Page<Parent> findAll(Pageable pageable); 

谢谢!第一个解决方案很棒!
Lucas Moyano Angelini

方式1.很棒。谢谢。
Lay Leangsros

3

将此注释添加到对我有用的实体类(模型)中,这会导致通过休眠代理对象延迟加载。

@JsonIgnoreProperties({“ hibernateLazyInitializer”,“ handler”})


2

此例外

org.springframework.http.converter.HttpMessageNotWritableException

因为我希望如此,您正在将响应输出作为Serializable对象发送。
这是在春天发生的问题。要解决此问题,请发送POJO对象作为响应输出。

范例:

    @Entity
    @Table(name="user_details")
    public class User implements Serializable{

        @Id
        @GeneratedValue(strategy= GenerationType.IDENTITY)
        @Column(name="id")
        private Integer id;

        @Column(name="user_name")
        private String userName;

        @Column(name="email_id")
        private String emailId;

        @Column(name="phone_no")
        private String phone;

//setter and getters

POJO类:

public class UserVO {

    private int Id;
    private String userName;
    private String emailId;
    private String phone;
    private Integer active;

//setter and getters

在控制器中,将可序列化的对象字段转换为POJO类字段,并返回pojo类作为输出。

         User u= userService.getdetials(); // get data from database

        UserVO userVo= new UserVO();  // created pojo class object

        userVo.setId(u.getId());
        userVo.setEmailId(u.getEmailId());
        userVo.setActive(u.getActive());
        userVo.setPhone(u.getPhone());
        userVo.setUserName(u.getUserName());
       retunr userVo;  //finally send pojo object as output.

是的,我正在执行相同的操作,但是即使执行相同的操作,也会遇到相同的错误,因为我正在发送与对象相关的数据,这些数据只不过是设置实体类
Pra_A

2

在Hibernate 5.2及更高版本中,您可以按以下方式删除hibernate代理,它将为您提供实际的对象,以便您可以正确地序列化它:

Object unproxiedEntity = Hibernate.unproxy( proxy );

它也会自动自动调用Hibernate.initialize
GMsoF

@Tim,应在json序列化之前添加它。发生此问题是因为在序列化过程中发现了休眠代理对象,因此一旦将其删除,序列化就可以了。如果使用弹簧控制器,则必须在控制器结束之前进行。
GMsoF

1

对于Hibernate,您可以使用jackson-datatype-hibernate项目来适应具有延迟加载对象的JSON序列化/反序列化。

例如,

import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonDatatypeHibernate5Configuration {

    // Register Jackson Hibernate5 Module to handle JSON serialization of lazy-loaded entities
    // Any beans of type com.fasterxml.jackson.databind.Module are automatically
    // registered with the auto-configured Jackson2ObjectMapperBuilder
    // https://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html#howto-customize-the-jackson-objectmapper
    @Bean
    public Module hibernate5Module() {
        Hibernate5Module hibernate5Module = new Hibernate5Module();
        hibernate5Module.enable( Hibernate5Module.Feature.FORCE_LAZY_LOADING );
        hibernate5Module.disable( Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION );
        return hibernate5Module;
    }
}

如果我用这个,我会得到can't parse JSON. Raw result:。有什么帮助吗?
Pra_A

1

该解决方案的灵感来自@marco的以下解决方案。我还用这些数据更新了他的答案。

这里的问题是关于子对象的延迟加载,在这种情况下,Jackson只找到休眠的代理,而不是完整的对象。

因此,我们有两个选择-抑制异常,就像上面大多数投票答案中所做的那样,或者确保加载LazyLoad对象。

如果选择使用后一种选项,则解决方案是使用jackson-datatype库,并配置该库以在序列化之前初始化延迟加载依赖性。

我添加了一个新的配置类来做到这一点。

@Configuration
public class JacksonConfig extends WebMvcConfigurerAdapter {

@Bean
@Primary
public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
    MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
    ObjectMapper mapper = new ObjectMapper();
    Hibernate5Module module = new Hibernate5Module();
    module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);
    mapper.registerModule(module);
    messageConverter.setObjectMapper(mapper);
    return messageConverter;
}

}

@Primary确保没有其他Jackson配置可用于初始化任何其他bean。@Bean和往常一样。module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);用于启用依赖项的延迟加载。

注意-请注意其性能影响。有时EAGER提取会有所帮助,但是即使您渴望它,您仍将需要此代码,因为除其他映射之外,所有其他映射仍然存在代理对象@OneToOne

PS:作为一般性评论,我不鼓励在Json响应中发送回整个数据对象的做法,应该使用Dto进行此通信,并使用诸如mapstruct之类的映射器来映射它们。这样可以避免意外的安全漏洞以及上述异常。


1

我现在有同样的问题。检查是否使用@jsonIQgnore修复了延迟获取

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="teachers")
@JsonIgnoreProperties("course")
Teacher teach;

只需删除“(fetch = ...)”或注释“ @jsonIgnore”,它将起作用

@ManyToOne
@JoinColumn(name="teachers")
@JsonIgnoreProperties("course")
Teacher teach;

0

或者,您可以将mapper配置为:

//延迟加载的自定义配置

public static class HibernateLazyInitializerSerializer extends JsonSerializer<JavassistLazyInitializer> {

    @Override
    public void serialize(JavassistLazyInitializer initializer, JsonGenerator jsonGenerator,
            SerializerProvider serializerProvider)
            throws IOException, JsonProcessingException {
        jsonGenerator.writeNull();
    }
}

并配置映射器:

    mapper = new JacksonMapper();
    SimpleModule simpleModule = new SimpleModule(
            "SimpleModule", new Version(1,0,0,null)
    );
    simpleModule.addSerializer(
            JavassistLazyInitializer.class,
            new HibernateLazyInitializerSerializer()
    );
    mapper.registerModule(simpleModule);

0

可能是您的Hibernate实体关系引起了问题...只是停止了对该相关实体的延迟加载...例如...我在下面通过为customerType设置lazy =“ false”来解决。

<class name="Customer" table="CUSTOMER">
        <id name="custId" type="long">
            <column name="CUSTID" />
            <generator class="assigned" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        <property name="phone" type="java.lang.String">
            <column name="PHONE" />
        </property>
        <property name="pan" type="java.lang.String">
            <column name="PAN" />
        </property>

        <many-to-one name="customerType" not-null="true" lazy="false"></many-to-one>
    </class>
</hibernate-mapping>

1
请在您的帖子中告知,这在现实生活中可能是非常危险的解决方案。
panurg

0

我更改了(在注释模型类中)

提取= FetchType.LAZY

提取= FetchType.EAGER

并以漂亮的方式工作...

爱它。


5
尽管这确实解决了问题,但非常危险。更改fetch模型的策略会对性能产生若干影响。进行此更改后,您将从数据库中获取更多数据。这可能是一个有效的解决方案,但首先需要进行性能研究。
若昂Menighin

1
如果您知道自己是模范的,并且不会有很多实体相关,则可以花一点时间和精力来获得完整的实体。但很高兴知道,最好使用LAZY提取
Sham Fiorin '18

0

这是杰克逊的问题。为避免这种情况,请指示Jackson不要序列化嵌套关系或嵌套类。

看下面的例子。映射到CityStateCountry类的地址类,State本身指向Country,而Country则指向Region。当您通过Spring boot REST API获取地址值时,会出现上述错误。为防止这种情况,只需序列化映射的类(反映一级JSON),并忽略带有 ,@JsonIgnoreProperties(value = {"state"})@JsonIgnoreProperties(value = {"country"})@JsonIgnoreProperties(value = {"region"})

这将防止Lazyload异常以及上述错误。使用以下代码作为示例,然后更改模型类。

地址.java

@Entity
public class Address extends AbstractAuditingEntity
{
    private static final long serialVersionUID = 4203344613880544060L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "street_name")
    private String streetName;

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

    @ManyToOne
    @JoinColumn(name = "city_id")
    @JsonIgnoreProperties(value = {"state"})
    private City city;

    @ManyToOne
    @JoinColumn(name = "state_id")
    @JsonIgnoreProperties(value = {"country"})
    private State state;

    @ManyToOne
    @JoinColumn(name = "country_id")
    @JsonIgnoreProperties(value = {"region"})
    private Country country;

    @ManyToOne
    @JoinColumn(name = "region_id")
    private Region region;

    @Column(name = "zip_code")
    private String zipCode;

    @ManyToOne
    @JoinColumn(name = "address_type_id", referencedColumnName = "id")
    private AddressType addressType;

}

City.java

@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "city")
@Cache(region = "cityCache",usage = CacheConcurrencyStrategy.READ_WRITE)
@Data
public class City extends AbstractAuditingEntity
{
    private static final long serialVersionUID = -8825045541258851493L;

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    //@Length(max = 100,min = 2)
    private String name;


    @ManyToOne
    @JoinColumn(name = "state_id")
    private State state;
}

State.java

@Entity
@Table(name = "state")
@Data
@EqualsAndHashCode(callSuper = true)
public class State extends AbstractAuditingEntity
{
    private static final long serialVersionUID = 5553856435782266275L;

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

    @Column(name = "name")
    @Length(max = 200, min = 2)
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "country_id")
    private Country country;

}

Country.java

@Entity
@Table(name = "country")
@Data
@EqualsAndHashCode(callSuper = true)
public class Country extends AbstractAuditingEntity
{
    private static final long serialVersionUID = 6396100319470393108L;

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    @Length(max = 200, min = 2)
    private String name;

    @Column(name = "code")
    @Length(max = 3, min = 2)
    private String code;

    @Column(name = "iso_code")
    @Length(max = 3, min = 2)
    private String isoCode;

    @ManyToOne
    @JoinColumn(name = "region_id")
    private Region region;
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.