This strange issue was encountered on this env:
Hibernate: 3.2.0 cr2
Oracle: 9i and 10g db
Application: Web & ejb
jdk: 1.5.6
The stackoverflowerror does not seem to be related to db and jdk or the development pattern. The issue is from a save operation on an entity which has one-to-many to 2 other entities. The cascade style is set to "all". We have our own custom id generator class registered and it runs query against database to get a bigdecimal. This generator is used for all our entities and tested and had NO problem to insert entities when cascade style is "none". When the cascade style is change to "all" for inserting the entity and all its one-to-many children, the error popped up.
From the logging, this section repeats hundreds of times before the stackoverflowerror showed up.
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.AbstractSaveEventListener - saving [com.gal.fast.common.domain.War#2344900.000002700000000]
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: com.gal.fast.common.domain.War
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.engine.Cascade - done processing cascade ACTION_SAVE_UPDATE for: com.gal.fast.common.domain.War
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.WrapVisitor - Wrapped collection in role: com.gal.fast.common.domain.War.darList
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.WrapVisitor - Wrapped collection in role: com.gal.fast.common.domain.War.subjectList
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: com.gal.fast.common.domain.War
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.engine.Cascade - cascade ACTION_SAVE_UPDATE for collection: com.gal.fast.common.domain.War.darList
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: com.gal.fast.common.domain.Dar
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.AbstractSaveEventListener - transient instance of: com.gal.fast.common.domain.Dar
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - saving transient instance
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG com.gal.fast.common.hib.SfaIdentifierGenerator - Generating sequence for object:com.gal.fast.common.domain.Dar@187a50b
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.context.ThreadLocalSessionContext - allowing proxied method [createCriteria] to proceed to real session
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - flushing session
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - processing flush-time cascades
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.engine.Cascade - processing cascade ACTION_SAVE_UPDATE for: com.gal.fast.common.domain.War
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.engine.Cascade - cascade ACTION_SAVE_UPDATE for collection: com.gal.fast.common.domain.War.darList
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.engine.CascadingAction - cascading to saveOrUpdate: com.gal.fast.common.domain.Dar
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.AbstractSaveEventListener - transient instance of: com.gal.fast.common.domain.Dar
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.DefaultSaveOrUpdateEventListener - saving transient instance
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG com.gal.fast.common.hib.SfaIdentifierGenerator - Generating sequence for object:com.gal.fast.common.domain.Dar@187a50b
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.context.ThreadLocalSessionContext - allowing proxied method [createCriteria] to proceed to real session
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - flushing session
04 Dec 2006 11:39:31,968. 955531 [RMICallHandler-393] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - processing flush-time cascades
it seems that Hibernate flushed the session before the generator line 32 returns which obviously cause the infinite loop of executing the same statement, according to the generator code:
package com.gal.fast.common.hib;
import java.io.Serializable;
import java.math.BigDecimal;
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;
import com.gal.fast.common.config.CommonAppMetaData;
import com.gal.fast.common.hib.domain.Identifiable;
import org.apache.log4j.Logger;
public class SfaIdentifierGenerator implements IdentifierGenerator {
public Serializable generate(SessionImplementor session,
Object object) throws HibernateException {
// If we have an Identifiable object with a non-null and non-zero id then we want to use that Id for the PK.
// In FAST this happens because we use the same PKs for the same data in both the Sybase and Oracle databases.
Logger.getLogger(this.getClass()).debug("Generating sequence for object:" + object);
BigDecimal bd = new BigDecimal(0.0);
try {
if (object instanceof Identifiable) {
Identifiable i = (Identifiable)object;
if ((i.getId() != null) && (i.getId() != BigDecimal.ZERO)) {
Logger.getLogger(this.getClass()).debug("Return existing ID: " + i.getId());
return i.getId();
}
}
bd = CommonAppMetaData.getCommonInstance().getDaoFactory().getSequence();
}
catch (Exception e) {
Logger.getLogger(this.getClass()).debug("Sequence generation failur:", e);
}
Logger.getLogger(this.getClass()).debug("Sequence for object " + object + " generated: " + bd);
return bd;
}
}
Here is the detail of getSequence() method:
((SfaSequence)ctx.getSession().createCriteria(SfaSequence.class).uniqueResult()).getNextSequence();
The main class mapping:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Jul 5, 2006 5:35:01 PM by Wu -->
<hibernate-mapping>
<class name="com.gal.fast.common.domain.War" table="SFA_WARS" schema="SFA">
<id name="reportId" type="big_decimal">
<column name="WAR_ID" precision="30" scale="15"/>
<generator class="com.gal.fast.common.hib.SfaIdentifierGenerator"/>
</id>
<property name="lastModifiedDate" type="date">
<column name="LAST_MODIFIED_DATE" not-null="true"/>
</property>
<property name="employeeId" type="double">
<column name="EMPLOYEE_ID" not-null="true"/>
</property>
<property name="status" type="string">
<column name="STATUS" not-null="false" length="20"/>
</property>
<component name="ctrl"
class="com.gal.fast.common.hib.domain.component.Ctrl">
<property name="ctrlEmployeeId" type="big_decimal">
<column name="CTRL_EMPLOYEE_ID" precision="30" scale="15"
not-null="true"/>
</property>
<property name="ctrlCreationDate" type="timestamp" update="false">
<column name="CTRL_CREATION_DATE" length="7" not-null="false"/>
</property>
</component>
<bag name="darList" order-by="DAR_DATE" cascade="all" >
<key column="WAR_ID" not-null="true"/>
<one-to-many class="com.gal.fast.common.domain.Dar" />
</bag>
<bag name="subjectList" cascade="none" >
<key column="WAR_ID" not-null="true"/>
<one-to-many class="com.gal.fast.common.domain.WarSubject" />
</bag>
</class>
</hibernate-mapping>
Is this a bug? Or I did something wrong? Thank you for your reply.
|