Versioning sets: IllegalArgumentException

We’re experiencing an issue when we try to use envers to version a persistent object that holds a set of other persistent objects, when we’re using Spring’s JTA transaction manager. We’re consistently getting a

org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is bitronix.tm.internal.BitronixRollbackException: transaction was marked as rollback only and has been rolled back
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1031)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:732)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:701)
at com.ontsys.fw.testutil.transaction.TransactionManager.commit(TransactionManager.java:129)
at com.ontsys.db.inventory.products.dao.ProductSetDAOIntegrationTest.createProduct(ProductSetDAOIntegrationTest.java:409)
at com.ontsys.db.inventory.products.dao.ProductSetDAOIntegrationTest.testRetrieveSetWithSetOfOne(ProductSetDAOIntegrationTest.java:123)

The problem doesn’t happen when we’re using Spring’s HibernateTransactionManager.

The thing that fails succeeds at first

Something that was throwing me for a loop (so to speak) was that the place that is throwing the exception succeeds several times first.  I had a breakpoint in bitronix.tm.BitronixTransaction.fireBeforeCompletionEvent() at the call to synchronization.beforeCompletion(), but I stepped all the way into this and back out, and it worked — the first time.

Counting the times till it fails

I had the idea to keep resuming from that breakpoint to count how many times it succeeded before the exception blew up my test.  I found that it was after it hit the breakpoint in bitronix.tm.BitronixTransaction.fireBeforeCompletionEvent() the eighth time that the beforeCompletion event never returned.  So I set the Hit Count on that breakpoint to 8 (so it wouldn’t break there until the eighth time).

Let’s see that in super slow-motion…

Turns out that it’s the seventh time it hits org.hibernate.event.def.AbstractSaveEventListener.performSave() that the exception occurs, down in a call of org.hibernate.property.BasicPropertyAccessor.BasicSetter.set().  The call stack at the method.invoke() call that will result in the IllegalArgumentException looks like this:

org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(java.lang.Object, java.lang.Object, org.hibernate.engine.SessionFactoryImplementor) line: 66	
org.hibernate.tuple.entity.PojoEntityTuplizer(org.hibernate.tuple.entity.AbstractEntityTuplizer).setIdentifier(java.lang.Object, java.io.Serializable) line: 234	
org.hibernate.persister.entity.SingleTableEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister).setIdentifier(java.lang.Object, java.io.Serializable, org.hibernate.EntityMode) line: 3624	
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.AbstractSaveEventListener).performSave(java.lang.Object, java.io.Serializable, org.hibernate.persister.entity.EntityPersister, boolean, java.lang.Object, org.hibernate.event.EventSource, boolean) line: 194	
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.AbstractSaveEventListener).saveWithGeneratedId(java.lang.Object, java.lang.String, java.lang.Object, org.hibernate.event.EventSource, boolean) line: 144	
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.DefaultSaveOrUpdateEventListener).saveWithGeneratedOrRequestedId(org.hibernate.event.SaveOrUpdateEvent) line: 210	
org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(org.hibernate.event.SaveOrUpdateEvent) line: 56	
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.DefaultSaveOrUpdateEventListener).entityIsTransient(org.hibernate.event.SaveOrUpdateEvent) line: 195	
org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(org.hibernate.event.SaveOrUpdateEvent) line: 50	
org.hibernate.event.def.DefaultSaveEventListener(org.hibernate.event.def.DefaultSaveOrUpdateEventListener).onSaveOrUpdate(org.hibernate.event.SaveOrUpdateEvent) line: 93	
org.hibernate.impl.SessionImpl.fireSave(org.hibernate.event.SaveOrUpdateEvent) line: 562	
org.hibernate.impl.SessionImpl.save(java.lang.String, java.lang.Object) line: 550	
org.jboss.envers.synchronization.work.PersistentCollectionChangeWorkUnit.perform(org.hibernate.Session, java.lang.Object) line: 67	
org.jboss.envers.synchronization.VersionsSync.executeInSession(org.hibernate.Session) line: 120	
org.jboss.envers.synchronization.VersionsSync.beforeCompletion() line: 135	
bitronix.tm.BitronixTransaction.fireBeforeCompletionEvent() line: 366	
bitronix.tm.BitronixTransaction.commit() line: 142	
bitronix.tm.BitronixTransactionManager.commit() line: 96	
org.springframework.transaction.jta.JtaTransactionManager.doCommit(org.springframework.transaction.support.DefaultTransactionStatus) line: 1028	
org.springframework.transaction.jta.JtaTransactionManager(org.springframework.transaction.support.AbstractPlatformTransactionManager).processCommit(org.springframework.transaction.support.DefaultTransactionStatus) line: 732	
org.springframework.transaction.jta.JtaTransactionManager(org.springframework.transaction.support.AbstractPlatformTransactionManager).commit(org.springframework.transaction.TransactionStatus) line: 701	
com.ontsys.fw.testutil.transaction.TransactionManager.commit() line: 129	
com.ontsys.db.inventory.products.dao.ProductSetDAOIntegrationTest.createProduct(com.ontsys.db.inventory.products.po.ProductPO, java.lang.String) line: 409	
com.ontsys.db.inventory.products.dao.ProductSetDAOIntegrationTest.testRetrieveSetWithSetOfOne() line: 123	
...

A Closer Look at the InvalidArgumentException

What is this IllegalArgumentException that BasicPropertyAccessor.BasicSetter.set() catches when it tries the method.invoke()?  The contained message is:

object is not an instance of declaring class

BasicPropertyAccessor.BasicSetter.set() then logs these messages:

IllegalArgumentException in class: com.ontsys.fw.datatypes.BaseTO, setter method of property: key
expected type: java.lang.String, actual value: java.lang.String

(Hmm, expected a java.lang.String but got a java.lang.String, huh?) …and then throwing an exception:

org.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter of com.ontsys.fw.datatypes.BaseTO.key

Going back to the IllegalArgumentException’s message, though: why would our object not be an instance of the declaring class?

That, my friends, will have to wait until next time.

Advertisements

, ,

  1. #1 by Zoran on February 4, 2009 - 8:19 am

    Greatings,
    You need more rest i think

    Thanks
    Zoran

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s