HHH-11083 WrongClassException using Infinispan and sharing cache regions

* DefaultCacheKeysFactory implements CacheKeysFactory, therefore it can be used in hibernate.cache.keys_factory
* Use DefaultCacheKeysFactory by default
* Add "default" and "simple" as short names for those factories
This commit is contained in:
Radim Vansa 2016-11-11 16:26:09 -05:00 committed by Gail Badner
parent 3e164382c1
commit f744f89bd3
24 changed files with 177 additions and 73 deletions

View File

@ -20,6 +20,9 @@ import org.hibernate.boot.registry.selector.StrategyRegistration;
import org.hibernate.boot.registry.selector.StrategyRegistrationProvider;
import org.hibernate.boot.registry.selector.spi.StrategySelectionException;
import org.hibernate.boot.registry.selector.spi.StrategySelector;
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
import org.hibernate.cache.internal.SimpleCacheKeysFactory;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.dialect.CUBRIDDialect;
import org.hibernate.dialect.Cache71Dialect;
import org.hibernate.dialect.DB2390Dialect;
@ -157,6 +160,7 @@ public class StrategySelectorBuilder {
addMultiTableBulkIdStrategies( strategySelector );
addEntityCopyObserverStrategies( strategySelector );
addImplicitNamingStrategies( strategySelector );
addCacheKeysFactories( strategySelector );
// apply auto-discovered registrations
for ( StrategyRegistrationProvider provider : classLoaderService.loadJavaServices( StrategyRegistrationProvider.class ) ) {
@ -436,4 +440,17 @@ public class StrategySelectorBuilder {
ImplicitNamingStrategyComponentPathImpl.class
);
}
private void addCacheKeysFactories(StrategySelectorImpl strategySelector) {
strategySelector.registerStrategyImplementor(
CacheKeysFactory.class,
DefaultCacheKeysFactory.SHORT_NAME,
DefaultCacheKeysFactory.class
);
strategySelector.registerStrategyImplementor(
CacheKeysFactory.class,
SimpleCacheKeysFactory.SHORT_NAME,
SimpleCacheKeysFactory.class
);
}
}

View File

@ -38,61 +38,61 @@ import org.hibernate.persister.entity.EntityPersister;
* @author Sanne Grinovero
* @since 5.0
*/
public class DefaultCacheKeysFactory {
public class DefaultCacheKeysFactory implements CacheKeysFactory {
public static final String SHORT_NAME = "default";
public static final DefaultCacheKeysFactory INSTANCE = new DefaultCacheKeysFactory();
public static Object createCollectionKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
public static Object staticCreateCollectionKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return new OldCacheKeyImplementation( id, persister.getKeyType(), persister.getRole(), tenantIdentifier, factory );
}
public static Object createEntityKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
public static Object staticCreateEntityKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return new OldCacheKeyImplementation( id, persister.getIdentifierType(), persister.getRootEntityName(), tenantIdentifier, factory );
}
public static Object createNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
public static Object staticCreateNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return new OldNaturalIdCacheKey( naturalIdValues, persister.getPropertyTypes(), persister.getNaturalIdentifierProperties(), persister.getRootEntityName(), session );
}
public static Object getEntityId(Object cacheKey) {
public static Object staticGetEntityId(Object cacheKey) {
return ((OldCacheKeyImplementation) cacheKey).getId();
}
public static Object getCollectionId(Object cacheKey) {
public static Object staticGetCollectionId(Object cacheKey) {
return ((OldCacheKeyImplementation) cacheKey).getId();
}
public static Object[] getNaturalIdValues(Object cacheKey) {
public static Object[] staticGetNaturalIdValues(Object cacheKey) {
return ((OldNaturalIdCacheKey) cacheKey).getNaturalIdValues();
}
public static CacheKeysFactory INSTANCE = new CacheKeysFactory() {
@Override
public Object createCollectionKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createCollectionKey(id, persister, factory, tenantIdentifier);
}
@Override
public Object createCollectionKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return staticCreateCollectionKey(id, persister, factory, tenantIdentifier);
}
@Override
public Object createEntityKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createEntityKey(id, persister, factory, tenantIdentifier);
}
@Override
public Object createEntityKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return staticCreateEntityKey(id, persister, factory, tenantIdentifier);
}
@Override
public Object createNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return DefaultCacheKeysFactory.createNaturalIdKey(naturalIdValues, persister, session);
}
@Override
public Object createNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return staticCreateNaturalIdKey(naturalIdValues, persister, session);
}
@Override
public Object getEntityId(Object cacheKey) {
return DefaultCacheKeysFactory.getEntityId(cacheKey);
}
@Override
public Object getEntityId(Object cacheKey) {
return staticGetEntityId(cacheKey);
}
@Override
public Object getCollectionId(Object cacheKey) {
return DefaultCacheKeysFactory.getCollectionId(cacheKey);
}
@Override
public Object getCollectionId(Object cacheKey) {
return staticGetCollectionId(cacheKey);
}
@Override
public Object[] getNaturalIdValues(Object cacheKey) {
return DefaultCacheKeysFactory.getNaturalIdValues(cacheKey);
}
};
@Override
public Object[] getNaturalIdValues(Object cacheKey) {
return staticGetNaturalIdValues(cacheKey);
}
}

View File

@ -18,8 +18,8 @@ import org.hibernate.persister.entity.EntityPersister;
* @author Radim Vansa <rvansa@redhat.com>
*/
public class SimpleCacheKeysFactory implements CacheKeysFactory {
public static CacheKeysFactory INSTANCE = new SimpleCacheKeysFactory();
public static final String SHORT_NAME = "simple";
public static CacheKeysFactory INSTANCE = new SimpleCacheKeysFactory();
@Override
public Object createCollectionKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {

View File

@ -61,7 +61,7 @@ public class NaturalIdCacheKeyTest {
}
});
final OldNaturalIdCacheKey key = (OldNaturalIdCacheKey) DefaultCacheKeysFactory.createNaturalIdKey( new Object[] {"a", "b", "c"}, entityPersister, sessionImplementor );
final OldNaturalIdCacheKey key = (OldNaturalIdCacheKey) DefaultCacheKeysFactory.staticCreateNaturalIdKey( new Object[] {"a", "b", "c"}, entityPersister, sessionImplementor );
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ObjectOutputStream oos = new ObjectOutputStream(baos);

View File

@ -163,11 +163,11 @@ public class NonstopAwareCollectionRegionAccessStrategy implements CollectionReg
@Override
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createCollectionKey( id, persister, factory, tenantIdentifier );
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getCollectionId(cacheKey);
return DefaultCacheKeysFactory.staticGetCollectionId(cacheKey);
}
}

View File

@ -209,11 +209,11 @@ public class NonstopAwareEntityRegionAccessStrategy implements EntityRegionAcces
@Override
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createEntityKey( id, persister, factory, tenantIdentifier );
return DefaultCacheKeysFactory.staticCreateEntityKey( id, persister, factory, tenantIdentifier );
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getEntityId(cacheKey);
return DefaultCacheKeysFactory.staticGetEntityId(cacheKey);
}
}

View File

@ -206,11 +206,11 @@ public class NonstopAwareNaturalIdRegionAccessStrategy implements NaturalIdRegio
@Override
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return DefaultCacheKeysFactory.createNaturalIdKey( naturalIdValues, persister, session );
return DefaultCacheKeysFactory.staticCreateNaturalIdKey( naturalIdValues, persister, session );
}
@Override
public Object[] getNaturalIdValues(Object cacheKey) {
return DefaultCacheKeysFactory.getNaturalIdValues(cacheKey);
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
}
}

View File

@ -86,11 +86,11 @@ public class NonStrictReadWriteEhcacheCollectionRegionAccessStrategy
@Override
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createCollectionKey( id, persister, factory, tenantIdentifier );
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getCollectionId( cacheKey );
return DefaultCacheKeysFactory.staticGetCollectionId( cacheKey );
}
}

View File

@ -125,11 +125,11 @@ public class NonStrictReadWriteEhcacheEntityRegionAccessStrategy
@Override
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createEntityKey( id, persister, factory, tenantIdentifier );
return DefaultCacheKeysFactory.staticCreateEntityKey( id, persister, factory, tenantIdentifier );
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getEntityId( cacheKey );
return DefaultCacheKeysFactory.staticGetEntityId( cacheKey );
}
}

View File

@ -122,11 +122,11 @@ public class NonStrictReadWriteEhcacheNaturalIdRegionAccessStrategy
@Override
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return DefaultCacheKeysFactory.createNaturalIdKey(naturalIdValues, persister, session);
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
}
@Override
public Object[] getNaturalIdValues(Object cacheKey) {
return DefaultCacheKeysFactory.getNaturalIdValues( cacheKey );
return DefaultCacheKeysFactory.staticGetNaturalIdValues( cacheKey );
}
}

View File

@ -75,11 +75,11 @@ public class ReadOnlyEhcacheCollectionRegionAccessStrategy
@Override
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createCollectionKey( id, persister, factory, tenantIdentifier );
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getCollectionId(cacheKey);
return DefaultCacheKeysFactory.staticGetCollectionId(cacheKey);
}
}

View File

@ -117,11 +117,11 @@ public class ReadOnlyEhcacheEntityRegionAccessStrategy extends AbstractEhcacheAc
@Override
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createEntityKey( id, persister, factory, tenantIdentifier );
return DefaultCacheKeysFactory.staticCreateEntityKey( id, persister, factory, tenantIdentifier );
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getEntityId(cacheKey);
return DefaultCacheKeysFactory.staticGetEntityId(cacheKey);
}
}

View File

@ -115,11 +115,11 @@ public class ReadOnlyEhcacheNaturalIdRegionAccessStrategy
@Override
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return DefaultCacheKeysFactory.createNaturalIdKey(naturalIdValues, persister, session);
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
}
@Override
public Object[] getNaturalIdValues(Object cacheKey) {
return DefaultCacheKeysFactory.getNaturalIdValues(cacheKey);
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
}
}

View File

@ -42,11 +42,11 @@ public class ReadWriteEhcacheCollectionRegionAccessStrategy
@Override
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createCollectionKey( id, persister, factory, tenantIdentifier );
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getCollectionId(cacheKey);
return DefaultCacheKeysFactory.staticGetCollectionId(cacheKey);
}
}

View File

@ -124,11 +124,11 @@ public class ReadWriteEhcacheEntityRegionAccessStrategy
@Override
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createEntityKey(id, persister, factory, tenantIdentifier);
return DefaultCacheKeysFactory.staticCreateEntityKey(id, persister, factory, tenantIdentifier);
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getEntityId(cacheKey);
return DefaultCacheKeysFactory.staticGetEntityId(cacheKey);
}
}

View File

@ -121,11 +121,11 @@ public class ReadWriteEhcacheNaturalIdRegionAccessStrategy
@Override
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return DefaultCacheKeysFactory.createNaturalIdKey(naturalIdValues, persister, session);
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
}
@Override
public Object[] getNaturalIdValues(Object cacheKey) {
return DefaultCacheKeysFactory.getNaturalIdValues(cacheKey);
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
}
}

View File

@ -106,11 +106,11 @@ public class TransactionalEhcacheCollectionRegionAccessStrategy
@Override
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createCollectionKey( id, persister, factory, tenantIdentifier );
return DefaultCacheKeysFactory.staticCreateCollectionKey( id, persister, factory, tenantIdentifier );
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getCollectionId(cacheKey);
return DefaultCacheKeysFactory.staticGetCollectionId(cacheKey);
}
}

View File

@ -144,11 +144,11 @@ public class TransactionalEhcacheEntityRegionAccessStrategy extends AbstractEhca
@Override
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createEntityKey(id, persister, factory, tenantIdentifier);
return DefaultCacheKeysFactory.staticCreateEntityKey(id, persister, factory, tenantIdentifier);
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getEntityId(cacheKey);
return DefaultCacheKeysFactory.staticGetEntityId(cacheKey);
}
}

View File

@ -137,11 +137,11 @@ public class TransactionalEhcacheNaturalIdRegionAccessStrategy
@Override
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return DefaultCacheKeysFactory.createNaturalIdKey(naturalIdValues, persister, session);
return DefaultCacheKeysFactory.staticCreateNaturalIdKey(naturalIdValues, persister, session);
}
@Override
public Object[] getNaturalIdValues(Object cacheKey) {
return DefaultCacheKeysFactory.getNaturalIdValues(cacheKey);
return DefaultCacheKeysFactory.staticGetNaturalIdValues(cacheKey);
}
}

View File

@ -22,6 +22,7 @@ dependencies {
compile( libraries.infinispan )
testCompile project( ':hibernate-testing' )
testCompile project( ':hibernate-entitymanager' )
testCompile( libraries.infinispan_test )
testCompile( libraries.jboss_common_core )
testCompile( libraries.jnp_client )

View File

@ -453,14 +453,10 @@ public class InfinispanRegionFactory implements RegionFactory {
}
private CacheKeysFactory determineCacheKeysFactory(SessionFactoryOptions settings, Properties properties) {
final CacheKeysFactory implicitFactory = settings.getMultiTenancyStrategy() != MultiTenancyStrategy.NONE
? DefaultCacheKeysFactory.INSTANCE
: SimpleCacheKeysFactory.INSTANCE;
return settings.getServiceRegistry().getService( StrategySelector.class ).resolveDefaultableStrategy(
CacheKeysFactory.class,
properties.get( AvailableSettings.CACHE_KEYS_FACTORY ),
implicitFactory
DefaultCacheKeysFactory.INSTANCE
);
}
@ -686,8 +682,7 @@ public class InfinispanRegionFactory implements RegionFactory {
log.debugf("Region '%s' has additional configuration set through properties.", regionName);
builder.read(override.build(false));
}
// with multi-tenancy the keys will be wrapped
if (settings.getMultiTenancyStrategy() == MultiTenancyStrategy.NONE) {
if (getCacheKeysFactory() instanceof SimpleCacheKeysFactory) {
// the keys may not define hashCode/equals correctly (e.g. arrays)
if (metadata != null && metadata.getKeyType() != null) {
builder.dataContainer().keyEquivalence(new TypeEquivalance(metadata.getKeyType()));

View File

@ -0,0 +1,87 @@
package org.hibernate.test.cache.infinispan;
import org.hibernate.SessionFactory;
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
import org.hibernate.cache.internal.SimpleCacheKeysFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.spi.CacheImplementor;
import org.hibernate.jpa.AvailableSettings;
import org.hibernate.test.cache.infinispan.functional.entities.Name;
import org.hibernate.test.cache.infinispan.functional.entities.Person;
import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup;
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.infinispan.Cache;
import org.junit.Rule;
import org.junit.Test;
import java.util.Iterator;
import static org.hibernate.test.cache.infinispan.util.TxUtil.withTxSession;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class CacheKeysFactoryTest extends BaseUnitTestCase {
@Rule
public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup();
private SessionFactory getSessionFactory(String cacheKeysFactory) {
Configuration configuration = new Configuration()
.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true")
.setProperty(Environment.CACHE_REGION_FACTORY, TestInfinispanRegionFactory.class.getName())
.setProperty(Environment.DEFAULT_CACHE_CONCURRENCY_STRATEGY, "transactional")
.setProperty(AvailableSettings.SHARED_CACHE_MODE, "ALL")
.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
if (cacheKeysFactory != null) {
configuration.setProperty(Environment.CACHE_KEYS_FACTORY, cacheKeysFactory);
}
configuration.addAnnotatedClass(Person.class);
return configuration.buildSessionFactory();
}
@Test
public void testNotSet() throws Exception {
test(null, "OldCacheKeyImplementation");
}
@Test
public void testDefault() throws Exception {
test(DefaultCacheKeysFactory.SHORT_NAME, "OldCacheKeyImplementation");
}
@Test
public void testDefaultClass() throws Exception {
test(DefaultCacheKeysFactory.class.getName(), "OldCacheKeyImplementation");
}
@Test
public void testSimple() throws Exception {
test(SimpleCacheKeysFactory.SHORT_NAME, Name.class.getSimpleName());
}
@Test
public void testSimpleClass() throws Exception {
test(SimpleCacheKeysFactory.class.getName(), Name.class.getSimpleName());
}
private void test(String cacheKeysFactory, String keyClassName) throws Exception {
SessionFactory sessionFactory = getSessionFactory(cacheKeysFactory);
withTxSession(false, sessionFactory, s -> {
Person person = new Person("John", "Black", 39);
s.persist(person);
});
TestInfinispanRegionFactory regionFactory = (TestInfinispanRegionFactory) ((CacheImplementor) sessionFactory.getCache()).getRegionFactory();
Cache<Object, Object> cache = regionFactory.getCacheManager().getCache(Person.class.getName());
Iterator<Object> iterator = cache.getAdvancedCache().getDataContainer().keySet().iterator();
assertTrue(iterator.hasNext());
Object key = iterator.next();
assertEquals(keyClassName, key.getClass().getSimpleName());
withTxSession(false, sessionFactory, s -> {
Person person = s.load(Person.class, new Name("John", "Black"));
assertEquals(39, person.getAge());
});
}
}

View File

@ -13,6 +13,7 @@ import java.util.Map;
import org.hibernate.Session;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cache.internal.SimpleCacheKeysFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.AvailableSettings;
@ -181,6 +182,7 @@ public abstract class AbstractFunctionalTest extends BaseNonConfigCoreFunctional
settings.put( Environment.GENERATE_STATISTICS, "true" );
settings.put( Environment.USE_QUERY_CACHE, String.valueOf( getUseQueryCache() ) );
settings.put( Environment.CACHE_REGION_FACTORY, getRegionFactoryClass().getName() );
settings.put( Environment.CACHE_KEYS_FACTORY, SimpleCacheKeysFactory.SHORT_NAME );
settings.put( TestInfinispanRegionFactory.TRANSACTIONAL, useTransactionalCache );
settings.put( TestInfinispanRegionFactory.CACHE_MODE, cacheMode);

View File

@ -1,5 +1,6 @@
package org.hibernate.test.cache.infinispan.functional.entities;
import javax.persistence.Cacheable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Transient;
@ -12,6 +13,7 @@ import java.io.Serializable;
* @author Radim Vansa &lt;rvansa@redhat.com&gt;
*/
@Entity
@Cacheable
public class Person implements Serializable {
@EmbeddedId
Name name;