Pergunta

I am using Spring MVC, AJAX/JSON and Hibernate to get all persons from a MySQL database. I wrote JUnit integration tests to verify my service and all is okay.

Now I call it in this kind:

@RequestMapping(value="/allpersons", method=RequestMethod.GET)
public @ResponseBody Set<Person> getAllPersons() {
    Set<Person> persons= new PersonServiceImpl().getAllPersons();
    return persons;
}

I debugged it. The line with

return persons;

everything is fine. I have a HashSet with all persons in it. Debugging more steps, I come to this line:

this.objectMapper.writeValue(jsonGenerator, o);

in

org.springframework.http.converter.json.MappingJacksonHttpMessageConverter

Then I do not see the source code, but my debugger tells me:

StdSerializerProvider._serializeValue(JsonGenerator, Object) line 297

After this line, I get the error:

ERROR: org.hibernate.LazyInitializationException - failed to lazily initialize a collection of role: com.mydomain.project.dom.Person.projects, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mydomain.project.dom.Person.projects, no session or session was closed
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
    at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368)
    at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111)
    at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:186)
    at org.codehaus.jackson.map.ser.ContainerSerializers$CollectionSerializer.serializeContents(ContainerSerializers.java:339)
    at org.codehaus.jackson.map.ser.ContainerSerializers$CollectionSerializer.serializeContents(ContainerSerializers.java:314)
    at org.codehaus.jackson.map.ser.ContainerSerializers$AsArraySerializer.serialize(ContainerSerializers.java:112)
    at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:268)
    at org.codehaus.jackson.map.ser.BeanSerializer.serializeFields(BeanSerializer.java:160)
    at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:131)
    at org.codehaus.jackson.map.ser.ContainerSerializers$CollectionSerializer.serializeContents(ContainerSerializers.java:363)
    at org.codehaus.jackson.map.ser.ContainerSerializers$CollectionSerializer.serializeContents(ContainerSerializers.java:314)
    at org.codehaus.jackson.map.ser.ContainerSerializers$AsArraySerializer.serialize(ContainerSerializers.java:112)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:297)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:224)
    at org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:1030)
    at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.writeInternal(MappingJacksonHttpMessageConverter.java:153)
    at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:181)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.writeWithMessageConverters(AnnotationMethodHandlerAdapter.java:975)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.handleResponseBody(AnnotationMethodHandlerAdapter.java:933)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.getModelAndView(AnnotationMethodHandlerAdapter.java:882)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:428)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
    at org.tuckey.web.filters.urlrewrite.NormalRewrittenUrl.doRewrite(NormalRewrittenUrl.java:195)
    at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:159)
    at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:141)
    at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:90)
    at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:417)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:619)

It seems, that is has something to do with the serialization / JacksonMapping. It wants to get the associated projects of a person, which are not needed and they are normally lazily loaded.

What's the problem here?

Thank you in advance & Best Regards.

Foi útil?

Solução

What you encounter is similar with this: Lazy Loading error

In a nutshell, you are accessing a lazy-loaded collection outside the Hibernate Session.

Possible solutions:

  • fetch it eagerly
  • make sure your Hibernate Session is still open at the point where you access the collection. You can use OpenSessionInView filter. That in itself may not be enough, as Hibernate may end your session where you close your transaction. So you will need to extend your transaction scope or find a way to prevent Hibernate to close the session upon transaction end.
  • make sure you access the lazy-loaded collection inside your transaction, to make sure Hibernate loads it.

Please check the post specified above for further details.

UPDATE 1 From what I've understood, this is caused by the Jackson mapper receiving a model that wasn't completely loaded (some collections are lazy loaded). You're saying you don't need the objects in those collections to be mapped by Jackson. The alternatives I'm seeing are:

  • Give Jackson a correct model, simple POJOs created based on your Person objects, containing only the information you want to map with Jackson. So, instead of giving Jackson a list of Persons, you'll give it a list of PersonDetails (or however you want to call them)
  • Configure Jackson to ignore that collection - not sure whether that's possible

Hope this helps.

Outras dicas

While this does not immediately help you with the easy, it may be good to know that there is a new Jackson-related project, jackson-module-hibernate (at GitHub) that aims to solve this problem along with other commonly problematic use cases.

But on short term, you might find this article useful: http://kyrill007.livejournal.com/2577.html

If you don't want to map in you're JSON object the field which is linked in hibernate relation, you can add annotation "@JsonIgnore" in your model class :

@JsonIgnore
@OneToMany(mappedBy = "person")
private List<ProjectEntity> projects = new ArrayList<ProjectEntity>();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top