Hi,
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.
Hibernate version: 2.1.6
Name and version of the database you are using:postgresql 7.2
NullPointerException stack trace:
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)
Category classCode:
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
}
Category hibernate mapping fileCode:
<?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>
ehcache configurationCode:
<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>