0

I am using hibernate 4.3 and SWF 2.4 and encountered a strange behavior in a particular case which leads to a LazyInitializedException.

Here is the configuration of the flow :

<persistence-context />

<on-start>
    <!-- attach enterprise to session if not provided -->
    <evaluate expression="enterpriseInput ?: enterpriseDaoImpl.merge(externalContext.sessionMap.workingEnterprise)" result="flowScope.enterprise"/>
</on-start>

<view-state id="start" view="filiation/list">
    <transition to="showBoardOrGoToList" on="save" />
</view-state>

<action-state id="showBoardOrGoToList">
    <evaluate expression="flowController.displayBoard(event)"  />
    <transition on="yes" to="boardSubflow"/>
    <transition on="no" to="something" />
</action-state>

<subflow-state id="boardSubflow" subflow="board">
    <on-entry>
        <evaluate expression="boardFlowController.initAdmins(enterprise)" result="flowScope.admins" />
    </on-entry>
    <input name="admins" value="flowScope.admins"/>

    <output name="enterprise" value="flowScope.enterprise"/>

    <transition on="save" to="end">
        <evaluate expression="enterpriseDaoImpl.merge(enterprise)" result="flowScope.enterprise"/>
    </transition>
    <transition on="cancel" to="cancel"/>
</subflow-state>

...

When the flow reaches the following line :

<evaluate expression="boardFlowController.initAdmins(enterprise)" result="flowScope.admins" />

It will trigger a LazyInitializedException, the method initAdmins() basically does a Hibernate.initialize() on the elements of a list.

for (Administrator administrator : enterprise.getAdministrators()) {
    Hibernate.initialize(administrator);
}

If just before that line a method on a DAO is called it will perform the DB query without issue, so this means that the hibernate session is available at this point but the lazyInit is not working.

BUT, if i call initAdmins() in the <on-start> tag of the flow, it works...

THe flow config that works :

<persistence-context />

<on-start>
    <!-- attach enterprise to session if not provided -->
    <evaluate expression="enterpriseInput ?: enterpriseDaoImpl.merge(externalContext.sessionMap.workingEnterprise)" result="flowScope.enterprise"/>
    <evaluate expression="boardFlowController.initAdmins(enterprise)" result="flowScope.admins" />
</on-start>

<view-state id="start" view="filiation/list">
    <transition to="showBoardOrGoToList" on="save" />
</view-state>

<action-state id="showBoardOrGoToList">
    <evaluate expression="flowController.displayBoard(event)"  />
    <transition on="yes" to="boardSubflow"/>
    <transition on="no" to="something" />
</action-state>

<subflow-state id="boardSubflow" subflow="board">

    <input name="admins" value="flowScope.admins"/>

    <output name="enterprise" value="flowScope.enterprise"/>

    <transition on="save" to="end">
        <evaluate expression="enterpriseDaoImpl.merge(enterprise)" result="flowScope.enterprise"/>
    </transition>
    <transition on="cancel" to="cancel"/>
</subflow-state>

...

The problem is that i want to initialize the admins only when required as this is a costly operation.

There is very little information on the mechanism of the persistence-context so i couldn't find an explanation on this.

For me it really looks like a bug.

Can someone highlight me or explain why the lazyInit is broken outside of the on-start tag? Thx

Quent
  • 23
  • 5
  • I had a similar problem. I had to change my List of items to a Set and override the equals/hashCode. – griFlo Mar 18 '15 at 11:53

1 Answers1

0

Not sure what is causing the issue. I've experienced this before and I agree I think it is a bug as well however I don't think it's worth the effort to troubleshoot because we'd have to step into the WebFlow code (done this a few times... not fun takes hours) and I've always found a simple and unintrusive work around (5 minutes or less).

Try to initialize the admins in the following transition

<transition on="yes" to="boardSubflow"/> 

see if it works now. (would be the same effect as on-start inside the subflow in terms of your goals of efficiency).

<transition on="yes" to="boardSubflow">
        <evaluate expression="boardFlowController.initAdmins(enterprise)" result="flowScope.admins" />
</transition>

If that doesn't work try to create an action-state who's sole purpose is to init admins. Place this action-state in the middle the transition -> subflow call. Make sure to evaluate the expression in either the on-start or on-exit of this action-state.

<action-state id="initAdminsActionState">
      <transition to="boardSubflow"/> 
      <on-exit>
          <evaluate expression="boardFlowController.initAdmins(enterprise)" result="flowScope.admins" />
      </on-exit>
</action-state>
Selwyn
  • 3,118
  • 1
  • 26
  • 33
  • i'll add it to my to do list to try to track down and report this bug but it's low priority for me :) – Selwyn Mar 19 '15 at 05:30
  • Thank you for answering, i have already tried to put it in the on="yes" transition as you suggested but the error also happens. In fact, i have tried to put this initialization almost everywhere, and for example, it works in the on-entry of the "start" view-state, but outside the first view-state apparently nothing works. I can determine if the initilalization is required at the beginning of the flow so not really an issue but this is indeed a bug. – Quent Mar 19 '15 at 09:06