-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Weird behaviour using Interceptors
PostPosted: Wed Jun 17, 2009 6:30 am 
Newbie

Joined: Tue Dec 07, 2004 12:44 pm
Posts: 13
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


Top
 Profile  
 
 Post subject: Re: Weird behaviour using Interceptors
PostPosted: Wed Jun 17, 2009 6:57 am 
Newbie

Joined: Tue Dec 07, 2004 12:44 pm
Posts: 13
I've just removed the proxies and lazy initializations in the Content-Version relationship, and then I don't get the NPE on the net.sf.hibernate.collection.Set class, but I get one later in another lazy initialized List, exactly on the method size() of net.sf.hibernate.collection.List. The error is basically the same, its wrapped list is null when it's trying to access it.

Both the iterator() method inside Set class and size() inside List have an invocation to read() (right before it invokes the corresponding method on the wrapped objects), which I suppose it should initialize the collections correctly, but it seems it isn't.

Why are these NPE happening on lazy initialized collections if I try to read objects with lazy initializations inside onFlushDirty?

Thanks again


Top
 Profile  
 
 Post subject: Re: Weird behaviour using Interceptors
PostPosted: Wed Jun 17, 2009 7:50 am 
Newbie

Joined: Tue Dec 07, 2004 12:44 pm
Posts: 13
I'm trying to get down to the root of the problem. It seems that the point that makes everything work or fail is the getLoadingCollection() method inside SessionImpl class. This is an extract of it:

Code:
PersistentCollection pc = getCollection(ckey);
if (pc!=null) {
   CollectionEntry ce = getCollectionEntry(pc);
   if (ce.initialized) {
      log.trace( "collection already initialized: ignoring");
      return null; //ignore this row of results! Note the early exit
   }
   else {
      //initialize this collection
      log.trace( "uninitialized collection: initializing");
   }
}
else {
   Object entity = getCollectionOwner(id, persister);
   if ( entity!=null && getEntry(entity).status!=LOADING ) {
      //important, to account for newly saved entities in query
      log.trace("owning entity already loaded: ignoring");
      return null;
   }
   else {
      //create one
      log.trace( "new collection: instantiating");
      pc = persister.getCollectionType().instantiate(this, persister);
   }
}


When everyting works fine (i. e., I don't configure an Interceptor), the call to getCollection(ckey) returns a PersistentCollection object whose associated CollectionEntry is not initialized, so the collection gets initialized.

But when I'm using my Interceptor, getCollection(ckey) returns null and then, getCollectionOwner(id, persister) returns an entity whose associated EntityEntry is in LOADED status, so the method returns and no initialization is performed, and then a NullPointerException is thrown.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.