HHH-6207 Implementing binding of @Cacheable. Changing implementation of Caching to use AccessType enum instead of string

This commit is contained in:
Hardy Ferentschik 2011-05-11 15:12:06 +02:00
parent 3dfeceffe3
commit 850cfda6c3
8 changed files with 144 additions and 44 deletions

View File

@ -23,13 +23,20 @@
*/ */
package org.hibernate.metamodel; package org.hibernate.metamodel;
import javax.persistence.SharedCacheMode;
import org.hibernate.cfg.NamingStrategy; import org.hibernate.cfg.NamingStrategy;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
* @author Hardy Ferentschik
*/ */
public interface MetadataBuilder { public interface MetadataBuilder {
public MetadataBuilder with(NamingStrategy namingStrategy); public MetadataBuilder with(NamingStrategy namingStrategy);
public MetadataBuilder with(SourceProcessingOrder sourceProcessingOrder); public MetadataBuilder with(SourceProcessingOrder sourceProcessingOrder);
public MetadataBuilder with(SharedCacheMode cacheMode);
public Metadata buildMetadata(); public Metadata buildMetadata();
} }

View File

@ -69,6 +69,8 @@ public class MetadataSources {
private final EntityResolver entityResolver; private final EntityResolver entityResolver;
private final NamingStrategy namingStrategy; private final NamingStrategy namingStrategy;
private final MetadataBuilderImpl metadataBuilder;
public MetadataSources(BasicServiceRegistry serviceRegistry) { public MetadataSources(BasicServiceRegistry serviceRegistry) {
this( serviceRegistry, EJB3DTDEntityResolver.INSTANCE, EJB3NamingStrategy.INSTANCE ); this( serviceRegistry, EJB3DTDEntityResolver.INSTANCE, EJB3NamingStrategy.INSTANCE );
} }
@ -79,6 +81,7 @@ public class MetadataSources {
this.namingStrategy = namingStrategy; this.namingStrategy = namingStrategy;
this.jaxbHelper = new JaxbHelper( this ); this.jaxbHelper = new JaxbHelper( this );
this.metadataBuilder = new MetadataBuilderImpl( this );
} }
public List<JaxbRoot> getJaxbRootList() { public List<JaxbRoot> getJaxbRootList() {
@ -102,7 +105,7 @@ public class MetadataSources {
} }
public MetadataBuilder getMetadataBuilder() { public MetadataBuilder getMetadataBuilder() {
return new MetadataBuilderImpl( this ); return metadataBuilder;
} }
public Metadata buildMetadata() { public Metadata buildMetadata() {

View File

@ -23,22 +23,25 @@
*/ */
package org.hibernate.metamodel.binding; package org.hibernate.metamodel.binding;
import org.hibernate.cache.spi.access.AccessType;
/** /**
* Defines the caching settings for an entity. * Defines the caching settings for an entity.
* *
* @author Steve Ebersole * @author Steve Ebersole
* @author Hardy Ferentschik
*/ */
public class Caching { public class Caching {
private String region; private String region;
private String strategy; private AccessType accessType;
private boolean cacheLazyProperties; private boolean cacheLazyProperties;
public Caching() { public Caching() {
} }
public Caching(String region, String strategy, boolean cacheLazyProperties) { public Caching(String region, AccessType accessType, boolean cacheLazyProperties) {
this.region = region; this.region = region;
this.strategy = strategy; this.accessType = accessType;
this.cacheLazyProperties = cacheLazyProperties; this.cacheLazyProperties = cacheLazyProperties;
} }
@ -50,12 +53,12 @@ public class Caching {
this.region = region; this.region = region;
} }
public String getStrategy() { public AccessType getAccessType() {
return strategy; return accessType;
} }
public void setStrategy(String strategy) { public void setAccessType(AccessType accessType) {
this.strategy = strategy; this.accessType = accessType;
} }
public boolean isCacheLazyProperties() { public boolean isCacheLazyProperties() {
@ -65,4 +68,15 @@ public class Caching {
public void setCacheLazyProperties(boolean cacheLazyProperties) { public void setCacheLazyProperties(boolean cacheLazyProperties) {
this.cacheLazyProperties = cacheLazyProperties; this.cacheLazyProperties = cacheLazyProperties;
} }
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append( "Caching" );
sb.append( "{region='" ).append( region ).append( '\'' );
sb.append( ", accessType=" ).append( accessType );
sb.append( ", cacheLazyProperties=" ).append( cacheLazyProperties );
sb.append( '}' );
return sb.toString();
}
} }

View File

@ -34,6 +34,8 @@ import org.hibernate.MappingException;
import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.OptimisticLockType; import org.hibernate.annotations.OptimisticLockType;
import org.hibernate.annotations.PolymorphismType; import org.hibernate.annotations.PolymorphismType;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.binding.Caching; import org.hibernate.metamodel.binding.Caching;
import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.EntityBinding;
@ -70,7 +72,8 @@ public class EntityBinder {
bindJpaEntityAnnotation( entityBinding ); bindJpaEntityAnnotation( entityBinding );
bindHibernateEntityAnnotation( entityBinding ); // optional hibernate specific @org.hibernate.annotations.Entity bindHibernateEntityAnnotation( entityBinding ); // optional hibernate specific @org.hibernate.annotations.Entity
bindWhereFilter( entityBinding ); bindWhereFilter( entityBinding );
bindCaching( entityBinding ); bindJpaCaching( entityBinding );
bindHibernateCaching( entityBinding );
schemaName = createSchemaName(); schemaName = createSchemaName();
bindTable( entityBinding ); bindTable( entityBinding );
@ -93,41 +96,90 @@ public class EntityBinder {
} }
} }
private void bindCaching(EntityBinding entityBinding) { private void bindHibernateCaching(EntityBinding entityBinding) {
AnnotationInstance cacheAnnotation = JandexHelper.getSingleAnnotation( AnnotationInstance cacheAnnotation = JandexHelper.getSingleAnnotation(
configuredClass.getClassInfo(), HibernateDotNames.CACHE configuredClass.getClassInfo(), HibernateDotNames.CACHE
); );
if ( cacheAnnotation != null ) { if ( cacheAnnotation == null ) {
String region; return;
if ( cacheAnnotation.value( "region" ) != null ) { }
region = cacheAnnotation.value( "region" ).asString();
String region;
if ( cacheAnnotation.value( "region" ) != null ) {
region = cacheAnnotation.value( "region" ).asString();
}
else {
region = entityBinding.getEntity().getName();
}
boolean cacheLazyProperties = true;
if ( cacheAnnotation.value( "include" ) != null ) {
String tmp = cacheAnnotation.value( "include" ).asString();
if ( "all".equalsIgnoreCase( tmp ) ) {
cacheLazyProperties = true;
}
else if ( "non-lazy".equalsIgnoreCase( tmp ) ) {
cacheLazyProperties = false;
} }
else { else {
region = entityBinding.getEntity().getName(); throw new AnnotationException( "Unknown lazy property annotations: " + tmp );
} }
}
boolean cacheLazyProperties = true; CacheConcurrencyStrategy strategy = CacheConcurrencyStrategy.valueOf(
if ( cacheAnnotation.value( "include" ) != null ) { cacheAnnotation.value( "usage" ).asEnum()
String tmp = cacheAnnotation.value( "include" ).asString(); );
if ( "all".equalsIgnoreCase( tmp ) ) { Caching caching = new Caching( region, strategy.toAccessType(), cacheLazyProperties );
cacheLazyProperties = true; entityBinding.setCaching( caching );
} }
else if ( "non-lazy".equalsIgnoreCase( tmp ) ) {
cacheLazyProperties = false; // This does not take care of any inheritance of @Cacheable within a class hierarchy as specified in JPA2.
} // This is currently not supported (HF)
else { private void bindJpaCaching(EntityBinding entityBinding) {
throw new AnnotationException( "Unknown lazy property annotations: " + tmp ); AnnotationInstance cacheAnnotation = JandexHelper.getSingleAnnotation(
} configuredClass.getClassInfo(), JPADotNames.CACHEABLE
);
boolean cacheable = true; // true is the default
if ( cacheAnnotation != null && cacheAnnotation.value() != null ) {
cacheable = cacheAnnotation.value().asBoolean();
}
Caching caching = null;
switch ( meta.getSharedCacheMode() ) {
case ALL: {
caching = createCachingForCacheableAnnotation( entityBinding );
break;
} }
case ENABLE_SELECTIVE: {
CacheConcurrencyStrategy strategy = CacheConcurrencyStrategy.valueOf( if ( cacheable ) {
cacheAnnotation.value( "usage" ).asEnum() caching = createCachingForCacheableAnnotation( entityBinding );
); }
Caching caching = new Caching( region, strategy.toAccessType().getExternalName(), cacheLazyProperties ); break;
}
case DISABLE_SELECTIVE: {
if ( cacheAnnotation == null || cacheable ) {
caching = createCachingForCacheableAnnotation( entityBinding );
}
break;
}
default: {
// treat both NONE and UNSPECIFIED the same
break;
}
}
if ( caching != null ) {
entityBinding.setCaching( caching ); entityBinding.setCaching( caching );
} }
} }
private Caching createCachingForCacheableAnnotation(EntityBinding entityBinding) {
String region = entityBinding.getEntity().getName();
RegionFactory regionFactory = meta.getServiceRegistry().getService( RegionFactory.class );
AccessType defaultAccessType = regionFactory.getDefaultAccessType();
return new Caching( region, defaultAccessType, true );
}
private Schema.Name createSchemaName() { private Schema.Name createSchemaName() {
String schema = null; String schema = null;
String catalog = null; String catalog = null;

View File

@ -25,6 +25,7 @@ package org.hibernate.metamodel.source.hbm;
import org.hibernate.InvalidMappingException; import org.hibernate.InvalidMappingException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.mapping.RootClass; import org.hibernate.mapping.RootClass;
import org.hibernate.metamodel.binding.Caching; import org.hibernate.metamodel.binding.Caching;
import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.EntityBinding;
@ -286,9 +287,8 @@ class RootEntityBinder extends AbstractEntityBinder {
return; return;
} }
final String region = cache.getRegion() != null ? cache.getRegion() : entityBinding.getEntity().getName(); final String region = cache.getRegion() != null ? cache.getRegion() : entityBinding.getEntity().getName();
final String strategy = cache.getUsage(); final AccessType accessType = Enum.valueOf( AccessType.class, cache.getUsage() );
final boolean cacheLazyProps = !"non-lazy".equals( cache.getInclude() ); final boolean cacheLazyProps = !"non-lazy".equals( cache.getInclude() );
entityBinding.setCaching( new Caching( region, strategy, cacheLazyProps ) ); entityBinding.setCaching( new Caching( region, accessType, cacheLazyProps ) );
} }
} }

View File

@ -23,6 +23,8 @@
*/ */
package org.hibernate.metamodel.source.internal; package org.hibernate.metamodel.source.internal;
import javax.persistence.SharedCacheMode;
import org.hibernate.cfg.EJB3NamingStrategy; import org.hibernate.cfg.EJB3NamingStrategy;
import org.hibernate.cfg.NamingStrategy; import org.hibernate.cfg.NamingStrategy;
import org.hibernate.metamodel.Metadata; import org.hibernate.metamodel.Metadata;
@ -38,6 +40,7 @@ public class MetadataBuilderImpl implements MetadataBuilder {
private NamingStrategy namingStrategy = EJB3NamingStrategy.INSTANCE; private NamingStrategy namingStrategy = EJB3NamingStrategy.INSTANCE;
private SourceProcessingOrder sourceProcessingOrder = SourceProcessingOrder.HBM_FIRST; private SourceProcessingOrder sourceProcessingOrder = SourceProcessingOrder.HBM_FIRST;
private SharedCacheMode sharedCacheMode = SharedCacheMode.ENABLE_SELECTIVE;
public MetadataBuilderImpl(MetadataSources sources) { public MetadataBuilderImpl(MetadataSources sources) {
this.sources = sources; this.sources = sources;
@ -51,6 +54,10 @@ public class MetadataBuilderImpl implements MetadataBuilder {
return namingStrategy; return namingStrategy;
} }
public SharedCacheMode getSharedCacheMode() {
return sharedCacheMode;
}
public SourceProcessingOrder getSourceProcessingOrder() { public SourceProcessingOrder getSourceProcessingOrder() {
return sourceProcessingOrder; return sourceProcessingOrder;
} }
@ -67,6 +74,12 @@ public class MetadataBuilderImpl implements MetadataBuilder {
return this; return this;
} }
@Override
public MetadataBuilder with(SharedCacheMode sharedCacheMode) {
this.sharedCacheMode = sharedCacheMode;
return this;
}
@Override @Override
public Metadata buildMetadata() { public Metadata buildMetadata() {
return new MetadataImpl( this ); return new MetadataImpl( this );

View File

@ -30,6 +30,7 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.persistence.SharedCacheMode;
import org.jboss.jandex.Index; import org.jboss.jandex.Index;
import org.jboss.jandex.Indexer; import org.jboss.jandex.Indexer;
@ -40,13 +41,13 @@ import org.hibernate.HibernateException;
import org.hibernate.cfg.NamingStrategy; import org.hibernate.cfg.NamingStrategy;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.mapping.MetadataSource; import org.hibernate.mapping.MetadataSource;
import org.hibernate.metamodel.Metadata;
import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.SourceProcessingOrder; import org.hibernate.metamodel.SourceProcessingOrder;
import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.FetchProfile; import org.hibernate.metamodel.binding.FetchProfile;
import org.hibernate.metamodel.binding.PluralAttributeBinding; import org.hibernate.metamodel.binding.PluralAttributeBinding;
import org.hibernate.metamodel.relational.Database; import org.hibernate.metamodel.relational.Database;
import org.hibernate.metamodel.Metadata;
import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.source.annotation.xml.XMLEntityMappings; import org.hibernate.metamodel.source.annotation.xml.XMLEntityMappings;
import org.hibernate.metamodel.source.annotations.AnnotationBinder; import org.hibernate.metamodel.source.annotations.AnnotationBinder;
import org.hibernate.metamodel.source.annotations.xml.OrmXmlParser; import org.hibernate.metamodel.source.annotations.xml.OrmXmlParser;
@ -69,6 +70,7 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable
private final BasicServiceRegistry serviceRegistry; private final BasicServiceRegistry serviceRegistry;
private final NamingStrategy namingStrategy; private final NamingStrategy namingStrategy;
private final SharedCacheMode sharedCacheMode;
private final Database database = new Database(); private final Database database = new Database();
private Map<String, EntityBinding> entityBindingMap = new HashMap<String, EntityBinding>(); private Map<String, EntityBinding> entityBindingMap = new HashMap<String, EntityBinding>();
@ -81,6 +83,7 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable
this.serviceRegistry = metadataSources.getServiceRegistry(); this.serviceRegistry = metadataSources.getServiceRegistry();
this.namingStrategy = builder.getNamingStrategy(); this.namingStrategy = builder.getNamingStrategy();
this.sharedCacheMode = builder.getSharedCacheMode();
final ArrayList<String> processedEntityNames = new ArrayList<String>(); final ArrayList<String> processedEntityNames = new ArrayList<String>();
if ( builder.getSourceProcessingOrder() == SourceProcessingOrder.HBM_FIRST ) { if ( builder.getSourceProcessingOrder() == SourceProcessingOrder.HBM_FIRST ) {
@ -162,6 +165,10 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable
return namingStrategy; return namingStrategy;
} }
public SharedCacheMode getSharedCacheMode() {
return sharedCacheMode;
}
public EntityBinding getEntityBinding(String entityName) { public EntityBinding getEntityBinding(String entityName) {
return entityBindingMap.get( entityName ); return entityBindingMap.get( entityName );
} }

View File

@ -26,17 +26,18 @@ package org.hibernate.metamodel.source.annotations;
import javax.persistence.Cacheable; import javax.persistence.Cacheable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.SharedCacheMode;
import org.junit.Test; import org.junit.Test;
import org.hibernate.annotations.Cache; import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.metamodel.MetadataSources; import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.binding.Caching; import org.hibernate.metamodel.binding.Caching;
import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.source.internal.MetadataImpl; import org.hibernate.metamodel.source.internal.MetadataImpl;
import org.hibernate.service.ServiceRegistryBuilder; import org.hibernate.service.ServiceRegistryBuilder;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.testing.junit4.BaseUnitTestCase;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
@ -51,30 +52,33 @@ import static junit.framework.Assert.assertNull;
public class CacheBindingTests extends BaseUnitTestCase { public class CacheBindingTests extends BaseUnitTestCase {
@Test @Test
public void testHibernateCaching() { public void testHibernateCaching() {
EntityBinding binding = getEntityBinding( HibernateCacheEntity.class ); EntityBinding binding = getEntityBinding( HibernateCacheEntity.class, SharedCacheMode.ALL );
assertNotNull( "There should be a cache binding", binding.getCaching() ); assertNotNull( "There should be a cache binding", binding.getCaching() );
Caching caching = binding.getCaching(); Caching caching = binding.getCaching();
assertEquals( "Wrong region", "foo", caching.getRegion() ); assertEquals( "Wrong region", "foo", caching.getRegion() );
assertEquals( "Wrong strategy", "read-write", caching.getStrategy() ); assertEquals( "Wrong strategy", AccessType.READ_WRITE, caching.getAccessType() );
assertEquals( "Wrong lazy properties configuration", false, caching.isCacheLazyProperties() ); assertEquals( "Wrong lazy properties configuration", false, caching.isCacheLazyProperties() );
} }
@Test @Test
@FailureExpected( jiraKey = "HHH-6207", message = "under construction")
public void testJpaCaching() { public void testJpaCaching() {
EntityBinding binding = getEntityBinding( JpaCacheEntity.class ); EntityBinding binding = getEntityBinding( JpaCacheEntity.class, SharedCacheMode.ALL );
assertNotNull( "There should be a cache binding", binding.getCaching() ); assertNotNull( "There should be a cache binding", binding.getCaching() );
Caching caching = binding.getCaching();
assertEquals( "Wrong region", "CacheBindingTests$JpaCacheEntity", caching.getRegion() );
assertEquals( "Wrong lazy properties configuration", true, caching.isCacheLazyProperties() );
} }
@Test @Test
public void testNoCaching() { public void testNoCaching() {
EntityBinding binding = getEntityBinding( NoCacheEntity.class ); EntityBinding binding = getEntityBinding( NoCacheEntity.class, SharedCacheMode.NONE );
assertNull( "There should be no cache binding", binding.getCaching() ); assertNull( "There should be no cache binding", binding.getCaching() );
} }
private EntityBinding getEntityBinding(Class<?> clazz) { private EntityBinding getEntityBinding(Class<?> clazz, SharedCacheMode cacheMode) {
MetadataSources sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); MetadataSources sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() );
sources.addAnnotatedClass( clazz ); sources.addAnnotatedClass( clazz );
sources.getMetadataBuilder().with( cacheMode );
MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); MetadataImpl metadata = (MetadataImpl) sources.buildMetadata();
return metadata.getEntityBinding( this.getClass().getSimpleName() + "$" + clazz.getSimpleName() ); return metadata.getEntityBinding( this.getClass().getSimpleName() + "$" + clazz.getSimpleName() );