Hibernate 延迟加载抛出 JsonMappingException
Hibernate lazy loading throws JsonMappingException
我知道有很多关于我会告诉你的相同问题的问题,但是 none 已经解决了我的问题。
我实现了一项服务,该服务必须通过延迟加载访问对象 属性。这是 class:
的简化
@Entity
public class Treatment {
private Long treatmentId;
private UserAccount patient;
private Regimen regimen;
private Medicine medicine;
public Treatment() { }
@SequenceGenerator( // It only takes effect for
name = "TreatmentIdGenerator", // databases providing identifier
sequenceName = "TreatmentSeq")// generators.
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "TreatmentIdGenerator")
public Long getTreatmentId() {
return treatmentId;
}
public void setTreatmentId(Long treatmentId) {
this.treatmentId = treatmentId;
}
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "patient")
public UserAccount getPatient() {
return patient;
}
public void setPatient(UserAccount patient) {
this.patient = patient;
}
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "regimen")
public Regimen getRegimen() {
return regimen;
}
public void setRegimen(Regimen regimen) {
this.regimen = regimen;
}
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "medicine")
public Medicine getMedicine() {
return medicine;
}
public void setMedicine(Medicine medicine) {
this.medicine = medicine;
}
}
具体来说,我需要得到一个 Regimen
属性。所以将下一个注释放在 class 中对我无效:
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
我尝试将 OpenSessionInViewFilter
添加到我的 WebApplicationInitializer,如下所示:
public class DiaryInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
OpenSessionInViewFilter openSessionInView = new OpenSessionInViewFilter();
openSessionInView.setSessionFactoryBeanName("sessionFactory");
servletContext.addFilter("openSessionInView", openSessionInView)
.addMappingForUrlPatterns(null, false, "/*");
// add other filters like this
super.onStartup(servletContext);
}
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { DiaryConfiguration.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
这是我对杰克逊的依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
这些是我遇到的错误:
com.fasterxml.jackson.databind.JsonMappingException: 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: es.udc.fic.tfg.mferreiro.diary.model.treatmentservice.TreatmentDetails["regimen"]->es.udc.fic.tfg.mferreiro.diary.model.regimen.Regimen_$$_jvstbae_3["handler"])
com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:59)
com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:26)
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:575)
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:666)
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:156)
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:575)
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:666)
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:156)
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:129)
com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:851)
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:264)
org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:222)
org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:183)
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:80)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:860)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:151)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
注意:我使用的是 Hibernate 4 和 Spring MVC 4
任何帮助将不胜感激,在此先感谢!
背景
当 hibernate 从数据库中加载具有惰性非空关系的实体时,它(通常)会为引用的实体创建一个惰性加载代理,并将该代理对象放入对应的 属性正在加载的对象。此代理对象将扩展 class 或引用实体的接口,并且从该 class 或接口调用任何方法都会导致代理对象初始化,从数据库中获取数据(这仅在会话仍然打开时工作,否则初始化将抛出异常)和 returns 加载的数据。
您的 OpenSessionInViewFilter 在整个请求处理期间保持会话打开,因此如果有人在代理对象上调用 getter,代理对象将成功初始化而不是抛出 LazyInitializationException。
然而,您的 JsonProcessingException 发生在此之前。这表明 Jackson 不知道应该以什么形式序列化这样一个代理对象。
解决方案
标准解决方案正在使用 jackson-datatype-hibernate。该模块还允许您配置 Jackson 是应该初始化代理(即从数据库中获取状态)还是只序列化所引用实体的身份。后者允许您灵活地控制应将多少数据写入响应(通过仅初始化客户端需要的关系),并且不需要 OpenSessionInViewFilter(因为代理提前初始化,或者根本不初始化)。
我知道有很多关于我会告诉你的相同问题的问题,但是 none 已经解决了我的问题。
我实现了一项服务,该服务必须通过延迟加载访问对象 属性。这是 class:
的简化@Entity
public class Treatment {
private Long treatmentId;
private UserAccount patient;
private Regimen regimen;
private Medicine medicine;
public Treatment() { }
@SequenceGenerator( // It only takes effect for
name = "TreatmentIdGenerator", // databases providing identifier
sequenceName = "TreatmentSeq")// generators.
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "TreatmentIdGenerator")
public Long getTreatmentId() {
return treatmentId;
}
public void setTreatmentId(Long treatmentId) {
this.treatmentId = treatmentId;
}
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "patient")
public UserAccount getPatient() {
return patient;
}
public void setPatient(UserAccount patient) {
this.patient = patient;
}
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "regimen")
public Regimen getRegimen() {
return regimen;
}
public void setRegimen(Regimen regimen) {
this.regimen = regimen;
}
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "medicine")
public Medicine getMedicine() {
return medicine;
}
public void setMedicine(Medicine medicine) {
this.medicine = medicine;
}
}
具体来说,我需要得到一个 Regimen
属性。所以将下一个注释放在 class 中对我无效:
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
我尝试将 OpenSessionInViewFilter
添加到我的 WebApplicationInitializer,如下所示:
public class DiaryInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
OpenSessionInViewFilter openSessionInView = new OpenSessionInViewFilter();
openSessionInView.setSessionFactoryBeanName("sessionFactory");
servletContext.addFilter("openSessionInView", openSessionInView)
.addMappingForUrlPatterns(null, false, "/*");
// add other filters like this
super.onStartup(servletContext);
}
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { DiaryConfiguration.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
这是我对杰克逊的依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
这些是我遇到的错误:
com.fasterxml.jackson.databind.JsonMappingException: 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: es.udc.fic.tfg.mferreiro.diary.model.treatmentservice.TreatmentDetails["regimen"]->es.udc.fic.tfg.mferreiro.diary.model.regimen.Regimen_$$_jvstbae_3["handler"])
com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:59)
com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:26)
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:575)
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:666)
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:156)
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:575)
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:666)
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:156)
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:129)
com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:851)
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:264)
org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:222)
org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:183)
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:80)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:860)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:151)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
注意:我使用的是 Hibernate 4 和 Spring MVC 4
任何帮助将不胜感激,在此先感谢!
背景
当 hibernate 从数据库中加载具有惰性非空关系的实体时,它(通常)会为引用的实体创建一个惰性加载代理,并将该代理对象放入对应的 属性正在加载的对象。此代理对象将扩展 class 或引用实体的接口,并且从该 class 或接口调用任何方法都会导致代理对象初始化,从数据库中获取数据(这仅在会话仍然打开时工作,否则初始化将抛出异常)和 returns 加载的数据。
您的 OpenSessionInViewFilter 在整个请求处理期间保持会话打开,因此如果有人在代理对象上调用 getter,代理对象将成功初始化而不是抛出 LazyInitializationException。
然而,您的 JsonProcessingException 发生在此之前。这表明 Jackson 不知道应该以什么形式序列化这样一个代理对象。
解决方案
标准解决方案正在使用 jackson-datatype-hibernate。该模块还允许您配置 Jackson 是应该初始化代理(即从数据库中获取状态)还是只序列化所引用实体的身份。后者允许您灵活地控制应将多少数据写入响应(通过仅初始化客户端需要的关系),并且不需要 OpenSessionInViewFilter(因为代理提前初始化,或者根本不初始化)。