2016-08-02 46 views
0

Ich weiß, es gibt viele Fragen zu diesem gleichen Problem, das ich Ihnen sagen werde, aber keiner von ihnen wurde erreicht, um mein Problem zu lösen.Hibernate Lazy Loading wirft JsonMappingException

Ich habe einen Dienst implementiert, der auf eine Objekteigenschaft mit LAZY laden muss. Dies ist eine Vereinfachung der Klasse:

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

} 

Konkret Ich brauche eine Regimen Eigenschaft zu erhalten. So setzen nächste Anmerkung in der Klasse ist nicht gültig für mich:

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) 

Ich versuchte OpenSessionInViewFilter meiner WebApplicationInitializer wie folgt hinzuzufügen:

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

} 

Und das ist meine jackson Abhängigkeit:

<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-databind</artifactId> 
    <version>2.5.3</version> 
</dependency> 

Dies sind die Fehler, die ich bekomme:

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) 

Hinweis: Ich benutze Hibernate 4 und Spring MVC 4

Jede Hilfe wird geschätzt, danke im Voraus!

Antwort

2

Hintergrund

Wenn Hibernate aus der Datenbank eine Einheit mit einer faulen Nicht-Null-Beziehung laden, wird es (in der Regel) einen verzögertes Laden Proxy für die genannten Unternehmen erstellen, und setzt dieses Proxy-Objekt in den entsprechenden Eigenschaft des geladenen Objekts. Dieses Proxy-Objekt erweitert die Klasse oder Schnittstelle der referenzierten Entität, und jeder Aufruf von Methoden aus dieser Klasse oder Schnittstelle führt zur Initialisierung des Proxy-Objekts, das die Daten aus der Datenbank abruft (dies funktioniert nur, solange die Sitzung noch offen ist.) andernfalls wird die Initialisierung eine Ausnahme auslösen) und gibt die geladenen Daten zurück.

Ihr OpenSessionInViewFilter hält die Sitzung während der gesamten Anforderungsverarbeitung geöffnet. Wenn also jemand ein Getter für das Proxyobjekt aufruft, wird das Proxyobjekt erfolgreich initialisiert, anstatt eine LazyInitializationException auszulösen.

Ihre JsonProcessingException passiert jedoch davor. Es zeigt an, dass Jackson nicht weiß, in welcher Form ein solches Proxy-Objekt serialisiert werden sollte.

Lösung

Die Standardlösung wird jackson-datatype-hibernate verwenden. Mit diesem Modul können Sie auch konfigurieren, ob Jackson Proxies initialisieren soll (d. H. Den Status von der Datenbank abrufen soll) oder einfach nur die Identität der referenzierten Entität serialisieren. Letzteres ermöglicht es Ihnen, flexibel zu steuern, wie viele Daten in die Antwort geschrieben werden sollen (indem Sie nur die Beziehungen initialisieren, die der Client benötigt) und keinen OpenSessionInViewFilter benötigt (weil die Proxys zu früh oder gar nicht initialisiert werden).

+0

Tolle Erklärung, vielen Dank! Sie haben mir sehr geholfen :) – Celtik

+0

Können Sie versuchen mit: @JsonIgnoreProperties ({"HibernateLazyInitializer", "Handler"}) Oder wenn Sie PropertyNamingStrategy.LowerCaseWithUndersCoresStrategy() verwenden, wäre die Annotation: @JsonIgnoreProperties ({"Hibernate_lazy_initializer "," Handler "}) – user3257644