1

I´m using JPA Hibernate and Spring MVC. I haved implemented repository pattern. I get a PageRepository that simply gets a Page object from the db. Then in the controller I'm trying to access pageObject.getWidgets() (defined lazy) and I get an exception saying that the session is closed.

Just to be clear, here is the code of the controller

@RequestMapping(value = "/pages/get",method=RequestMethod.GET)
    public @ResponseBody String getPage(@RequestParam Long id){
        .....
            Page page = pageRepository.getById(id);
            if(page!=null && page.getWidgets()!=null){
                for(Widget widget: page.getWidgets()){ <--- here the exception occurs
                    ....    }

the simple code of repository

@PersistenceContext
    public void setEntityManager(EntityManager em) {
        this.em = em;
    }

    protected abstract Class<T> getConcreteClass();

    @Override
    public T getById(long id) {
        return em.find(getConcreteClass(), id);
    }

the model in relation with widgets

@OneToMany(fetch=FetchType.LAZY,orphanRemoval=true,cascade=CascadeType.ALL,mappedBy="page")
    public List<Widget> getWidgets() {
        return widgets;
    }

    public void setWidgets(List<Widget> widgets) {
        this.widgets = widgets;
    }

my web.xml

 <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
      <display-name>Spring3MVC</display-name>
      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
      <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>
            com.opensymphony.module.sitemesh.filter.PageFilter
        </filter-class>
      </filter>
    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>



      <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>
                org.springframework.web.servlet.DispatcherServlet
            </servlet-class>
        <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>*.html</url-pattern>
      </servlet-mapping>
      <servlet>
        <servlet-name>Resource Servlet</servlet-name>
        <servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>Resource Servlet</servlet-name>
        <url-pattern>/resources/*</url-pattern>
      </servlet-mapping>
      <!-- 
      Spring Security
      -->

        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                ...
            </param-value>
        </context-param>

        <filter>
          <filter-name>springSecurityFilterChain</filter-name>
          <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>

        <filter-mapping>
          <filter-name>springSecurityFilterChain</filter-name>
          <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!-- 
        Spring Security
        -->

        <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>


    </web-app>

my spring-servlet

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">


   ....
    <bean id="localeResolver"
        class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
        <property name="defaultLocale" value="es"/>
    </bean>

    <bean id="handlerMapping"
        class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
        <property name="interceptors">
            <ref bean="localeChangeInterceptor" />
        </property>
    </bean>


    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
     ...
    </bean>

    <bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    p:dataSource-ref="dataSource"
    p:jpaVendorAdapter-ref="jpaAdapter">
        <property name="loadTimeWeaver">
                <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
        </property>                             
        <property name="persistenceUnitName" value="sparkPersistenceUnit"></property>
    </bean>

     <bean id="jpaAdapter"
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
    p:database="MYSQL"
    p:showSql="true"
    p:generateDdl="true"/>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
    p:entityManagerFactory-ref="entityManagerFactory"/>

    <tx:annotation-driven transaction-manager="transactionManager"/>



</beans>

Exception

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.model.Page.widgets, 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.PersistentBag.iterator(PersistentBag.java:272)
    at com.sprekelia.spark.controller.PageController.getPage(PageController.java:78)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:710)
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:167)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:414)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:402)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:771)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:647)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:552)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:306)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:312)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:95)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:79)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:119)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:187)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:324)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:165)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:244)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at com.opensymphony.sitemesh.webapp.SiteMeshFilter.obtainContent(SiteMeshFilter.java:129)
    at com.opensymphony.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:77)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:244)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:108)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:558)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:379)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:259)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:281)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

Well, what can i do to solve this problem?

Thanks in advance

2 Answers 2

4

Have not used pure JPA but JPA via Hibernate and to get the lazy loading to work you need to add @Transactional annotation on your method. This will cause the connection to remain open during the lifetime of the method.

Controller methods don't get called externally and therefore are not subject to proxying that @Transactional relies on. May have to move entity graph traversal code into a "Service" class and apply @Transactional there.

Sign up to request clarification or add additional context in comments.

8 Comments

if i do that i get the following exception Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.
mirrors.ibiblio.org/pub/mirrors/maven2/cglib/cglib-nodep/2.1_3/…. And you have to add a no-arg constructor to your controller class.
i did what you propose, but i still getting failed to lazily initialize a collection of role: com.Page.widgets, no session or session was closed
You can add OpenEntityManagerInViewFilter to web.xml
Ok, one last recommendation: I have read elsewhere that Spring won't proxy to a Controller class, which is required for transactions. I personally put all my transactions into a layer of "Service" classes and that is where I apply @Transactional rather than in the controller. Maybe you can give that a try.
|
2

Thanks to all. I solved the problem writing the code inside a component or a service. So, i can use @Transactional without problems.

here is the code

the method controller

@RequestMapping(value = "/pages/get",method=RequestMethod.GET)
    public @ResponseBody String getPage(@RequestParam Long id){
        return new Gson().toJson(new ActionResult(pageBuilderService.buildAdapterFromPage(id)));
    }

the service

@Component(value="PageBuilderService")
public class PageBuilderService {

    @Autowired
    private IPageRepository pageRepository;


    public void setPageRepository(IPageRepository pageRepository) {
        this.pageRepository = pageRepository;
    }

    @Transactional
    public List<WidgetAdapter> buildAdapterFromPage(Long pageId){
        List<WidgetAdapter> adapters = new ArrayList<WidgetAdapter>();
        if(pageId!=null){
            Page page = pageRepository.getById(pageId);
            if(page!=null && page.getWidgets()!=null){
                for(Widget widget: page.getWidgets()){
                    adapters.add(WidgetFactory.FactoryMethodAdapter(widget));
                }
            }
        }
        return adapters;
    }

}

that is the solution i get with the information supplied. I don´t know if it is the best but i think it´s a good solution.

3 Comments

Ok, so I bust my hump to help you get it working and you give yourself credit for the answer. Nice.
@musli BTW for service classes exists special annotation @Service which will be better in your case.
@splonk i fixed. Sorry i was new in the site.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.