0

Integration of Spring, Hibernate and ZK causing lazy initialization exception

asked 2009-03-02 08:11:44 +0800

adrianlim83 gravatar image adrianlim83
69 1 2

Hi all, is there anyone knowing this exception? I was trying to fixed this issue since 2 months ago, however, there is no solutions so far. Well, i think everyone should know that the integration of spring and hibernate would causing lazy initialization exception. To resolve this issue, we will need to include OpenSessionInView in the web.xml and hibernate interceptor in spring xml by using Spring AOP as an example. With this solutions, by right it should resolved.

Well, while integrate with ZK, first of all, we should include the ThreadLocal in zk.xml. Physically it work fine, however, while the table more than 22 records with lazy load required. This would pop up this exception "could not initialize proxy - the owning Session was closed" when you trying to scrolled down the list. In the server console, this is the exception message:


SEVERE: could not initialize proxy - the owning Session was closed
org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:60)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:140)
at com.ersm.common.bean.role.Role$$EnhancerByCGLIB$$ea4c9486.getName(<generated>)
at sun.reflect.GeneratedMethodAccessor75.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.zkoss.lang.reflect.Fields.get(Fields.java:119)
at org.zkoss.zkplus.databind.DataBinder.fetchValue(DataBinder.java:919)
at org.zkoss.zkplus.databind.DataBinder.myGetBeanWithExpression(DataBinder.java:910)
at org.zkoss.zkplus.databind.DataBinder.getBeanAndRegisterBeanSameNodes(DataBinder.java:878)
at org.zkoss.zkplus.databind.Binding.loadAttribute(Binding.java:278)
at org.zkoss.zkplus.databind.DataBinder.loadAttrs(DataBinder.java:490)
at org.zkoss.zkplus.databind.DataBinder.loadComponent(DataBinder.java:441)
at org.zkoss.zkplus.databind.DataBinder.loadComponent(DataBinder.java:446)
at org.zkoss.zkplus.databind.BindingListitemRenderer.render(BindingListitemRenderer.java:99)
at org.zkoss.zul.Listbox$Renderer.render(Listbox.java:2289)
at org.zkoss.zul.Listbox.renderItems(Listbox.java:2390)
at org.zkoss.zul.Listbox$ExtraCtrl.renderItems(Listbox.java:2643)
at org.zkoss.zk.au.in.RenderCommand.process(RenderCommand.java:51)
at org.zkoss.zk.au.Command.process(Command.java:131)
at org.zkoss.zk.ui.impl.UiEngineImpl.process(UiEngineImpl.java:1196)
at org.zkoss.zk.ui.impl.UiEngineImpl.execUpdate(UiEngineImpl.java:989)
at org.zkoss.zk.au.http.DHtmlUpdateServlet.process(DHtmlUpdateServlet.java:480)
at org.zkoss.zk.au.http.DHtmlUpdateServlet.doGet(DHtmlUpdateServlet.java:370)
at org.zkoss.zk.au.http.DHtmlUpdateServlet.doPost(DHtmlUpdateServlet.java:379)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:83)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:174)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:874)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
at java.lang.Thread.run(Unknown Source)
Mar 2, 2009 4:04:58 PM org.zkoss.zk.ui.impl.UiEngineImpl handleError:1107
SEVERE: >>org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed
>> at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:60)
>> at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
>> at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:140)
>> at com.ersm.common.bean.role.Role$$EnhancerByCGLIB$$ea4c9486.getName(<generated>)
>> at sun.reflect.GeneratedMethodAccessor75.invoke(Unknown Source)
>> at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
>> at java.lang.reflect.Method.invoke(Unknown Source)
>> at org.zkoss.lang.reflect.Fields.get(Fields.java:119)
>>...


The below content is my configuration in web.xml and zk.xml

zk.xml:

<zk>
...
<listener>
<description>Spring TransactionSynchronizationManager handler</description>
<listener-class>org.zkoss.zkplus.spring.SpringTransactionSynchronizationListener</listener-class>
</listener>


<listener>
<description>ThreadLocal Variables Synchronizer</description>
<listener-class>org.zkoss.zkplus.util.ThreadLocalListener</listener-class>
</listener>

<preference>
<name>ThreadLocal</name>
<value>
org.springframework.transaction.support.TransactionSynchronizationManager=
resources,synchronizations,currentTransactionName,currentTransactionReadOnly,actualTransactionActive;
org.springframework.orm.hibernate3.SessionFactoryUtils=deferredCloseHolder;
org.springframework.transaction.interceptor.TransactionAspectSupport=transactionInfoHolder;
</value>
</preference>
...
</zk>


web.xml:

<web-app>
...

<filter>
<filter-name>OSIV</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>flushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>OSIV</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

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

...


<listener>
<description>ZK listener for cleanup when a session is destroyed</description>
<listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
</listener>

<servlet>
<description>ZK loader for ZUML pages</description>
<servlet-name>zkLoader</servlet-name>
<servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>
<!-- Must. Specifies URI of the update engine (DHtmlUpdateServlet).
It must be the same as <url-pattern> for the update engine.
-->
<init-param>
<param-name>update-uri</param-name>
<param-value>/zkau</param-value>
</init-param>
<!-- Optional. Specifies the default log level: OFF, ERROR, WARNING,
INFO, DEBUG and FINER. If not specified, the system default is used.
<init-param>
<param-name>log-level</param-name>
<param-value>OFF</param-value>
</init-param>
-->
<load-on-startup>1</load-on-startup><!-- Must -->
</servlet>

<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zul</url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>*.zhtml</url-pattern>
</servlet-mapping>

<!-- Optional. Uncomment it if you want to use richlets.
-->
<servlet-mapping>
<servlet-name>zkLoader</servlet-name>
<url-pattern>/zk/*</url-pattern>
</servlet-mapping>

<servlet>
<description>The asynchronous update engine for ZK</description>
<servlet-name>auEngine</servlet-name>
<servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>auEngine</servlet-name>
<url-pattern>/zkau/*</url-pattern>
</servlet-mapping>

...

</web-app>


Thanks in advance and your advice and solutions is appreciated.

delete flag offensive retag edit

21 Replies

Sort by ยป oldest newest

answered 2009-03-02 08:45:05 +0800

A gravatar image A
117 2

hi,
Can you post your Role.hbm.xml? I think you should configure the mapping relationship "lazy='false'"
by Cary

link publish delete flag offensive edit

answered 2009-03-02 08:50:15 +0800

adrianlim83 gravatar image adrianlim83
69 1 2

Hi Cary, thanks for your solution and advice. Between, do you know is there any way to solve without configure lazy="false"? Because this may reduce the performance. For instance, every call from the User will involve Role mapping.


The below content is my Role.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.ersm.common.bean.role.Role" table="role" entity-name="Role">
<id name="id" column="id" type="string"><generator class="uuid" /></id>
<property name="name" column="name" type="string" />
<property name="description" column="description" type="string" />

<!-- table join -->
<set name="users">
<key column="roleId" />
<one-to-many entity-name="User" />
</set>

<set name="services" table="role_service">
<key column="roleId"></key>
<many-to-many column="serviceId" entity-name="Service" order-by="titleGroup asc" />
</set>
</class>
</hibernate-mapping>

link publish delete flag offensive edit

answered 2009-03-02 11:17:44 +0800

iantsai gravatar image iantsai
2755 1

This is a long story.

your problem is an Ajax Framework(such as ZK) will do things through different Http requests but the Hibernate's default session life-cycle handler(which is a filter declared in web.xml) got no information about this.
That's why you need to rebind Hibernate session in the beginning of every event listener method such as onClick, onSelect, etc...
Because after Browser URL request is fulfilled, all the Hibernate bean's sessions are already closed.

The way to solve this problem is using Hibernate's "session merge" before use Hibernate beans.
But, inyour case, Listbox live-data mechanism in Annotated Databinding is totally automatic, there's no normal way for developer to reconfigure it.(If you didn't use Annotated Databinding, you can call merge in ListitemRenderer manually)

Here's a work-around in current situation, you must implement a "HibernateSessionMergeConverter" yourself and use it in listcell's annotation declaration.

If you can't understand what I mean, please post your piece of code about your Listbox and I can show you some pseudo code about it.

link publish delete flag offensive edit

answered 2009-03-03 01:40:29 +0800

adrianlim83 gravatar image adrianlim83
69 1 2

Hi iantsai, thanks for your deep definition of the big picture of ZK and Hibernate's default session life-cycle handler. I am not really understand the work-around in current situation. Between, this is my piece of code about the Listbox.

zul:

<?xml version="1.0" encoding="UTF-8"?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" arg0="./userController"?>

<window id="userController" width="850px"
use="com.ersm.mvc.user.ZKUserController"
title="@{userController.WINDOW_TITLE}" defaultActionOnShow="appear" border="normal" closable="true">

...
<listbox id="userBox" height="350px" width="820px" multiple="false" checkmark="true"
model="@{userController.userList}"
onSelect="userController.doSelectedItem(self)">
<listhead sizable="true">
<listheader label="@{userController.LOGIN_LABEL}" width="170px" sort="auto"/>
<listheader label="@{userController.FIRST_NAME_LABEL}" width="250px"/>
<listheader label="@{userController.LAST_NAME_LABEL}" width="250px"/>
<listheader label="@{userController.ROLE_LABEL}" width="150px"/>
</listhead>

<listitem self="@{each='userBean'}" value="@{userBean}"
onDoubleClick="userController.onEdit()">
<listcell label="@{userBean.login}"/>
<listcell label="@{userBean.firstName}"/>
<listcell label="@{userBean.lastName}"/>
<listcell label="@{userBean.role.name}"/>
</listitem>
</listbox>
...
</window>

ZK User Controller:

...
/**
* 6a. Refresh user table
*/
public void refreshUserListbox() throws InterruptedException{

List tableList = getUserTableList();

//admin and user control
if(!getLoginUser().getRole().getName().equals("Administrator")){
userList = userManager.getAllActiveUsersExceptAdmin();
}else{
userList = userManager.getAllActiveUsers();
}
user = (User)userList.get(0);


//refresh user table
tableList.clear();
tableList.addAll(userList);
}

/**
* 6b. Get user table list
*/
public List getUserTableList() {
Listbox userListbox = getUserListbox();
List userList = (List)userListbox.getModel();
return userList;
}

/**
* 6c. Get user list box
*/
public Listbox getUserListbox() {
return (Listbox)this.getFellow("userBox");
}
...

Thanks for your guidance and steps in advance.

link publish delete flag offensive edit

answered 2009-03-03 01:43:11 +0800

adrianlim83 gravatar image adrianlim83
69 1 2

Sorry, let off something. This is the after compose method

ZK User Controller:

/**
* 1. Initialize the components
*/
public void afterCompose() {
//remove administrator data if it's not admin
if(!getLoginUser().getRole().getName().equals("Administrator")){
userList = userManager.getAllActiveUsersExceptAdmin();
}else{
userList = userManager.getAllActiveUsers();
}
user = (User)userList.get(0);
}

/**
* Get current login user
*/
public User getLoginUser()
{
Session session = (Session) Sessions.getCurrent();
if (session != null)
return (User) session.getAttribute("loginId");
else
return null;
}

link publish delete flag offensive edit

answered 2009-03-03 03:57:11 +0800

iantsai gravatar image iantsai
2755 1

The work around is like this:

<listitem self="@{each='userBean'}" value="@{userBean, converter='test.HibernateSessionMergeConverter'}"
onDoubleClick="userController.onEdit()">
<listcell label="@{userBean.login"}/>
<listcell label="@{userBean.firstName}"/>
<listcell label="@{userBean.lastName}"/>
<listcell label="@{userBean.role.name}"/>
</listitem>

// in HibernateSessionMergeConverter.java

public class HibernateSessionMergeConverter implements TypeConverter {

    public Object coerceToBean(java.lang.Object val, org.zkoss.zk.ui.Component comp) {
        return null;
    }

    public Object coerceToUi(java.lang.Object val, org.zkoss.zk.ui.Component comp) {
        if(val instanceof MyBean)
        {
            //DO Hibernate session merge here...
        }
        return ;
    }
}

link publish delete flag offensive edit

answered 2009-03-03 06:09:49 +0800

adrianlim83 gravatar image adrianlim83
69 1 2

Hi iantsai, the same exception still occur after implement Hibernate Session Merge Converter. Kindly correct me if my implementation was incorrect.

User zul:
...
<listitem self="@{each='userBean'}" value="@{userBean, converter='com.ersm.util.HibernateSessionMergeConverter'}"
onDoubleClick="userController.onEdit()">
<listcell label="@{userBean.login}"/>
<listcell label="@{userBean.firstName}"/>
<listcell label="@{userBean.lastName}"/>
<listcell label="@{userBean.role.name}"/>
</listitem>
...


HibernateSessionMergeConverter:

...

public class HibernateSessionMergeConverter implements TypeConverter {

public Object coerceToBean(Object val, Component comp) {
return null;
}

public Object coerceToUi(Object val, Component comp) {
if(val instanceof GenericBean){
Listitem listitem = new Listitem();
listitem.setValue(val);
return listitem;
}
return null;
}
}
...

link publish delete flag offensive edit

answered 2009-03-03 06:17:44 +0800

adrianlim83 gravatar image adrianlim83
69 1 2

Between, I was trying to debug and it does step into coerceToUi method from HibernateSessionMergeConverter while the list is display. However, the exception occur is not from the loading instead is happened when I was trying to scrolled down the list (happen only if my data is 22 or more records).

link publish delete flag offensive edit

answered 2009-03-03 09:52:55 +0800

iantsai gravatar image iantsai
2755 1

updated 2009-03-03 09:53:14 +0800

Your implementation is incorrect, you shouldn't setValue() by your self because ZK Databinder will do it for you.

Converter is used to "Transform" the data to proper value witch can be passed to bean field or UI component attribute.

and in our implementation, we just need to ensure the value(which is a Bean from Hibernate) has correct state to be used.

The code should be looked like following:

// in HibernateSessionMergeConverter.java

public class HibernateSessionMergeConverter implements TypeConverter {

    public Object coerceToBean(java.lang.Object val, org.zkoss.zk.ui.Component comp) {
        return null;
    }

    public Object coerceToUi(java.lang.Object val, org.zkoss.zk.ui.Component comp) {
        if(val instanceof MyBean)
        {
            //get  javax.persistence.EntityManager from somewhere...
            entityManager.merge(val );
        }
        return val;
    }
}



link publish delete flag offensive edit

answered 2009-03-06 03:20:08 +0800

adrianlim83 gravatar image adrianlim83
69 1 2

Hi iantsai, thanks a lot. I am currently looking for the solutions, however, initially I used Spring IoC to configure my hibernate and included HibernateDaoSupport (all the data source, session factory, etc is configure using Spring IoC). However, because of the existing issue while integrate with ZK, I have to use EntityManager.merge(...) from your point of view, and thus I required to configure LocalEntityManagerFactoryBean in Spring IoC. If I am not mistake, it's because my existing LocalSessionFactoryBean has been initialize and when I initialize LocalEntityManagerFactoryBean using Spring IoC, it will throws this exception: "Caused by: org.hibernate.DuplicateMappingException: Duplicate collection role mapping ..."

May you point some advice on this matter? Really thanks for you fully consideration and helpful.

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2009-03-02 08:11:44 +0800

Seen: 2,831 times

Last updated: May 12 '09

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More