circular reference cache problem

Description

Hi,
As instructed by gavin, I am posting my issue here. Here is the description:

I have a Category class that has a circular reference to itselft. I am using the second-level ehcache cache on this class. The problem is: when I load a Category instance by id, a strange NullPointerException happens in Category.hashCode() when the Category 'name' attribute is accessed in the second line of the Category.hashCode() method. This exception should not happen because name can't be null. This problem only happens when cache is enabled, Category._parent!=null and the Category instance is stored in the cache.
My guess is that hibernate is adding a Category instance to a Set before setting the Category name. Below are the exception stack trace, Category class, Category hibernate mapping and the ehcache configuration file. Please, what do I have to do to solve this problem? Any help would be appreciated.

Thank you very much.

[b]NullPointerException stack trace:/b
[code]
java.lang.NullPointerException
at my.package.Category.hashCode(Category.java:57)
at java.util.HashMap.hash(HashMap.java:261)
at java.util.HashMap.put(HashMap.java:379)
at java.util.HashSet.add(HashSet.java:192)
at net.sf.hibernate.collection.Set.initializeFromCache(Set.java:92)
at net.sf.hibernate.impl.SessionImpl.initializeCollectionFromCache(SessionImpl.java:3963)
at net.sf.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:3262)
at net.sf.hibernate.collection.PersistentCollection.forceInitialization(PersistentCollection.java:336)
at net.sf.hibernate.impl.SessionImpl.initializeNonLazyCollections(SessionImpl.java:3123)
at net.sf.hibernate.impl.SessionImpl.assembleCacheEntry(SessionImpl.java:2139)
at net.sf.hibernate.impl.SessionImpl.doLoad(SessionImpl.java:2112)
at net.sf.hibernate.impl.SessionImpl.doLoadByClass(SessionImpl.java:1991)
at net.sf.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1953)
at net.sf.hibernate.type.ManyToOneType.resolveIdentifier(ManyToOneType.java:69)
at net.sf.hibernate.type.ManyToOneType.assemble(ManyToOneType.java:108)
at net.sf.hibernate.impl.CacheEntry.assemble(CacheEntry.java:56)
at net.sf.hibernate.impl.CacheEntry.assemble(CacheEntry.java:48)
at net.sf.hibernate.impl.SessionImpl.assembleCacheEntry(SessionImpl.java:2134)
at net.sf.hibernate.impl.SessionImpl.doLoad(SessionImpl.java:2112)
at net.sf.hibernate.impl.SessionImpl.doLoadByClass(SessionImpl.java:1991)
at net.sf.hibernate.impl.SessionImpl.load(SessionImpl.java:1920)
at org.apache.jsp.test_jsp._jspService(test_jsp.java:62)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:137)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:210)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:295)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
at com.fabrica.hibernate.web.HibernateSessionFilter.doFilter(HibernateSessionFilter.java:26)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:213)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
at my.package.web.LoggedUserFilter.doFilter(LoggedUserFilter.java:41)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:213)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2422)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:163)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:199)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:828)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:700)
at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:584)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
at java.lang.Thread.run(Thread.java:534)
/code

[b]Category class/b
[code]
public class Category{

private Long _id;
private String _name;
private Category _parent;
private Set _children=new HashSet();

public boolean equals(Object c){
if(this==c){
return true;
}
if(!(c instanceof Category)){
return false;
}

final Category category=(Category)c;

if(!getName().equals(category.getName())){
return false;
}
if(!(getParent()==null ? category.getParent()==null : getParent().equals(category.getParent()))){
return false;
}
return true;
}

public int hashCode(){
int result=31;
result=29*result+getName().hashCode();
if(getParent()!=null){
result=29*result+getParent().hashCode();
}
return result;
}

// other methods
}
/code

[b]Category hibernate mapping file/b
[code]
<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
<class
name="my.package.Category"
table="category"
dynamic-update="false"
dynamic-insert="false"
>
<cache usage="nonstrict-read-write" />

<id
name="id"
column="id"
type="long"
>
<generator class="increment">
</generator>
</id>

<property
name="name"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="name"
length="50"
not-null="true"
/>

<many-to-one

name="parent"
class="my.package.Category"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="parentId"
/>

<set
name="children"
lazy="false"
inverse="true"
cascade="all-delete-orphan"
sort="unsorted"
order-by="name asc"
>
<cache
usage="nonstrict-read-write"
/>

<key
column="parentId"
>
</key>

<one-to-many
class="my.package.Category"
/>
</set>

</class>

</hibernate-mapping>
/code

[b]ehcache configuration/b
[code]
<ehcache>

<diskStore path="java.io.tmpdir"/>

<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
/>

<cache name="my.package.Category"
maxElementsInMemory="100"
eternal="true"
overflowToDisk="false"
/>

</ehcache>
/code

Environment

Hibernate version: 2.1.6
Name and version of the databaseostgresql 7.2

Assignee

Unassigned

Reporter

Jair da Silva Ferreira Jr

Labels

None

Feedback Requested

None

Feedback Requested By

None

backPortable

None

Suitable for new contributors

None

Pull Request

None

backportDecision

None

backportReEvaluate

None

Priority

Major
Configure