2016-08-02 8 views
0

Я знаю, что есть много вопросов по этой же проблеме, я скажу вам, но ни один из них не был достигнут для решения моей проблемы.Hibernate ленивые загрузки бросков JsonMappingException

Я реализовал службу, которая имеет доступ к объекту с загрузкой LAZY. Это упрощение класса:

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

} 

И это моя джексон зависимость:

<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

Любая помощь будет оценена, спасибо заранее!

ответ

2

фон

Когда спящий режим загружает объект с ленивыми ненулевыми отношениями из базы данных, он будет (как правило) создать отложенную загрузку прокси для упомянутого объекта, и положить, что прокси-объект в соответствующем свойство загружаемого объекта. Этот прокси-объект расширяет класс или интерфейс упомянутого объекта, и любой вызов методов из этого класса или интерфейса приведет к инициализации объекта-прокси, который извлекает данные из базы данных (это работает только во время сеанса, иначе инициализация вызовет исключение) и возвращает загруженные данные.

Ваш OpenSessionInViewFilter сохраняет сеанс открытым во время обработки всего запроса, поэтому, если кто-то вызовет getter на прокси-объекте, объект-прокси инициализируется успешно, а не бросает исключение LazyInitializationException.

Ваше JsonProcessingException, однако, происходит до этого. Это указывает на то, что Джексон не знает, в какой форме он должен сериализовать такой прокси-объект.

Решение

Стандартное решение использует jackson-datatype-hibernate. Этот модуль также позволяет настроить, должен ли Джексон инициализировать прокси (например, получить состояние из базы данных) или просто сериализовать идентификатор упомянутого объекта. Последнее позволяет вам гибко контролировать, сколько данных должно быть записано в ответ (путем инициализации отношений, которые нужны клиенту), и не требует OpenSessionInViewFilter (поскольку прокси инициализируются раньше или вообще не выполняются).

+0

Отличное объяснение, большое спасибо! Вы мне очень помогли :) – Celtik

+0

Можете ли вы попробовать: @JsonIgnoreProperties ({"hibernateLazyInitializer", "handler"}) Или, если вы используете PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy(), аннотация будет выглядеть так: @JsonIgnoreProperties ({"hibernate_lazy_initializer "," обработчик "}) – user3257644

Смежные вопросы