Hi. I'm working on a content manager, and I need to execute some logic whenever an entity (a Publication) changes one of its properties (its validation state), so I'm currently building my SessionFactory with an Interceptor bound to it. The only method I'm implementing is onFlushDirty. It looks like this:
Code:
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) throws CallbackException {
if (entity instanceof Publication) {
boolean currentValidationState = getValidationState(currentState, propertyNames);
boolean previousValidationState = getValidationState(previousState, propertyNames);
if (currentValidationState && !previousValidationState && contentTypeTimestamped((Publication) entity)) {
Version validatedVersion = getValidatedVersion((Publication) entity);
TimestampContentUtil.sign(validatedVersion);
}
}
return false;
}
Publications, Contents and Versions are mapped like this (simplified):
Code:
<hibernate-mapping>
<class
name="com.example.Publication"
table="cm_publication"
proxy="com.example.Publication"
dynamic-update="false"
dynamic-insert="false"
>
<id
name="id"
column="id"
type="java.lang.Long"
>
<generator class="native">
</generator>
</id>
<many-to-one
name="content"
class="com.example.Content"
cascade="none"
outer-join="auto"
update="true"
insert="true"
column="id_content"
not-null="true"
/>
</hibernate-mapping>
<hibernate-mapping>
<class
name="com.example.Content"
table="cm_content"
proxy="com.example.Content"
dynamic-update="false"
dynamic-insert="false"
>
<id
name="id"
column="id"
type="java.lang.Long"
>
<generator class="native">
</generator>
</id>
<set
name="versions"
lazy="true"
inverse="true"
cascade="delete"
sort="unsorted"
>
<key
column="id_content"
/>
<one-to-many
class="com.example.Version"
/>
</set>
</hibernate-mapping>
<hibernate-mapping>
<class
name="com.example.Version"
table="cm_version"
proxy="com.example.Version"
dynamic-update="false"
dynamic-insert="false"
>
<id
name="id"
column="id"
type="java.lang.Long"
>
<generator class="native">
</generator>
</id>
</hibernate-mapping>
As you can see, I'm using proxies and lazy initializations for lists, and despite I've put a simplified mapping configuration, the rest of it it's also pretty simple. The thing is, whenever the contentTypeTimestamped method is called, strange things begin to occur. None of my logic inside onFlushDirty performs any modification to any entity.
The strange things are, for example, that if I try to iterate the versions list later, I get a NullPointerException in the iterator() method of net.sf.hibernate.collection.Set class, since its internal "set" field is null. It doesn't happen if I'm not using the interceptor or the contentTypeTimestamped is not invoked. Another example is that, if I try to iterate over a list of associated contents twice (I didn't put it in the mapping above for sake of simplicity, but it's a simple lazy initialized many to many List), and access a simple String property of its entities, the first iteration works fine, and then on the second, Hibernate starts executing queries like crazy until I get an OutOfMemoryError.
I think it all has to do with the proxies and lazy initializations. But, even if I'm using them, I think I could safely access an entity inside onFlushDirty as long as I don't modify any entity's state. Am I wrong?
I'm using Hibernate 2.1.8, BTW.
Thanks in advance