From ff312720ce016bbc790dea86539dbb97f09fedc0 Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Wed, 29 Jun 2011 18:00:32 +0200 Subject: [PATCH] HHH-6173 allow embeddable classes to use inheritance as well --- .../source/annotations/AnnotationBinder.java | 7 +- .../annotations/AnnotationBindingContext.java | 8 + .../annotations/entity/ConfiguredClass.java | 32 +- .../entity/ConfiguredClassHierarchy.java | 84 +++-- ...mbeddedClass.java => EmbeddableClass.java} | 15 +- .../annotations/entity/EntityBinder.java | 4 +- .../annotations/entity/EntityClass.java | 28 +- .../source/annotations/package-info.java | 2 +- .../util/ConfiguredClassHierarchyBuilder.java | 79 ++++- .../annotations/entity/TableNameTest.java | 16 +- .../util/BaseAnnotationIndexTestCase.java | 75 ++++ ...Test.java => EmbeddableHierarchyTest.java} | 124 +++---- .../annotations/util/EntityHierarchyTest.java | 327 ++++++++++++++++++ .../util/GenericTypeDiscoveryTest.java | 35 +- .../annotations/util/TypeDiscoveryTest.java | 27 +- 15 files changed, 656 insertions(+), 207 deletions(-) rename hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/{EmbeddedClass.java => EmbeddableClass.java} (77%) create mode 100644 hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/BaseAnnotationIndexTestCase.java rename hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/{ConfiguredClassHierarchyBuilderTest.java => EmbeddableHierarchyTest.java} (66%) create mode 100644 hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/EntityHierarchyTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java index 6f74cddc41..ab7a2b55a7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java @@ -135,12 +135,11 @@ public class AnnotationBinder implements Binder { @Override public void bindMappingMetadata(MetadataSources sources, List processedEntityNames) { // need to order our annotated entities into an order we can process - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, metadata.getServiceRegistry() - ); + AnnotationBindingContext context = new AnnotationBindingContext( index, metadata.getServiceRegistry() ); + Set> hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( context ); // now we process each hierarchy one at the time - for ( ConfiguredClassHierarchy hierarchy : hierarchies ) { + for ( ConfiguredClassHierarchy hierarchy : hierarchies ) { for ( EntityClass entityClass : hierarchy ) { LOG.bindingEntityFromAnnotatedClass( entityClass.getName() ); EntityBinder entityBinder = new EntityBinder( metadata, entityClass ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBindingContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBindingContext.java index 94b4b54d7d..075e3117c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBindingContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBindingContext.java @@ -58,6 +58,10 @@ public class AnnotationBindingContext { this.resolvedTypeCache = new HashMap, ResolvedType>(); } + public Index getIndex() { + return index; + } + public ClassLoaderService classLoaderService() { if ( classLoaderService == null ) { classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); @@ -70,6 +74,10 @@ public class AnnotationBindingContext { return index.getClassByName( dotName ); } + public Class loadClass(String className) { + return classLoaderService.classForName( className ); + } + public void resolveAllTypes(String className) { // the resolved type for the top level class in the hierarchy Class clazz = classLoaderService().classForName( className ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/ConfiguredClass.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/ConfiguredClass.java index 36eeb69c6c..0048175a11 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/ConfiguredClass.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/ConfiguredClass.java @@ -57,6 +57,7 @@ import org.hibernate.metamodel.source.annotations.attribute.AssociationAttribute import org.hibernate.metamodel.source.annotations.attribute.AttributeType; import org.hibernate.metamodel.source.annotations.attribute.MappedAttribute; import org.hibernate.metamodel.source.annotations.attribute.SimpleAttribute; +import org.hibernate.metamodel.source.annotations.util.ConfiguredClassHierarchyBuilder; import org.hibernate.metamodel.source.annotations.util.JandexHelper; import org.hibernate.metamodel.source.annotations.util.ReflectionHelper; @@ -66,6 +67,12 @@ import org.hibernate.metamodel.source.annotations.util.ReflectionHelper; * @author Hardy Ferentschik */ public class ConfiguredClass { + + /** + * The parent of this configured class or {@code null} in case this configured class is the root of a hierarchy. + */ + private final ConfiguredClass parent; + /** * The Jandex class info for this configured class. Provides access to the annotation defined on this configured class. */ @@ -104,7 +111,7 @@ public class ConfiguredClass { /** * The embedded classes for this entity */ - private final Map embeddedClasses = new HashMap(); + private final Map embeddedClasses = new HashMap(); private final Set transientFieldNames = new HashSet(); private final Set transientMethodNames = new HashSet(); @@ -113,7 +120,9 @@ public class ConfiguredClass { public ConfiguredClass(ClassInfo classInfo, AccessType defaultAccessType, + ConfiguredClass parent, AnnotationBindingContext context) { + this.parent = parent; this.context = context; this.classInfo = classInfo; this.clazz = context.classLoaderService().classForName( classInfo.toString() ); @@ -148,6 +157,14 @@ public class ConfiguredClass { return classInfo; } + public ConfiguredClass getParent() { + return parent; + } + + public boolean isRoot() { + return parent == null; + } + public ConfiguredClassType getConfiguredClassType() { return configuredClassType; } @@ -156,7 +173,7 @@ public class ConfiguredClass { return mappedAttributes.values(); } - public Map getEmbeddedClasses() { + public Map getEmbeddedClasses() { return embeddedClasses; } @@ -172,8 +189,6 @@ public class ConfiguredClass { sb.append( ", classAccessType=" ).append( classAccessType ); sb.append( ", configuredClassType=" ).append( configuredClassType ); sb.append( ", mappedAttributes=" ).append( mappedAttributes ); - sb.append( ", transientFieldNames=" ).append( transientFieldNames ); - sb.append( ", transientMethodNames=" ).append( transientMethodNames ); sb.append( '}' ); return sb.toString(); } @@ -391,15 +406,12 @@ public class ConfiguredClass { } context.resolveAllTypes( type.getName() ); - EmbeddedClass embeddedClass = new EmbeddedClass( - embeddableClassInfo, + ConfiguredClassHierarchy hierarchy = ConfiguredClassHierarchyBuilder.createEmbeddableHierarchy( + context.loadClass( embeddableClassInfo.toString() ), classAccessType, - attributeOverrides, - associationOverrides, context ); - - embeddedClasses.put( attributeName, embeddedClass ); + embeddedClasses.put( attributeName, hierarchy.getLeaf() ); } // TODO handle the different association types default: { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/ConfiguredClassHierarchy.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/ConfiguredClassHierarchy.java index a298eed5e5..c74923e4c2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/ConfiguredClassHierarchy.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/ConfiguredClassHierarchy.java @@ -44,30 +44,56 @@ import org.hibernate.metamodel.source.annotations.util.JandexHelper; * * @author Hardy Ferentschik */ -public class ConfiguredClassHierarchy implements Iterable { +public class ConfiguredClassHierarchy implements Iterable { private final AccessType defaultAccessType; private final InheritanceType inheritanceType; - private final List entityClasses; + private final List configuredClasses; - public static ConfiguredClassHierarchy create(List classes, AnnotationBindingContext context) { - return new ConfiguredClassHierarchy( classes, context ); + public static ConfiguredClassHierarchy createEntityClassHierarchy(List classInfoList, AnnotationBindingContext context) { + AccessType defaultAccessType = determineDefaultAccessType( classInfoList ); + InheritanceType inheritanceType = determineInheritanceType( classInfoList ); + return new ConfiguredClassHierarchy( + classInfoList, + context, + defaultAccessType, + inheritanceType, + EntityClass.class + ); } - private ConfiguredClassHierarchy(List classInfoList, AnnotationBindingContext context) { - defaultAccessType = determineDefaultAccessType( classInfoList ); - inheritanceType = determineInheritanceType( classInfoList ); + public static ConfiguredClassHierarchy createEmbeddableClassHierarchy(List classes, AccessType accessType, AnnotationBindingContext context) { + return new ConfiguredClassHierarchy( + classes, + context, + accessType, + InheritanceType.NO_INHERITANCE, + EmbeddableClass.class + ); + } + + private ConfiguredClassHierarchy(List classInfoList, AnnotationBindingContext context, AccessType defaultAccessType, InheritanceType inheritanceType, Class configuredClassType) { + this.defaultAccessType = defaultAccessType; + this.inheritanceType = inheritanceType; // the resolved type for the top level class in the hierarchy context.resolveAllTypes( classInfoList.get( classInfoList.size() - 1 ).name().toString() ); - entityClasses = new ArrayList(); - EntityClass parent = null; + configuredClasses = new ArrayList(); + T parent = null; for ( ClassInfo info : classInfoList ) { - EntityClass entityClass = new EntityClass( - info, parent, defaultAccessType, inheritanceType, context - ); - entityClasses.add( entityClass ); - parent = entityClass; + T configuredClass; + if ( EntityClass.class.equals( configuredClassType ) ) { + configuredClass = (T) new EntityClass( + info, (EntityClass) parent, defaultAccessType, inheritanceType, context + ); + } + else { + configuredClass = (T) new EmbeddableClass( + info, (EmbeddableClass) parent, defaultAccessType, context + ); + } + configuredClasses.add( configuredClass ); + parent = configuredClass; } } @@ -82,8 +108,22 @@ public class ConfiguredClassHierarchy implements Iterable { /** * @return An iterator iterating in top down manner over the configured classes in this hierarchy. */ - public Iterator iterator() { - return entityClasses.iterator(); + public Iterator iterator() { + return configuredClasses.iterator(); + } + + /** + * @return Returns the top level configured class + */ + public T getRoot() { + return configuredClasses.get( 0 ); + } + + /** + * @return Returns the leaf configured class + */ + public T getLeaf() { + return configuredClasses.get( configuredClasses.size() - 1 ); } @Override @@ -91,7 +131,7 @@ public class ConfiguredClassHierarchy implements Iterable { final StringBuilder sb = new StringBuilder(); sb.append( "ConfiguredClassHierarchy" ); sb.append( "{defaultAccessType=" ).append( defaultAccessType ); - sb.append( ", configuredClasses=" ).append( entityClasses ); + sb.append( ", configuredClasses=" ).append( configuredClasses ); sb.append( '}' ); return sb.toString(); } @@ -103,7 +143,7 @@ public class ConfiguredClassHierarchy implements Iterable { * {@code AccessType} annotations. The default access type is determined by the placement of the * annotations. */ - private AccessType determineDefaultAccessType(List classes) { + private static AccessType determineDefaultAccessType(List classes) { AccessType accessType = null; for ( ClassInfo info : classes ) { List idAnnotations = info.annotations().get( JPADotNames.ID ); @@ -120,7 +160,7 @@ public class ConfiguredClassHierarchy implements Iterable { return accessType; } - private AccessType determineAccessTypeByIdPlacement(List idAnnotations) { + private static AccessType determineAccessTypeByIdPlacement(List idAnnotations) { AccessType accessType = null; for ( AnnotationInstance annotation : idAnnotations ) { AccessType tmpAccessType; @@ -146,7 +186,7 @@ public class ConfiguredClassHierarchy implements Iterable { return accessType; } - private InheritanceType determineInheritanceType(List classes) { + private static InheritanceType determineInheritanceType(List classes) { if ( classes.size() == 1 ) { return InheritanceType.NO_INHERITANCE; } @@ -190,14 +230,14 @@ public class ConfiguredClassHierarchy implements Iterable { return inheritanceType; } - private AccessType throwIdNotFoundAnnotationException(List classes) { + private static AccessType throwIdNotFoundAnnotationException(List classes) { StringBuilder builder = new StringBuilder(); builder.append( "Unable to determine identifier attribute for class hierarchy consisting of the classe(s) " ); builder.append( hierarchyListString( classes ) ); throw new AnnotationException( builder.toString() ); } - private String hierarchyListString(List classes) { + private static String hierarchyListString(List classes) { StringBuilder builder = new StringBuilder(); builder.append( "[" ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EmbeddedClass.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EmbeddableClass.java similarity index 77% rename from hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EmbeddedClass.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EmbeddableClass.java index 7197ebfb7e..285ca1cd9a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EmbeddedClass.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EmbeddableClass.java @@ -23,10 +23,8 @@ */ package org.hibernate.metamodel.source.annotations.entity; -import java.util.List; import javax.persistence.AccessType; -import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.ClassInfo; import org.hibernate.metamodel.source.annotations.AnnotationBindingContext; @@ -34,14 +32,13 @@ import org.hibernate.metamodel.source.annotations.AnnotationBindingContext; /** * @author Hardy Ferentschik */ -public class EmbeddedClass extends ConfiguredClass { +public class EmbeddableClass extends ConfiguredClass { // todo - need to take care of the attribute path (HF) - public EmbeddedClass(ClassInfo classInfo, - AccessType defaultAccessType, - List attributeOverrides, - List associationOverrides, - AnnotationBindingContext context) { - super( classInfo, defaultAccessType, context ); + public EmbeddableClass(ClassInfo classInfo, + EmbeddableClass parent, + AccessType defaultAccessType, + AnnotationBindingContext context) { + super( classInfo, defaultAccessType, parent, context ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityBinder.java index ec5d9b372f..4939030913 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityBinder.java @@ -574,9 +574,9 @@ public class EntityBinder { } private void bindEmbeddedAttributes(EntityBinding entityBinding) { - for ( Map.Entry entry : entityClass.getEmbeddedClasses().entrySet() ) { + for ( Map.Entry entry : entityClass.getEmbeddedClasses().entrySet() ) { String attributeName = entry.getKey(); - EmbeddedClass embeddedClass = entry.getValue(); + EmbeddableClass embeddedClass = entry.getValue(); SingularAttribute component = entityBinding.getEntity().getOrCreateComponentAttribute( attributeName ); for ( MappedAttribute mappedAttribute : embeddedClass.getMappedAttributes() ) { if ( mappedAttribute instanceof AssociationAttribute ) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityClass.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityClass.java index 5e4ce9f502..c400aa0670 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityClass.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityClass.java @@ -26,7 +26,6 @@ package org.hibernate.metamodel.source.annotations.entity; import java.util.List; import javax.persistence.AccessType; -import com.fasterxml.classmate.ResolvedTypeWithMembers; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.ClassInfo; @@ -44,12 +43,6 @@ import org.hibernate.metamodel.source.annotations.util.JandexHelper; * @author Hardy Ferentschik */ public class EntityClass extends ConfiguredClass { - /** - * The parent of this configured class or {@code null} in case this configured class is the root of a hierarchy. - */ - private final EntityClass parent; - - private final boolean isRoot; private final AccessType hierarchyAccessType; private final InheritanceType inheritanceType; @@ -64,9 +57,7 @@ public class EntityClass extends ConfiguredClass { InheritanceType inheritanceType, AnnotationBindingContext context) { - super( classInfo, hierarchyAccessType, context ); - this.parent = parent; - this.isRoot = parent == null; + super( classInfo, hierarchyAccessType, parent, context ); this.hierarchyAccessType = hierarchyAccessType; this.inheritanceType = inheritanceType; this.idType = determineIdType(); @@ -75,14 +66,6 @@ public class EntityClass extends ConfiguredClass { this.primaryTableName = determinePrimaryTableName(); } - public EntityClass getParent() { - return parent; - } - - public boolean isRoot() { - return isRoot; - } - public InheritanceType getInheritanceType() { return inheritanceType; } @@ -104,7 +87,6 @@ public class EntityClass extends ConfiguredClass { final StringBuilder sb = new StringBuilder(); sb.append( "EntityClass" ); sb.append( "{name=" ).append( getName() ); - sb.append( ", isRoot=" ).append( isRoot ); sb.append( ", hierarchyAccessType=" ).append( hierarchyAccessType ); sb.append( ", inheritanceType=" ).append( inheritanceType ); sb.append( ", hasOwnTable=" ).append( hasOwnTable ); @@ -142,10 +124,10 @@ public class EntityClass extends ConfiguredClass { } } } - else if ( parent != null - && !parent.getConfiguredClassType().equals( ConfiguredClassType.MAPPED_SUPERCLASS ) - && !parent.getConfiguredClassType().equals( ConfiguredClassType.EMBEDDABLE ) ) { - tableName = parent.getPrimaryTableName(); + else if ( getParent() != null + && !getParent().getConfiguredClassType().equals( ConfiguredClassType.MAPPED_SUPERCLASS ) + && !getParent().getConfiguredClassType().equals( ConfiguredClassType.EMBEDDABLE ) ) { + tableName = ( (EntityClass) getParent() ).getPrimaryTableName(); } return tableName; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/package-info.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/package-info.java index b8cb2f04a7..9f27fce7c2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/package-info.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/package-info.java @@ -24,5 +24,5 @@ package org.hibernate.metamodel.source.annotations; /** - * This package contains the binding code for binding annotation based configuration to the Hibernate metamodel. + * This package and its sub-packages contains the binding code for binding annotation based configuration to the Hibernate metamodel. */ \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilder.java index 1533b21c14..25009c117d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilder.java @@ -30,51 +30,55 @@ import java.util.List; import java.util.Map; import java.util.Set; +import javax.persistence.AccessType; + import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; -import org.jboss.jandex.Index; import org.hibernate.AnnotationException; +import org.hibernate.AssertionFailure; import org.hibernate.metamodel.source.annotations.AnnotationBindingContext; import org.hibernate.metamodel.source.annotations.JPADotNames; import org.hibernate.metamodel.source.annotations.entity.ConfiguredClassHierarchy; -import org.hibernate.service.ServiceRegistry; +import org.hibernate.metamodel.source.annotations.entity.EmbeddableClass; +import org.hibernate.metamodel.source.annotations.entity.EntityClass; import org.hibernate.service.classloading.spi.ClassLoaderService; /** - * Given a annotation index build a set of class hierarchies. + * Given a (jandex) annotation index build processes all classes with JPA relevant annotations and pre-orders + * JPA entities respectively their inheritance hierarchy. * * @author Hardy Ferentschik */ public class ConfiguredClassHierarchyBuilder { /** - * This methods pre-processes the annotated entities from the index and put them into a structure which can + * Pre-processes the annotated entities from the index and put them into a structure which can * bound to the Hibernate metamodel. * - * @param index The annotation index - * @param serviceRegistry The service registry + * @param context the annotation binding context with access to the service registry and the annotation index * * @return a set of {@code ConfiguredClassHierarchy}s. One for each "leaf" entity. */ - public static Set createEntityHierarchies(Index index, ServiceRegistry serviceRegistry) { - ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); + public static Set> createEntityHierarchies(AnnotationBindingContext context) { + ClassLoaderService classLoaderService = context.classLoaderService(); Map> processedClassInfos = new HashMap>(); - for ( ClassInfo info : index.getKnownClasses() ) { - if ( !isConfiguredClass( info ) ) { + for ( ClassInfo info : context.getIndex().getKnownClasses() ) { + if ( !isEntityClass( info ) ) { continue; } if ( processedClassInfos.containsKey( info ) ) { continue; } + List configuredClassList = new ArrayList(); ClassInfo tmpClassInfo = info; Class clazz = classLoaderService.classForName( tmpClassInfo.toString() ); while ( clazz != null && !clazz.equals( Object.class ) ) { - tmpClassInfo = index.getClassByName( DotName.createSimple( clazz.getName() ) ); + tmpClassInfo = context.getIndex().getClassByName( DotName.createSimple( clazz.getName() ) ); clazz = clazz.getSuperclass(); if ( tmpClassInfo == null ) { continue; @@ -95,12 +99,11 @@ public class ConfiguredClassHierarchyBuilder { } } - AnnotationBindingContext context = new AnnotationBindingContext( index, serviceRegistry ); - Set hierarchies = new HashSet(); + Set> hierarchies = new HashSet>(); List> processedList = new ArrayList>(); for ( List classInfoList : processedClassInfos.values() ) { if ( !processedList.contains( classInfoList ) ) { - hierarchies.add( ConfiguredClassHierarchy.create( classInfoList, context ) ); + hierarchies.add( ConfiguredClassHierarchy.createEntityClassHierarchy( classInfoList, context ) ); processedList.add( classInfoList ); } } @@ -108,6 +111,52 @@ public class ConfiguredClassHierarchyBuilder { return hierarchies; } + /** + * Builds the configured class hierarchy for a an embeddable class. + * + * @param embeddableClass the top level embedded class + * @param accessType the access type inherited from the class in which the embeddable gets embedded + * @param context the annotation binding context with access to the service registry and the annotation index + * + * @return a set of {@code ConfiguredClassHierarchy}s. One for each "leaf" entity. + */ + public static ConfiguredClassHierarchy createEmbeddableHierarchy(Class embeddableClass, AccessType accessType, AnnotationBindingContext context) { + + ClassInfo embeddableClassInfo = context.getClassInfo( embeddableClass.getName() ); + if ( embeddableClassInfo == null ) { + throw new AssertionFailure( + String.format( + "The specified class %s cannot be found in the annotation index", + embeddableClass.getName() + ) + ); + } + + if ( JandexHelper.getSingleAnnotation( embeddableClassInfo, JPADotNames.EMBEDDABLE ) == null ) { + throw new AssertionFailure( + String.format( + "The specified class %s is not annotated with @Embeddable", + embeddableClass.getName() + ) + ); + } + + List classInfoList = new ArrayList(); + ClassInfo tmpClassInfo; + Class clazz = embeddableClass; + while ( clazz != null && !clazz.equals( Object.class ) ) { + tmpClassInfo = context.getIndex().getClassByName( DotName.createSimple( clazz.getName() ) ); + clazz = clazz.getSuperclass(); + if ( tmpClassInfo == null ) { + continue; + } + + classInfoList.add( 0, tmpClassInfo ); + } + + return ConfiguredClassHierarchy.createEmbeddableClassHierarchy( classInfoList, accessType, context ); + } + /** * Checks whether the passed jandex class info needs to be processed. * @@ -115,7 +164,7 @@ public class ConfiguredClassHierarchyBuilder { * * @return {@code true} if the class represented by {@code info} is relevant for the JPA mappings, {@code false} otherwise. */ - private static boolean isConfiguredClass(ClassInfo info) { + private static boolean isEntityClass(ClassInfo info) { boolean isConfiguredClass = true; AnnotationInstance jpaEntityAnnotation = JandexHelper.getSingleAnnotation( info, JPADotNames.ENTITY ); AnnotationInstance mappedSuperClassAnnotation = JandexHelper.getSingleAnnotation( diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/TableNameTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/TableNameTest.java index d0193b5f9f..5e3cbc326f 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/TableNameTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/TableNameTest.java @@ -40,6 +40,7 @@ import org.junit.Before; import org.junit.Test; import org.hibernate.metamodel.binding.InheritanceType; +import org.hibernate.metamodel.source.annotations.AnnotationBindingContext; import org.hibernate.metamodel.source.annotations.util.ConfiguredClassHierarchyBuilder; import org.hibernate.metamodel.source.annotations.util.JandexHelper; import org.hibernate.service.ServiceRegistryBuilder; @@ -84,8 +85,9 @@ public class TableNameTest extends BaseUnitTestCase { } Index index = JandexHelper.indexForClass( service, A.class, B.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry + AnnotationBindingContext context = new AnnotationBindingContext( index, serviceRegistry ); + Set> hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( + context ); assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); @@ -131,8 +133,9 @@ public class TableNameTest extends BaseUnitTestCase { } Index index = JandexHelper.indexForClass( service, A.class, B.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry + AnnotationBindingContext context = new AnnotationBindingContext( index, serviceRegistry ); + Set> hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( + context ); assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); @@ -179,8 +182,9 @@ public class TableNameTest extends BaseUnitTestCase { } Index index = JandexHelper.indexForClass( service, B.class, A.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry + AnnotationBindingContext context = new AnnotationBindingContext( index, serviceRegistry ); + Set> hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( + context ); assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/BaseAnnotationIndexTestCase.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/BaseAnnotationIndexTestCase.java new file mode 100644 index 0000000000..ef2e8ef198 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/BaseAnnotationIndexTestCase.java @@ -0,0 +1,75 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.metamodel.source.annotations.util; + +import java.util.Set; + +import javax.persistence.AccessType; + +import org.jboss.jandex.Index; +import org.junit.After; +import org.junit.Before; + +import org.hibernate.metamodel.source.annotations.AnnotationBindingContext; +import org.hibernate.metamodel.source.annotations.entity.ConfiguredClassHierarchy; +import org.hibernate.metamodel.source.annotations.entity.EmbeddableClass; +import org.hibernate.metamodel.source.annotations.entity.EntityClass; +import org.hibernate.service.ServiceRegistryBuilder; +import org.hibernate.service.classloading.spi.ClassLoaderService; +import org.hibernate.service.internal.BasicServiceRegistryImpl; +import org.hibernate.testing.junit4.BaseUnitTestCase; + +/** + * @author Hardy Ferentschik + */ +public abstract class BaseAnnotationIndexTestCase extends BaseUnitTestCase { + private BasicServiceRegistryImpl serviceRegistry; + + @Before + public void setUp() { + serviceRegistry = (BasicServiceRegistryImpl) new ServiceRegistryBuilder().buildServiceRegistry(); + } + + @After + public void tearDown() { + serviceRegistry.destroy(); + } + + public Set> createEntityHierarchies(Class... clazz) { + Index index = JandexHelper.indexForClass( serviceRegistry.getService( ClassLoaderService.class ), clazz ); + AnnotationBindingContext context = new AnnotationBindingContext( index, serviceRegistry ); + return ConfiguredClassHierarchyBuilder.createEntityHierarchies( context ); + } + + public ConfiguredClassHierarchy createEmbeddableHierarchy(AccessType accessType, Class... configuredClasses) { + Index index = JandexHelper.indexForClass( + serviceRegistry.getService( ClassLoaderService.class ), + configuredClasses + ); + AnnotationBindingContext context = new AnnotationBindingContext( index, serviceRegistry ); + return ConfiguredClassHierarchyBuilder.createEmbeddableHierarchy( configuredClasses[0], accessType, context ); + } +} + + diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilderTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/EmbeddableHierarchyTest.java similarity index 66% rename from hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilderTest.java rename to hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/EmbeddableHierarchyTest.java index 0daf55c328..8c42527516 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/ConfiguredClassHierarchyBuilderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/EmbeddableHierarchyTest.java @@ -35,49 +35,28 @@ import javax.persistence.MappedSuperclass; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; -import org.jboss.jandex.Index; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.hibernate.AnnotationException; +import org.hibernate.AssertionFailure; import org.hibernate.metamodel.binding.InheritanceType; import org.hibernate.metamodel.source.annotations.entity.ConfiguredClassHierarchy; +import org.hibernate.metamodel.source.annotations.entity.EmbeddableClass; import org.hibernate.metamodel.source.annotations.entity.EntityClass; -import org.hibernate.service.ServiceRegistryBuilder; -import org.hibernate.service.classloading.spi.ClassLoaderService; -import org.hibernate.service.internal.BasicServiceRegistryImpl; -import org.hibernate.testing.junit4.BaseUnitTestCase; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertFalse; /** * @author Hardy Ferentschik */ -public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { - - private BasicServiceRegistryImpl serviceRegistry; - private ClassLoaderService classLoaderService; - - @Before - public void setUp() { - serviceRegistry = (BasicServiceRegistryImpl) new ServiceRegistryBuilder().buildServiceRegistry(); - classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); - } - - @After - public void tearDown() { - serviceRegistry.destroy(); - } +public class EmbeddableHierarchyTest extends BaseAnnotationIndexTestCase { @Test public void testSingleEntity() { - Index index = JandexHelper.indexForClass( classLoaderService, Foo.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry - ); + Set> hierarchies = createEntityHierarchies( Foo.class ); assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); Iterator iter = hierarchies.iterator().next().iterator(); @@ -88,10 +67,7 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { @Test public void testSimpleInheritance() { - Index index = JandexHelper.indexForClass( classLoaderService, B.class, A.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry - ); + Set> hierarchies = createEntityHierarchies( B.class, A.class ); assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); Iterator iter = hierarchies.iterator().next().iterator(); @@ -104,10 +80,7 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { @Test public void testMultipleHierarchies() { - Index index = JandexHelper.indexForClass( classLoaderService, B.class, A.class, Foo.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry - ); + Set> hierarchies = createEntityHierarchies( B.class, Foo.class, A.class ); assertEquals( "There should be only one hierarchy", 2, hierarchies.size() ); } @@ -129,11 +102,10 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { private String mappedProperty; } - Index index = JandexHelper.indexForClass( - classLoaderService, MappedSubClass.class, MappedSuperClass.class, UnmappedSubClass.class - ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry + Set> hierarchies = createEntityHierarchies( + MappedSubClass.class, + MappedSuperClass.class, + UnmappedSubClass.class ); assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); @@ -154,8 +126,7 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { class EntityAndMappedSuperClass { } - Index index = JandexHelper.indexForClass( classLoaderService, EntityAndMappedSuperClass.class ); - ConfiguredClassHierarchyBuilder.createEntityHierarchies( index, serviceRegistry ); + createEntityHierarchies( EntityAndMappedSuperClass.class ); } @Test(expected = AnnotationException.class) @@ -165,8 +136,7 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { class EntityAndEmbeddable { } - Index index = JandexHelper.indexForClass( classLoaderService, EntityAndEmbeddable.class ); - ConfiguredClassHierarchyBuilder.createEntityHierarchies( index, serviceRegistry ); + createEntityHierarchies( EntityAndEmbeddable.class ); } @Test(expected = AnnotationException.class) @@ -181,8 +151,7 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { class B extends A { } - Index index = JandexHelper.indexForClass( classLoaderService, B.class, A.class ); - ConfiguredClassHierarchyBuilder.createEntityHierarchies( index, serviceRegistry ); + createEntityHierarchies( B.class, A.class ); } @Test @@ -197,10 +166,7 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { class B extends A { } - Index index = JandexHelper.indexForClass( classLoaderService, B.class, A.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry - ); + Set> hierarchies = createEntityHierarchies( B.class, A.class ); assertTrue( hierarchies.size() == 1 ); ConfiguredClassHierarchy hierarchy = hierarchies.iterator().next(); assertEquals( "Wrong default access type", AccessType.FIELD, hierarchy.getDefaultAccessType() ); @@ -226,10 +192,7 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { class B extends A { } - Index index = JandexHelper.indexForClass( classLoaderService, B.class, A.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry - ); + Set> hierarchies = createEntityHierarchies( B.class, A.class ); assertTrue( hierarchies.size() == 1 ); ConfiguredClassHierarchy hierarchy = hierarchies.iterator().next(); assertEquals( "Wrong default access type", AccessType.PROPERTY, hierarchy.getDefaultAccessType() ); @@ -247,10 +210,7 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { class B extends A { } - Index index = JandexHelper.indexForClass( classLoaderService, B.class, A.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry - ); + Set> hierarchies = createEntityHierarchies( B.class, A.class ); assertTrue( hierarchies.size() == 1 ); ConfiguredClassHierarchy hierarchy = hierarchies.iterator().next(); assertEquals( "Wrong inheritance type", InheritanceType.SINGLE_TABLE, hierarchy.getInheritanceType() ); @@ -275,9 +235,10 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { class B extends A { } - Index index = JandexHelper.indexForClass( classLoaderService, B.class, MappedSuperClass.class, A.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry + Set> hierarchies = createEntityHierarchies( + B.class, + MappedSuperClass.class, + A.class ); assertTrue( hierarchies.size() == 1 ); ConfiguredClassHierarchy hierarchy = hierarchies.iterator().next(); @@ -300,8 +261,47 @@ public class ConfiguredClassHierarchyBuilderTest extends BaseUnitTestCase { class B extends A { } - Index index = JandexHelper.indexForClass( classLoaderService, B.class, A.class ); - ConfiguredClassHierarchyBuilder.createEntityHierarchies( index, serviceRegistry ); + createEntityHierarchies( B.class, A.class ); + } + + @Test + public void testEmbeddableHierarchy() { + @Embeddable + class A { + String foo; + } + + class B extends A { + } + + @Embeddable + class C extends B { + String bar; + } + + ConfiguredClassHierarchy hierarchy = createEmbeddableHierarchy( + AccessType.FIELD, + C.class, + A.class, + B.class + ); + Iterator iter = hierarchy.iterator(); + ClassInfo info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( A.class.getName() ), info.name() ); + info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( B.class.getName() ), info.name() ); + info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( C.class.getName() ), info.name() ); + assertFalse( iter.hasNext() ); + assertNotNull( hierarchy ); + } + + @Test(expected = AssertionFailure.class) + public void testEmbeddableHierarchyWithNotAnnotatedEntity() { + class NonAnnotatedEmbeddable { + } + + createEmbeddableHierarchy( AccessType.FIELD, NonAnnotatedEmbeddable.class ); } @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/EntityHierarchyTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/EntityHierarchyTest.java new file mode 100644 index 0000000000..02db05a1b5 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/EntityHierarchyTest.java @@ -0,0 +1,327 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.metamodel.source.annotations.util; + +import java.util.Iterator; +import java.util.Set; +import javax.persistence.AccessType; +import javax.persistence.Embeddable; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.MappedSuperclass; + +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.DotName; +import org.junit.Test; + +import org.hibernate.AnnotationException; +import org.hibernate.AssertionFailure; +import org.hibernate.metamodel.binding.InheritanceType; +import org.hibernate.metamodel.source.annotations.entity.ConfiguredClassHierarchy; +import org.hibernate.metamodel.source.annotations.entity.EmbeddableClass; +import org.hibernate.metamodel.source.annotations.entity.EntityClass; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +/** + * @author Hardy Ferentschik + */ +public class EntityHierarchyTest extends BaseAnnotationIndexTestCase { + + @Test + public void testSingleEntity() { + Set> hierarchies = createEntityHierarchies( Foo.class ); + assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); + + Iterator iter = hierarchies.iterator().next().iterator(); + ClassInfo info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( Foo.class.getName() ), info.name() ); + assertFalse( iter.hasNext() ); + } + + @Test + public void testSimpleInheritance() { + Set> hierarchies = createEntityHierarchies( B.class, A.class ); + assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); + + Iterator iter = hierarchies.iterator().next().iterator(); + ClassInfo info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( A.class.getName() ), info.name() ); + info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( B.class.getName() ), info.name() ); + assertFalse( iter.hasNext() ); + } + + @Test + public void testMultipleHierarchies() { + Set> hierarchies = createEntityHierarchies( B.class, Foo.class, A.class ); + assertEquals( "There should be only one hierarchy", 2, hierarchies.size() ); + } + + @Test + public void testMappedSuperClass() { + @MappedSuperclass + class MappedSuperClass { + @Id + @GeneratedValue + private int id; + } + + class UnmappedSubClass extends MappedSuperClass { + private String unmappedProperty; + } + + @Entity + class MappedSubClass extends UnmappedSubClass { + private String mappedProperty; + } + + Set> hierarchies = createEntityHierarchies( + MappedSubClass.class, + MappedSuperClass.class, + UnmappedSubClass.class + ); + assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); + + Iterator iter = hierarchies.iterator().next().iterator(); + ClassInfo info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( MappedSuperClass.class.getName() ), info.name() ); + info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( UnmappedSubClass.class.getName() ), info.name() ); + info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( MappedSubClass.class.getName() ), info.name() ); + assertFalse( iter.hasNext() ); + } + + @Test(expected = AnnotationException.class) + public void testEntityAndMappedSuperClassAnnotations() { + @Entity + @MappedSuperclass + class EntityAndMappedSuperClass { + } + + createEntityHierarchies( EntityAndMappedSuperClass.class ); + } + + @Test(expected = AnnotationException.class) + public void testEntityAndEmbeddableAnnotations() { + @Entity + @Embeddable + class EntityAndEmbeddable { + } + + createEntityHierarchies( EntityAndEmbeddable.class ); + } + + @Test(expected = AnnotationException.class) + public void testNoIdAnnotation() { + + @Entity + class A { + String id; + } + + @Entity + class B extends A { + } + + createEntityHierarchies( B.class, A.class ); + } + + @Test + public void testDefaultFieldAccess() { + @Entity + class A { + @Id + String id; + } + + @Entity + class B extends A { + } + + Set> hierarchies = createEntityHierarchies( B.class, A.class ); + assertTrue( hierarchies.size() == 1 ); + ConfiguredClassHierarchy hierarchy = hierarchies.iterator().next(); + assertEquals( "Wrong default access type", AccessType.FIELD, hierarchy.getDefaultAccessType() ); + } + + @Test + public void testDefaultPropertyAccess() { + @Entity + class A { + String id; + + @Id + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + } + + @Entity + class B extends A { + } + + Set> hierarchies = createEntityHierarchies( B.class, A.class ); + assertTrue( hierarchies.size() == 1 ); + ConfiguredClassHierarchy hierarchy = hierarchies.iterator().next(); + assertEquals( "Wrong default access type", AccessType.PROPERTY, hierarchy.getDefaultAccessType() ); + } + + @Test + public void testDefaultInheritanceStrategy() { + @Entity + class A { + @Id + String id; + } + + @Entity + class B extends A { + } + + Set> hierarchies = createEntityHierarchies( B.class, A.class ); + assertTrue( hierarchies.size() == 1 ); + ConfiguredClassHierarchy hierarchy = hierarchies.iterator().next(); + assertEquals( "Wrong inheritance type", InheritanceType.SINGLE_TABLE, hierarchy.getInheritanceType() ); + } + + + @Test + public void testExplicitInheritanceStrategy() { + @MappedSuperclass + class MappedSuperClass { + + } + + @Entity + @Inheritance(strategy = javax.persistence.InheritanceType.JOINED) + class A extends MappedSuperClass { + @Id + String id; + } + + @Entity + class B extends A { + } + + Set> hierarchies = createEntityHierarchies( + B.class, + MappedSuperClass.class, + A.class + ); + assertTrue( hierarchies.size() == 1 ); + ConfiguredClassHierarchy hierarchy = hierarchies.iterator().next(); + assertEquals( + "Wrong inheritance type", InheritanceType.JOINED, hierarchy.getInheritanceType() + ); + } + + @Test(expected = AnnotationException.class) + public void testMultipleConflictingInheritanceDefinitions() { + + @Entity + @Inheritance(strategy = javax.persistence.InheritanceType.JOINED) + class A { + String id; + } + + @Entity + @Inheritance(strategy = javax.persistence.InheritanceType.TABLE_PER_CLASS) + class B extends A { + } + + createEntityHierarchies( B.class, A.class ); + } + + @Test + public void testEmbeddableHierarchy() { + @Embeddable + class A { + String foo; + } + + class B extends A { + } + + @Embeddable + class C extends B { + String bar; + } + + ConfiguredClassHierarchy hierarchy = createEmbeddableHierarchy( + AccessType.FIELD, + C.class, + A.class, + B.class + ); + Iterator iter = hierarchy.iterator(); + ClassInfo info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( A.class.getName() ), info.name() ); + info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( B.class.getName() ), info.name() ); + info = iter.next().getClassInfo(); + assertEquals( "wrong class", DotName.createSimple( C.class.getName() ), info.name() ); + assertFalse( iter.hasNext() ); + assertNotNull( hierarchy ); + } + + @Test(expected = AssertionFailure.class) + public void testEmbeddableHierarchyWithNotAnnotatedEntity() { + class NonAnnotatedEmbeddable { + } + + createEmbeddableHierarchy( AccessType.FIELD, NonAnnotatedEmbeddable.class ); + } + + @Entity + public class Foo { + @Id + @GeneratedValue + private int id; + } + + @Entity + public class A { + @Id + @GeneratedValue + private int id; + } + + @Entity + public class B extends A { + private String name; + } +} + + diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/GenericTypeDiscoveryTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/GenericTypeDiscoveryTest.java index 4b05f50136..25136a7e8c 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/GenericTypeDiscoveryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/GenericTypeDiscoveryTest.java @@ -33,19 +33,12 @@ import javax.persistence.MappedSuperclass; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; -import org.jboss.jandex.Index; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.hibernate.metamodel.source.annotations.attribute.MappedAttribute; import org.hibernate.metamodel.source.annotations.entity.ConfiguredClass; import org.hibernate.metamodel.source.annotations.entity.ConfiguredClassHierarchy; import org.hibernate.metamodel.source.annotations.entity.EntityClass; -import org.hibernate.service.ServiceRegistryBuilder; -import org.hibernate.service.classloading.spi.ClassLoaderService; -import org.hibernate.service.internal.BasicServiceRegistryImpl; -import org.hibernate.testing.junit4.BaseUnitTestCase; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -54,26 +47,15 @@ import static junit.framework.Assert.assertTrue; /** * @author Hardy Ferentschik */ -public class GenericTypeDiscoveryTest extends BaseUnitTestCase { - private BasicServiceRegistryImpl serviceRegistry; - private ClassLoaderService service; - - @Before - public void setUp() { - serviceRegistry = (BasicServiceRegistryImpl) new ServiceRegistryBuilder().buildServiceRegistry(); - service = serviceRegistry.getService( ClassLoaderService.class ); - } - - @After - public void tearDown() { - serviceRegistry.destroy(); - } +public class GenericTypeDiscoveryTest extends BaseAnnotationIndexTestCase { @Test public void testGenericClassHierarchy() { - Index index = JandexHelper.indexForClass( service, Paper.class, Stuff.class, Item.class, PricedStuff.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry + Set> hierarchies = createEntityHierarchies( + Paper.class, + Stuff.class, + Item.class, + PricedStuff.class ); assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); @@ -113,10 +95,7 @@ public class GenericTypeDiscoveryTest extends BaseUnitTestCase { @Test public void testUnresolvedType() { - Index index = JandexHelper.indexForClass( service, UnresolvedType.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry - ); + Set> hierarchies = createEntityHierarchies( UnresolvedType.class ); assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/TypeDiscoveryTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/TypeDiscoveryTest.java index c3393a849c..a6fdc8267b 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/TypeDiscoveryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/TypeDiscoveryTest.java @@ -28,9 +28,6 @@ import java.util.Map; import java.util.Set; import javax.persistence.Id; -import org.jboss.jandex.Index; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.hibernate.annotations.Parameter; @@ -39,37 +36,17 @@ import org.hibernate.metamodel.source.annotations.attribute.MappedAttribute; import org.hibernate.metamodel.source.annotations.entity.ConfiguredClass; import org.hibernate.metamodel.source.annotations.entity.ConfiguredClassHierarchy; import org.hibernate.metamodel.source.annotations.entity.EntityClass; -import org.hibernate.service.ServiceRegistryBuilder; -import org.hibernate.service.classloading.spi.ClassLoaderService; -import org.hibernate.service.internal.BasicServiceRegistryImpl; -import org.hibernate.testing.junit4.BaseUnitTestCase; import static junit.framework.Assert.assertEquals; /** * @author Hardy Ferentschik */ -public class TypeDiscoveryTest extends BaseUnitTestCase { - private BasicServiceRegistryImpl serviceRegistry; - private ClassLoaderService service; - - @Before - public void setUp() { - serviceRegistry = (BasicServiceRegistryImpl) new ServiceRegistryBuilder().buildServiceRegistry(); - service = serviceRegistry.getService( ClassLoaderService.class ); - } - - @After - public void tearDown() { - serviceRegistry.destroy(); - } +public class TypeDiscoveryTest extends BaseAnnotationIndexTestCase { @Test public void testImplicitAndExplicitType() { - Index index = JandexHelper.indexForClass( service, Entity.class ); - Set hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( - index, serviceRegistry - ); + Set> hierarchies = createEntityHierarchies( Entity.class ); assertEquals( "There should be only one hierarchy", 1, hierarchies.size() ); Iterator iter = hierarchies.iterator().next().iterator();