Don't know if it is a bug or not, so lets first try the forum before submitting a bug report. I'm working on a web application where a lot of classes extend a single class called PublicationControlled. Which currently only functions as a placeholder for future code controlling the publication of data.
When we don't active the caching functionallity of Hibernate, we don't have any issues with it. But if we do active caching (EHCache of OSCache, those 2 have been tried). We seem to have discovered a change in the results given back.
Normally we request a Object from hibernate by issuing session.get(clazz, id). All is fine when we use our webapplication as we intend. But offcourse we have to see what happens when somebody messes with the requests.
So we tried to request some objects we know that didn't exists. All is ok, but when we request the ID of a object of a different subclass we see a change in returned results when caching is active or not.
For example we change to URL for requesting the details of a Expert object:
http://www.ourserver.com/ExpertDetail.do?id=60
to:
http://www.ourserver.com/ExpertDetail.do?id=660
which is the ID off a Study object in our database.
Without caching active hibernate returned us NULL, which is what was expected after looking at the hibernate API. But when caching is activated we get a Study object back. But whe requested a Expert ?
In our code we check it the returned type is of the same class of the requested type with an assert. So we stop working with information we can't do anything with. (See related code)
I don't know if this this change in behaviour is intended or not?? We can simply work around this issue. But we still wanted to report this.
Hibernate version:
2.1.7c
Mapping documents:
PublicationControlled (Base class)
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.PublicationControlled"
dynamic-update="false"
dynamic-insert="false">
<cache usage="read-write"/>
<id name="id"
column="id"
type="java.lang.Long"
unsaved-value="null">
<generator class="native" />
</id>
<property name="comment"
type="text"
update="true"
insert="true"
access="property"
column="comment" />
</class>
</hibernate-mapping>
Expert (Subclass of PublicationControlled)
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>
<joined-subclass name="my.package.Expert"
dynamic-update="true"
dynamic-insert="false"
extends="my.package.PublicationControlled">
<key column="id" />
<property name="title"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="title"
length="100" />
<property name="givenNames"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="givenNames"
length="100" />
<property name="lastName"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="lastName"
length="100"
not-null="true" />
<!-- Bunch of properties, components and relations removed so post will not be tooo long -->
</hibernate-mapping>
Study (Subclass of PublicationControlled)
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>
<joined-subclass name="my.package.Study"
dynamic-update="true"
dynamic-insert="false"
extends="my.package.PublicationControlled">
<key column="id" />
<property name="name"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="name"
length="50"
not-null="true" />
<property name="title"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="title"
length="100"
not-null="true" />
<property name="description"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="description"
length="255" />
<!-- Bunch of properties, components and relations removed so post will not be tooo long -->
</joined-subclass>
</hibernate-mapping>
Name and version of the database you are using:MySQL 4.0.21
Related code:Code:
public PersistentBean retrievePersistentBean(
final Long id,
final Class persistentObjectType)
throws IdNotFoundException, TechnicalException {
LOG.debug("Retrieving record with id = " + id + " ..."); //$NON-NLS-1$ //$NON-NLS-2$
if (getSession() == null) {
throw new TechnicalException(NULL_SESSION, null);
}
if (id == null) {
throw new IdNotFoundException(id, "ID_IS_NULL", //$NON-NLS-1$
null, persistentObjectType);
}
if (persistentObjectType == null) {
throw new TechnicalException(NO_PERSISTENT_OBJECT, null);
}
if (!PersistentBean.class.isAssignableFrom(persistentObjectType)) {
throw new TechnicalException(persistentObjectType.toString()
+ WRONG_SUBTYPE,
null);
}
PersistentBean result = null;
try {
result = (PersistentBean)getSession().get(persistentObjectType, id);
if (result == null) {
LOG.debug("Record not found"); //$NON-NLS-1$
throw new IdNotFoundException(id, null, null, persistentObjectType);
}
}
catch (ClassCastException ccExc) {
throw new TechnicalException("retrieved object was not a PersistentBean", //$NON-NLS-1$
ccExc);
}
catch (HibernateException hExc) {
// this cannot be that we did not find an object with that id, since we
// use get
throw new TechnicalException("problem getting record from DB", hExc); //$NON-NLS-1$
}
assert result != null;
assert result.getId().equals(id);
assert persistentObjectType.isInstance(result);
if (LOG.isDebugEnabled()) {
LOG.debug("Retrieval succeeded (" + result + ")"); //$NON-NLS-1$ //$NON-NLS-2$
}
return result;
}
assert persistentObjectType.isInstance(result);
doesn't give any trouble we caching isn't used, but does when we active caching (EHCache and OSCache tested)
Debug level Hibernate log excerpt:
DEBUG of the ill formed request from cache (requesting a Expert object with the ID (660) of a Study object):
09:52:48,587 DEBUG SessionImpl:558 - opened session
09:52:48,589 DEBUG SessionImpl:1995 - loading [my.package.Expert#660]
09:52:48,590 DEBUG SessionImpl:2093 - attempting to resolve [my.package.Expert#660]
09:52:48,592 DEBUG ReadWriteCache:69 - Cache lookup: 660
09:52:48,595 DEBUG ReadWriteCache:79 - Cache hit: 660
09:52:48,597 DEBUG SessionImpl:2141 - resolved object in second-level cache [my.package.Expert#660]
09:52:48,598 DEBUG SessionImpl:3982 - creating collection wrapper:[my.package.$investigators#660]
09:52:48,601 DEBUG SessionImpl:3982 - creating collection wrapper:[my.package.Study.$studySponsorships#660]
09:52:48,603 DEBUG SessionImpl:2150 - Cached Version: null
09:52:48,604 DEBUG SessionImpl:3149 - initializing non-lazy collections
StandardWrapperValve[action]: Servlet.service() for servlet action threw exception
java.lang.AssertionError
(Investigator and StudySponsorship collection are part of a Study object, NOT a Expert object)