我正在处理SpringMVC
,Hibernate
& 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;
}
}
我该如何解决这个问题?
答案 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中的对象?
如果您需要JSON中的对象,请从导致它的字段中删除FetchType.LAZY
选项(它也可能是某个嵌套对象中的字段,而不仅仅是您要提取的根实体中的字段)
如果不需要JSON中的对象,请使用@JsonIgnore
注释此字段的getter(或字段本身,如果您不需要接受传入值),例如:
// this field will not be serialized to/from JSON
@JsonIgnore
private NestedType secret;
如果您有更复杂的需求(例如,使用相同实体的不同REST控制器的不同规则),您可以使用jackson views或filtering或非常简单的用例,单独获取嵌套对象。
答案 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