java - Hibernate 延迟加载抛出 JsonMappingException

标签 java json hibernate spring-mvc lazy-loading

我知道关于我会告诉你的同一个问题有很多问题,但还没有一个能解决我的问题。

我已经实现了一项服务,该服务必须通过延迟加载来访问对象属性。这是类的简化:

@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 属性。所以在类中放置下一个注释对我来说无效:

@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[] { "/" };
}

}

这是我对 jackson 的依赖:

<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[&quot;regimen&quot;]-&gt;es.udc.fic.tfg.mferreiro.diary.model.regimen.Regimen_$$_jvstbae_3[&quot;handler&quot;])
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从数据库中加载一个具有惰性非空关系的实体时,它(通常)会为被引用的实体创建一个惰性加载代理,并将该代理对象放入被加载对象的相应属性中。此代理对象将扩展所引用实体的类或接口(interface),并且从该类或接口(interface)调用任何方法都会导致代理对象初始化,从数据库中获取数据(这仅在 session 仍处于打开状态时有效,否则初始化会抛出异常),并返回加载的数据。

您的 OpenSessionInViewFilter 在整个请求处理期间保持 session 打开,因此如果有人调用代理对象上的 getter,代理对象将成功初始化而不是抛出 LazyInitializationException。

然而,您的 JsonProcessingException 在此之前发生。这表明 Jackson 不知道应该以什么形式序列化这样一个代理对象。

解决方案

标准解决方案使用jackson-datatype-hibernate .该模块还允许您配置 Jackson 是应该初始化代理(即从数据库中获取状态)还是只序列化所引用实体的身份。后者允许您灵活地控制应将多少数据写入响应(通过仅初始化客户端需要的关系),并且不需要 OpenSessionInViewFilter(因为代理提前初始化,或者根本不初始化)。

关于java - Hibernate 延迟加载抛出 JsonMappingException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38729485/

相关文章:

java - 在 Apache Phoenix 中显示正确的 HBase 日期类型时出现问题

java - Vaadin 保存主题

java - 获取错误: connect ECONNREFUSED while making active MQ Connection?

PhpStorm 中的 JSON 模式验证

java - 使用 Java 列表 hibernate 多对多双向映射

java - 套接字从 TimerTask.run() 内关闭

java - JAXB:解码异构数组

json - 如何在不为整个应用程序重新定义 `errorHandler` 的情况下从 JSON 处理程序发出 JSON 错误?

java - hibernate MySQL

java - Spring Boot 数据 JPA : No qualifying bean of type 'java.util.Set<javax.persistence.EntityManager>' available