When @Cache.usage changes, casting exception is thrown
rica-v3 opened this issue · comments
rica commented
After changing "CacheConcurrencyStrategy" READ_ONLY to READ_WRITE, getting entity occurs the exception below.
Cause:
The cached entity is StandardCacheEntryImpl but current entity should be AbstractReadWriteAccess$Lockable
org.hibernate.HibernateException: Unable to perform afterTransactionCompletion callback: org.hibernate.cache.spi.entry.StandardCacheEntryImpl cannot be cast to org.hibernate.cache.spi.support.AbstractReadWriteAccess$Lockable
at org.hibernate.engine.spi.ActionQueue$AfterTransactionCompletionProcessQueue.afterTransactionCompletion(ActionQueue.java:990)
at org.hibernate.engine.spi.ActionQueue.afterTransactionCompletion(ActionQueue.java:513)
at org.hibernate.internal.SessionImpl.afterTransactionCompletion(SessionImpl.java:2404)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.afterTransactionCompletion(JdbcCoordinatorImpl.java:454)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.afterCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:203)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$400(JdbcResourceLocalTransactionCoordinatorImpl.java:40)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:283)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
at hibernate.CollectionCacheTest.testCollectionCache_whenCollectionCacheIsPut_thenCollectionCacheShouldBeHitForTheNextGet(CollectionCacheTest.java:98)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.hibernate.testing.junit4.ExtendedFrameworkMethod.invokeExplosively(ExtendedFrameworkMethod.java:45)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298)
at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ClassCastException: org.hibernate.cache.spi.entry.StandardCacheEntryImpl cannot be cast to org.hibernate.cache.spi.support.AbstractReadWriteAccess$Lockable
at org.hibernate.cache.spi.support.EntityReadWriteAccess.afterInsert(EntityReadWriteAccess.java:85)
at org.hibernate.action.internal.EntityInsertAction.cacheAfterInsert(EntityInsertAction.java:257)
at org.hibernate.action.internal.EntityInsertAction.doAfterTransactionCompletion(EntityInsertAction.java:239)
at org.hibernate.engine.spi.ActionQueue$AfterTransactionCompletionProcessQueue.afterTransactionCompletion(ActionQueue.java:983)
... 23 more
Solution:
When changing CacheConcurrencyStrategy, regionName should be modified together not to reuse same cache items
rica commented
To resolve the casting exception, EntityReadWriteAccess needs to be overridden by handling Casting Exception
package org.hibernate.cache.spi.support;
public class EntityReadWriteAccess extends AbstractReadWriteAccess implements EntityDataAccess
@Override
public boolean afterInsert(SharedSessionContractImplementor session, Object key, Object value, Object version) {
try {
writeLock().lock();
* Lockable item = (Lockable) getStorageAccess().getFromCache( key, session ); // <--- casting exception point #1
if ( item == null ) {
getStorageAccess().putIntoCache(
key,
new Item( value, version, getRegion().getRegionFactory().nextTimestamp() ),
session
);
return true;
}
else {
return false;
}
}
finally {
writeLock().unlock();
}
}
@Override
public boolean afterUpdate(
SharedSessionContractImplementor session,
Object key,
Object value,
Object currentVersion,
Object previousVersion,
SoftLock lock) {
try {
writeLock().lock();
* Lockable item = (Lockable) getStorageAccess().getFromCache( key, session ); // <--- casting exception point #2
if ( item != null && item.isUnlockable( lock ) ) {
SoftLockImpl lockItem = (SoftLockImpl) item;
if ( lockItem.wasLockedConcurrently() ) {
decrementLock( session, key, lockItem );
return false;
}
else {
getStorageAccess().putIntoCache(
key,
new Item( value, currentVersion, getRegion().getRegionFactory().nextTimestamp() ),
session
);
return true;
}
}
else {
handleLockExpiry(session, key, item );
return false;
}
}
finally {
writeLock().unlock();
}
}
rica commented
This is not a bug, but is intended by hibernate-orm
Solution:
When changing CacheConcurrencyStrategy, regionName should be modified together not to reuse same cache items