1

I have a problem with the access to a collection from JSP file. Application is based on MVC Spring framework. I put OpenSessionInViewFilter filter to my web.xml. When I want to access to URL with mentioned file, it throws me

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.cloud.hibernate.Product.availabilities, no session or session was closed

I use domain driven design in my app. When I changed fetch type in class Product from FetchType.LAZY to FetchType.EAGER, it worked.

stacktrace

SEVERE: Servlet.service() for servlet [spring] in context with path [] threw exception [org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.cloud.hibernate.Product.availabilities, no session or session was closed] with root cause
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.app.cloud.hibernate.Product.availabilities, no session or session was closed
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
    at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119)
    at org.hibernate.collection.PersistentSet.isEmpty(PersistentSet.java:169)
    at org.apache.el.parser.AstEmpty.getValue(AstEmpty.java:55)
    at org.apache.el.parser.AstNot.getValue(AstNot.java:44)
    at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:185)
    at org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:1026)
    at org.apache.jsp.WEB_002dINF.jsp.product.products_jsp._jspx_meth_c_005fwhen_005f0(products_jsp.java:321)
    at org.apache.jsp.WEB_002dINF.jsp.product.products_jsp._jspx_meth_c_005fchoose_005f0(products_jsp.java:290)
    at org.apache.jsp.WEB_002dINF.jsp.product.products_jsp._jspx_meth_c_005fforEach_005f0(products_jsp.java:233)
    at org.apache.jsp.WEB_002dINF.jsp.product.products_jsp._jspx_meth_c_005fif_005f0(products_jsp.java:185)
    at org.apache.jsp.WEB_002dINF.jsp.product.products_jsp._jspService(products_jsp.java:141)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    at org.apache.jasper.servlet.JspServlet._serviceJspFile(JspServlet.java:390)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:749)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:487)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:412)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:339)
    at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:238)
    at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:264)
    at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1208)
    at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:992)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:939)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:915)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:811)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:123)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:581)
    at org.apache.catalina.core.StandardHostValve.__invoke(StandardHostValve.java:171)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1686)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

web.xml

  <welcome-file-list>
      <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <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>/</url-pattern>
  </servlet-mapping>


<filter>
  <filter-name>OpenSessionInViewFilter</filter-name>
  <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
  <init-param>
    <param-name>sessionFactoryBeanName</param-name>
    <param-value>sessionFactory</param-value>
  </init-param>
  <init-param>
    <param-name>singleSession</param-name>
    <param-value>true</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>OpenSessionInViewFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Context parameters -->
  <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>WEB-INF/log4j.properties</param-value>
  </context-param>
  <context-param>
    <param-name>log4jExposeWebAppRoot</param-name>
    <param-value>false</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>
</web-app>

spring-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" 
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
    http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

<mvc:annotation-driven />
<tx:annotation-driven />
<context:component-scan base-package="com.app.cloud" />

<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
    <property name="basename" value="spring-views" />
    <property name="order" value="1" />
</bean>

<bean id="jspViewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass"
        value="org.springframework.web.servlet.view.JstlView" />
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
    <property name="order" value="2" />
</bean>

<!-- JDBC -->
<bean id="propertyConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
    p:location="/WEB-INF/jdbc.properties" />

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
    p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />

<!-- Hibernate -->
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation">
        <value>classpath:hibernate.cfg.xml</value>
    </property>
    <property name="configurationClass">
        <value>org.hibernate.cfg.AnnotationConfiguration</value>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${jdbc.dialect}</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

<bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

ProductService.java

    @Transactional
    public interface ProductService {

        @Transactional
        public void add(Product product);
        @Transactional
        public List<Product> getAll();
        @Transactional
        public Product get(Integer idProduct);
        @Transactional
        public void remove(Integer id);
        @Transactional
        public void edit(Product product);

    }

ProductServiceImpl.java

@Service
@Transactional
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductDAO productDAO;

    @Transactional
    public void add(Product product) {
        productDAO.add(product);
    }

    @Transactional
    public List<Product> getAll() {
        return productDAO.getAll();
    }

    @Transactional
    public void remove(Integer id) {
        productDAO.remove(id);
    }

    @Transactional
    public Product get(Integer idProduct) {
        return productDAO.get(idProduct);
    }

    @Transactional
    public void edit(Product product) {
        productDAO.edit(product);
    }


}

ProductDAO.java

    public interface ProductDAO {

        public void add(Product product);
        public void edit(Product product);
        public List<Product> getAll();
        public Product get(Integer idProduct);
        public void remove(Integer id);

    }

ProductDAOImpl.java

@Repository
public class ProductDAOImpl implements ProductDAO {

    @Autowired
    private SessionFactory sessionFactory;

    public void add(Product product) {
        sessionFactory.getCurrentSession().save(product);
    }

    public List<Product> getAll() {
        return sessionFactory.getCurrentSession().createQuery("from Product")
                .list();
    }

    public void remove(Integer id) {
        Product product = (Product) sessionFactory.getCurrentSession().load(
                Product.class, id);
        if (null != product) {
            sessionFactory.getCurrentSession().delete(product);
        }
    }

    public Product get(Integer idProduct) {
        Product product = (Product) sessionFactory.openSession().get(
                Product.class, idProduct);
        return product;
    }

    @Override
    public void edit(Product product) {
        sessionFactory.getCurrentSession().update(product);
    }

}

Product.java

@Entity
@Table(name = "product", catalog = "app")
public class Product implements java.io.Serializable {

    private Integer idProduct;

    @NotEmpty
    @Length (min=1,max=70)
    private String name;

    private Set<Availability> availabilities = new HashSet<Availability>(0);

    public Product() {
    }

    public Product(String name) {
        this.category = category;
        this.name = name;
        this.lastUpdate = lastUpdate;
        this.actionFlag = actionFlag;
    }

    public Product(String name,
            Set<Availability> availabilities,
            ) {
        this.name = name;
        this.availabilities = availabilities;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id_product", unique = true, nullable = false)
    public Integer getIdProduct() {
        return this.idProduct;
    }

    public void setIdProduct(Integer idProduct) {
        this.idProduct = idProduct;
    }

    @Column(name = "name", nullable = false, length = 70)
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "product")
    public Set<Availability> getAvailabilities() {
        return this.availabilities;
    }

    public void setAvailabilities(Set<Availability> availabilities) {
        this.availabilities = availabilities;
    }

}
misco
  • 1,912
  • 4
  • 41
  • 68

4 Answers4

5

It's very classical error when working with Hibernate.

If you have any lazy-loading proxies your should replace them either with nulls or with real objects before returning from @Transactional context.

The Set or List that is lazy loaded is replaced by the Hibernate with the proxy. The proxy would load the collection first time it is accessed. But what if it is first accessed if you are outside the transactional context? The hibernate session that is referenced by the proxy doesn't exist so you have the error.

If you won't need the collection, set it to null or empty HashSet/ArrayList. If you would need it, call the size() or iterate through the element within transactional context. If you are not sure, provide the API for loading the connection. But don't return objects with uninitialized proxies.

Danubian Sailor
  • 1
  • 38
  • 145
  • 223
  • I need the collection in JSP. I tried to call `size()` method on the collection in the controller. `System.out.println(list.get(0).getAvailabilities().size());` it throws me the same exception, what I make the wrong. It isn't clear from your answer. Thanks. – misco Jun 24 '13 at 15:08
  • The exception is when you call size() or afterwards? Calling size() always worked for me, but maybe in your case the iteration through the all elements is needed... toString() method could work nice as well... – Danubian Sailor Jun 24 '13 at 21:44
  • the exception is on call size(). But when i use `openSession` instead of `getCurrentSession()`, it works. Can you give me the explanation? – misco Jun 24 '13 at 21:50
  • I was always using getCurrentSession(), but on the object org.springframework.orm.hibernate3.HibernateTemplate – Danubian Sailor Jun 24 '13 at 21:58
1

Annotate your Controller as @Transactional. You wont see that error again, You bet!!

Note

Experts say that @Transactional is not to be used on Controller, But I didn't get an answer why?

Niranjan
  • 1,776
  • 1
  • 13
  • 21
0

You can try

@Proxy (lazy = false)

On top of both entity class. It works in my case.

Manoj Kathiriya
  • 3,366
  • 5
  • 19
  • 19
0

I believe it's the same problem mentioned in this post.

Collections are lazy-loaded by default, take a look at this if you want to know more.

It's ok to use FetchType.EAGER if you want to have all your collection fetched every time you get a Product. For example you could use:

@ElementCollection(fetch = FetchType.EAGER)
private Set<Availability> availabilities = new HashSet<Availability>(0);
Juan Costamagna
  • 591
  • 4
  • 6