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

时间:2014-07-28 11:37:50

标签: json spring hibernate

我正在处理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;
    }

    }

我该如何解决这个问题?

18 个答案:

答案 0 :(得分:141)

我在通过hibernate代理对象进行延迟加载时遇到了类似的问题。通过使用:

注释具有延迟加载的私有属性的类来解决它
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})

我假设您可以在代理对象上添加将JSON序列化分解为该批注的属性。

问题是实体是懒惰加载的,序列化在完全加载之前就已经发生了。

Hibernate.initialize(<your getter method>);

答案 1 :(得分:65)

只是为了添加它,我遇到了同样的问题,但提供的答案不起作用。我通过获取异常的建议并添加到application.properties文件...

来修复它
{{1}}

我正在使用带有Hibernate 4.3的Spring Boot v1.3

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

编辑:2018

由于这仍然得到评论,我将在此澄清。此绝对仅隐藏错误。性能影响是存在的。当时,我需要一些东西来交付并在以后工作(我不再使用弹簧了)。所以是的,如果你真的想解决这个问题,请听别人的意见。如果你现在只想让它消失,请继续使用这个答案。这是一个可怕的想法,但是,它可能对你有用。为了记录,在此之后再也没有发生过崩溃或问题。但它可能是最终成为SQL性能噩梦的根源。

答案 2 :(得分:56)

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

现在Jackson尝试序列化嵌套对象(==从中生成JSON),但是失败了,因为它找到了JavassistLazyInitializer而不是普通对象。这是你看到的错误。现在,如何解决?

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

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

但这是处理症状,而不是原因。要优雅地解决它,你需要决定是否需要这个JSON中的对象?

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

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

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

  3. 如果您有更复杂的需求(例如,使用相同实体的不同REST控制器的不同规则),您可以使用jackson viewsfiltering或非常简单的用例,单独获取嵌套对象。

答案 3 :(得分:13)

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

关于https://github.com/FasterXML/jackson-datatype-hibernate的更多信息,它们分别支持hibernate 3和4。

答案 4 :(得分: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方法实际上可以获得真实对象,这个对象实际上可以被序列化。

答案 5 :(得分:3)

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

  

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

答案 6 :(得分:2)

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

Object unproxiedEntity = Hibernate.unproxy( proxy );

答案 7 :(得分:2)

对我有用

@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;

}

答案 8 :(得分:1)

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

方法1

添加 spring.jackson.serialization.fail-on-empty-beans=false进入 application.properties

方法2

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

@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); 

答案 9 :(得分: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;
    }
}

答案 10 :(得分:0)

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

对我有用

答案 11 :(得分:0)

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

before="$(sha256sum Migrations/*Snapshot.cs | sha256sum)"
dotnet ef migrations add dummy
after="$(sha256sum Migrations/*Snapshot.cs | sha256sum)"
if [ "$before" != "$after" ]; then
    exit 1
fi

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

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

答案 12 :(得分:0)

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

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

这将防止Lazyload异常以及上述错误。以下面的代码为例,并更改您的模型类。

Address.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;
}

答案 13 :(得分:0)

该解决方案的灵感来自@marco的以下解决方案。

这里的问题是依赖项的延迟加载,因此合适的解决方案是使用jackson-databind库,并配置该库以在序列化之前初始化延迟加载的依赖项。

我添加了一个新的配置类。

@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确保没有其他杰克逊配置用于初始化任何其他bean。 @Bean和往常一样。 module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);用于启用依赖项的延迟加载。

警告-请注意其性能影响。有时EAGER提取会有所帮助,但是即使您急于执行,也仍然需要此代码,因为除@OneToOne

以外的所有其他映射仍然存在代理对象

答案 14 :(得分:0)

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

  

fetch = FetchType.LAZY

  

fetch = FetchType.EAGER

并且工作得很好...

爱它。

答案 15 :(得分: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>

答案 16 :(得分: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:

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

答案 17 :(得分:-4)

尝试

implements interface Serializable