HHH-6201 Create attribute and attribute bindings for mapped super classes
This commit is contained in:
parent
546ba3c550
commit
ec482d3d0e
|
@ -36,8 +36,13 @@ import org.jboss.logging.Logger;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.metamodel.MetadataSources;
|
||||
import org.hibernate.metamodel.binding.EntityBinding;
|
||||
import org.hibernate.metamodel.domain.Hierarchical;
|
||||
import org.hibernate.metamodel.domain.NonEntity;
|
||||
import org.hibernate.metamodel.domain.Superclass;
|
||||
import org.hibernate.metamodel.source.annotation.xml.XMLEntityMappings;
|
||||
import org.hibernate.metamodel.source.annotations.entity.ConfiguredClassHierarchy;
|
||||
import org.hibernate.metamodel.source.annotations.entity.ConfiguredClassType;
|
||||
import org.hibernate.metamodel.source.annotations.entity.EntityBinder;
|
||||
import org.hibernate.metamodel.source.annotations.entity.EntityClass;
|
||||
import org.hibernate.metamodel.source.annotations.global.FetchProfileBinder;
|
||||
|
@ -56,10 +61,11 @@ import org.hibernate.service.classloading.spi.ClassLoaderService;
|
|||
|
||||
/**
|
||||
* Main class responsible to creating and binding the Hibernate meta-model from annotations.
|
||||
* This binder only has to deal with annotation index. XML configuration is already processed and pseudo annotations
|
||||
* are added to the annotation index.
|
||||
* This binder only has to deal with the (jandex) annotation index/repository. XML configuration is already processed
|
||||
* and pseudo annotations are created.
|
||||
*
|
||||
* @author Hardy Ferentschik
|
||||
* @see org.hibernate.metamodel.source.annotations.xml.OrmXmlParser
|
||||
*/
|
||||
public class AnnotationBinder implements Binder {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||
|
@ -105,6 +111,12 @@ public class AnnotationBinder implements Binder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the class w/ the specified name to the jandex index.
|
||||
*
|
||||
* @param indexer The jandex indexer
|
||||
* @param className the fully qualified class name to be indexed
|
||||
*/
|
||||
private void indexClass(Indexer indexer, String className) {
|
||||
InputStream stream = classLoaderService().locateResourceStream( className );
|
||||
try {
|
||||
|
@ -134,16 +146,33 @@ public class AnnotationBinder implements Binder {
|
|||
|
||||
@Override
|
||||
public void bindMappingMetadata(MetadataSources sources, List<String> processedEntityNames) {
|
||||
// need to order our annotated entities into an order we can process
|
||||
AnnotationBindingContext context = new AnnotationBindingContext( index, metadata.getServiceRegistry() );
|
||||
Set<ConfiguredClassHierarchy<EntityClass>> hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies( context );
|
||||
// need to order our annotated entities into an order we can process
|
||||
Set<ConfiguredClassHierarchy<EntityClass>> hierarchies = ConfiguredClassHierarchyBuilder.createEntityHierarchies(
|
||||
context
|
||||
);
|
||||
|
||||
// now we process each hierarchy one at the time
|
||||
Hierarchical parent = null;
|
||||
for ( ConfiguredClassHierarchy<EntityClass> hierarchy : hierarchies ) {
|
||||
for ( EntityClass entityClass : hierarchy ) {
|
||||
LOG.bindingEntityFromAnnotatedClass( entityClass.getName() );
|
||||
EntityBinder entityBinder = new EntityBinder( metadata, entityClass );
|
||||
entityBinder.bind();
|
||||
// for classes annotated w/ @Entity we create a EntityBinding
|
||||
if ( ConfiguredClassType.ENTITY.equals( entityClass.getConfiguredClassType() ) ) {
|
||||
LOG.bindingEntityFromAnnotatedClass( entityClass.getName() );
|
||||
EntityBinder entityBinder = new EntityBinder( metadata, entityClass, parent );
|
||||
EntityBinding binding = entityBinder.bind();
|
||||
parent = binding.getEntity();
|
||||
}
|
||||
// for classes annotated w/ @MappedSuperclass we just create the domain instance
|
||||
// the attribute bindings will be part of the first entity subclass
|
||||
else if ( ConfiguredClassType.MAPPED_SUPERCLASS.equals( entityClass.getConfiguredClassType() ) ) {
|
||||
parent = new Superclass( entityClass.getName(), parent );
|
||||
}
|
||||
// for classes which are not annotated at all we create the NonEntity domain class
|
||||
// todo - not sure whether this is needed. It might be that we don't need this information (HF)
|
||||
else {
|
||||
parent = new NonEntity( entityClass.getName(), parent );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.metamodel.source.annotations.entity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.persistence.GenerationType;
|
||||
|
@ -65,7 +66,6 @@ import org.hibernate.metamodel.relational.UniqueKey;
|
|||
import org.hibernate.metamodel.source.annotations.HibernateDotNames;
|
||||
import org.hibernate.metamodel.source.annotations.JPADotNames;
|
||||
import org.hibernate.metamodel.source.annotations.attribute.AssociationAttribute;
|
||||
import org.hibernate.metamodel.source.annotations.attribute.DiscriminatorColumnValues;
|
||||
import org.hibernate.metamodel.source.annotations.attribute.MappedAttribute;
|
||||
import org.hibernate.metamodel.source.annotations.attribute.SimpleAttribute;
|
||||
import org.hibernate.metamodel.source.annotations.attribute.state.binding.AttributeBindingStateImpl;
|
||||
|
@ -88,22 +88,20 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
public class EntityBinder {
|
||||
private final EntityClass entityClass;
|
||||
private final MetadataImplementor meta;
|
||||
private final Hierarchical superType;
|
||||
|
||||
private Schema.Name schemaName;
|
||||
|
||||
public EntityBinder(MetadataImplementor metadata, EntityClass entityClass) {
|
||||
public EntityBinder(MetadataImplementor metadata, EntityClass entityClass, Hierarchical superType) {
|
||||
this.entityClass = entityClass;
|
||||
this.meta = metadata;
|
||||
this.superType = superType;
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
public EntityBinding bind() {
|
||||
EntityBinding entityBinding = new EntityBinding();
|
||||
EntityBindingStateImpl entityBindingState = new EntityBindingStateImpl( getSuperType(), entityClass );
|
||||
EntityBindingStateImpl entityBindingState = new EntityBindingStateImpl( superType, entityClass );
|
||||
|
||||
bindJpaEntityAnnotation( entityBindingState );
|
||||
bindHibernateEntityAnnotation( entityBindingState ); // optional hibernate specific @org.hibernate.annotations.Entity
|
||||
|
||||
schemaName = createSchemaName();
|
||||
bindTable( entityBinding );
|
||||
|
||||
// bind entity level annotations
|
||||
|
@ -115,18 +113,16 @@ public class EntityBinder {
|
|||
bindCustomSQL( entityBindingState );
|
||||
bindRowId( entityBindingState );
|
||||
bindBatchSize( entityBindingState );
|
||||
|
||||
entityBinding.initialize( meta, entityBindingState );
|
||||
|
||||
bindInheritance( entityBinding );
|
||||
|
||||
|
||||
|
||||
// bind all attributes - simple as well as associations
|
||||
bindAttributes( entityBinding );
|
||||
bindEmbeddedAttributes( entityBinding );
|
||||
// take care of the id, attributes and relations
|
||||
if ( entityClass.isRoot() ) {
|
||||
|
||||
// take care of the id, attributes and relations
|
||||
if ( entityClass.isEntityRoot() ) {
|
||||
bindId( entityBinding );
|
||||
}
|
||||
|
||||
|
@ -134,6 +130,7 @@ public class EntityBinder {
|
|||
|
||||
// last, but not least we initialize and register the new EntityBinding
|
||||
meta.addEntity( entityBinding );
|
||||
return entityBinding;
|
||||
}
|
||||
|
||||
private void bindTableUniqueConstraints(EntityBinding entityBinding) {
|
||||
|
@ -199,12 +196,7 @@ public class EntityBinder {
|
|||
entityClass.getClassInfo()
|
||||
);
|
||||
SimpleAttribute discriminatorAttribute = SimpleAttribute.createDiscriminatorAttribute( typeAnnotations );
|
||||
|
||||
bindSingleMappedAttribute( entityBinding, entityBinding.getEntity(), discriminatorAttribute );
|
||||
|
||||
if ( !( discriminatorAttribute.getColumnValues() instanceof DiscriminatorColumnValues ) ) {
|
||||
throw new AssertionFailure( "Expected discriminator column values" );
|
||||
}
|
||||
}
|
||||
|
||||
private void bindWhereFilter(EntityBindingStateImpl entityBindingState) {
|
||||
|
@ -426,7 +418,7 @@ public class EntityBinder {
|
|||
}
|
||||
|
||||
private void bindTable(EntityBinding entityBinding) {
|
||||
final Schema schema = meta.getDatabase().getSchema( schemaName );
|
||||
final Schema schema = meta.getDatabase().getSchema( createSchemaName() );
|
||||
final Identifier tableName = Identifier.toIdentifier( entityClass.getPrimaryTableName() );
|
||||
org.hibernate.metamodel.relational.Table table = schema.getTable( tableName );
|
||||
if ( table == null ) {
|
||||
|
@ -476,40 +468,9 @@ public class EntityBinder {
|
|||
entityBindingState.setJpaEntityName( name );
|
||||
}
|
||||
|
||||
private void bindEmbeddedIdAnnotation(EntityBinding entityBinding) {
|
||||
AnnotationInstance idAnnotation = JandexHelper.getSingleAnnotation(
|
||||
entityClass.getClassInfo(), JPADotNames.EMBEDDED_ID
|
||||
);
|
||||
|
||||
String idName = JandexHelper.getPropertyName( idAnnotation.target() );
|
||||
MappedAttribute idAttribute = entityClass.getMappedAttribute( idName );
|
||||
if ( !( idAttribute instanceof SimpleAttribute ) ) {
|
||||
throw new AssertionFailure( "Unexpected attribute type for id attribute" );
|
||||
}
|
||||
|
||||
SingularAttribute attribute = entityBinding.getEntity().getOrCreateComponentAttribute( idName );
|
||||
|
||||
|
||||
SimpleAttributeBinding attributeBinding = entityBinding.makeSimpleIdAttributeBinding( attribute );
|
||||
|
||||
attributeBinding.initialize( new AttributeBindingStateImpl( (SimpleAttribute) idAttribute ) );
|
||||
|
||||
TupleRelationalStateImpl state = new TupleRelationalStateImpl();
|
||||
EmbeddableClass embeddableClass = entityClass.getEmbeddedClasses().get( idName );
|
||||
for ( MappedAttribute attr : embeddableClass.getMappedAttributes() ) {
|
||||
state.addValueState( new ColumnRelationalStateImpl( (SimpleAttribute) attr, meta ) );
|
||||
}
|
||||
attributeBinding.initialize( state );
|
||||
Map<String,String> parms = new HashMap<String, String>( 1 );
|
||||
parms.put( IdentifierGenerator.ENTITY_NAME, entityBinding.getEntity().getName() );
|
||||
IdGenerator generator = new IdGenerator( "NAME","assigned", parms);
|
||||
entityBinding.getEntityIdentifier().setIdGenerator( generator );
|
||||
// entityBinding.getEntityIdentifier().createIdentifierGenerator( meta.getIdentifierGeneratorFactory() );
|
||||
}
|
||||
|
||||
private void bindSingleIdAnnotation(EntityBinding entityBinding) {
|
||||
private void bindEmbeddedIdAnnotation(EntityBinding entityBinding) {
|
||||
AnnotationInstance idAnnotation = JandexHelper.getSingleAnnotation(
|
||||
entityClass.getClassInfo(), JPADotNames.ID
|
||||
entityClass.getClassInfo(), JPADotNames.EMBEDDED_ID
|
||||
);
|
||||
|
||||
String idName = JandexHelper.getPropertyName( idAnnotation.target() );
|
||||
|
@ -518,13 +479,59 @@ public class EntityBinder {
|
|||
throw new AssertionFailure( "Unexpected attribute type for id attribute" );
|
||||
}
|
||||
|
||||
Attribute attribute = entityBinding.getEntity().getOrCreateSingularAttribute( idName );
|
||||
SingularAttribute attribute = entityBinding.getEntity().getOrCreateComponentAttribute( idName );
|
||||
|
||||
|
||||
SimpleAttributeBinding attributeBinding = entityBinding.makeSimpleIdAttributeBinding( attribute );
|
||||
|
||||
attributeBinding.initialize( new AttributeBindingStateImpl( (SimpleAttribute) idAttribute ) );
|
||||
|
||||
TupleRelationalStateImpl state = new TupleRelationalStateImpl();
|
||||
EmbeddableClass embeddableClass = entityClass.getEmbeddedClasses().get( idName );
|
||||
for ( SimpleAttribute attr : embeddableClass.getSimpleAttributes() ) {
|
||||
state.addValueState( new ColumnRelationalStateImpl( attr, meta ) );
|
||||
}
|
||||
attributeBinding.initialize( state );
|
||||
Map<String, String> parms = new HashMap<String, String>( 1 );
|
||||
parms.put( IdentifierGenerator.ENTITY_NAME, entityBinding.getEntity().getName() );
|
||||
IdGenerator generator = new IdGenerator( "NAME", "assigned", parms );
|
||||
entityBinding.getEntityIdentifier().setIdGenerator( generator );
|
||||
// entityBinding.getEntityIdentifier().createIdentifierGenerator( meta.getIdentifierGeneratorFactory() );
|
||||
}
|
||||
|
||||
private void bindSingleIdAnnotation(EntityBinding entityBinding) {
|
||||
// we know we are dealing w/ a single @Id, but potentially it is defined in a mapped super class
|
||||
ConfiguredClass configuredClass = entityClass;
|
||||
EntityClass superEntity = entityClass.getEntityParent();
|
||||
Hierarchical container = entityBinding.getEntity();
|
||||
Iterator<SimpleAttribute> iter = null;
|
||||
while ( configuredClass != null && configuredClass != superEntity ) {
|
||||
iter = configuredClass.getIdAttributes().iterator();
|
||||
if ( iter.hasNext() ) {
|
||||
break;
|
||||
}
|
||||
configuredClass = configuredClass.getParent();
|
||||
container = container.getSuperType();
|
||||
}
|
||||
|
||||
// if we could not find the attribute our assumptions were wrong
|
||||
if ( iter == null || !iter.hasNext() ) {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
"Unable to find id attribute for class %s",
|
||||
entityClass.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// now that we have the id attribute we can create the attribute and binding
|
||||
MappedAttribute idAttribute = iter.next();
|
||||
Attribute attribute = container.getOrCreateSingularAttribute( idAttribute.getName() );
|
||||
|
||||
SimpleAttributeBinding attributeBinding = entityBinding.makeSimpleIdAttributeBinding( attribute );
|
||||
attributeBinding.initialize( new AttributeBindingStateImpl( (SimpleAttribute) idAttribute ) );
|
||||
attributeBinding.initialize( new ColumnRelationalStateImpl( (SimpleAttribute) idAttribute, meta ) );
|
||||
bindSingleIdGeneratedValue( entityBinding, idName );
|
||||
|
||||
bindSingleIdGeneratedValue( entityBinding, idAttribute.getName() );
|
||||
}
|
||||
|
||||
private void bindSingleIdGeneratedValue(EntityBinding entityBinding, String idPropertyName) {
|
||||
|
@ -552,7 +559,7 @@ public class EntityBinder {
|
|||
if ( idGenerator == null ) {
|
||||
throw new MappingException(
|
||||
String.format(
|
||||
"@GeneratedValue on %s.%s refering an undefined generator [%s]",
|
||||
"@GeneratedValue on %s.%s referring an undefined generator [%s]",
|
||||
entityClass.getName(),
|
||||
idName,
|
||||
generator
|
||||
|
@ -580,7 +587,7 @@ public class EntityBinder {
|
|||
)
|
||||
);
|
||||
}
|
||||
if( idGenerator == null ) {
|
||||
if ( idGenerator == null ) {
|
||||
idGenerator = new IdGenerator( "NAME", strategy, new HashMap<String, String>() );
|
||||
entityBinding.getEntityIdentifier().setIdGenerator( idGenerator );
|
||||
}
|
||||
|
@ -588,44 +595,74 @@ public class EntityBinder {
|
|||
}
|
||||
|
||||
private void bindAttributes(EntityBinding entityBinding) {
|
||||
for ( MappedAttribute mappedAttribute : entityClass.getMappedAttributes() ) {
|
||||
if ( mappedAttribute instanceof AssociationAttribute ) {
|
||||
bindAssociationAttribute(
|
||||
entityBinding,
|
||||
entityBinding.getEntity(),
|
||||
(AssociationAttribute) mappedAttribute
|
||||
);
|
||||
}
|
||||
else {
|
||||
bindSingleMappedAttribute(
|
||||
entityBinding,
|
||||
entityBinding.getEntity(),
|
||||
(SimpleAttribute) mappedAttribute
|
||||
);
|
||||
}
|
||||
// bind the attributes of this entity
|
||||
AttributeContainer entity = entityBinding.getEntity();
|
||||
bindAttributes( entityBinding, entity, entityClass );
|
||||
|
||||
// bind potential mapped super class attributes
|
||||
ConfiguredClass parent = entityClass.getParent();
|
||||
Hierarchical superTypeContainer = entityBinding.getEntity().getSuperType();
|
||||
while ( containsPotentialMappedSuperclassAttributes( parent ) ) {
|
||||
bindAttributes( entityBinding, superTypeContainer, parent );
|
||||
parent = parent.getParent();
|
||||
superTypeContainer = superTypeContainer.getSuperType();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsPotentialMappedSuperclassAttributes(ConfiguredClass parent) {
|
||||
return parent != null && ( ConfiguredClassType.MAPPED_SUPERCLASS.equals( parent.getConfiguredClassType() ) ||
|
||||
ConfiguredClassType.NON_ENTITY.equals( parent.getConfiguredClassType() ) );
|
||||
}
|
||||
|
||||
private void bindAttributes(EntityBinding entityBinding, AttributeContainer attributeContainer, ConfiguredClass configuredClass) {
|
||||
for ( SimpleAttribute simpleAttribute : configuredClass.getSimpleAttributes() ) {
|
||||
bindSingleMappedAttribute(
|
||||
entityBinding,
|
||||
attributeContainer,
|
||||
simpleAttribute
|
||||
);
|
||||
}
|
||||
for ( AssociationAttribute associationAttribute : configuredClass.getAssociationAttributes() ) {
|
||||
bindAssociationAttribute(
|
||||
entityBinding,
|
||||
attributeContainer,
|
||||
associationAttribute
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindEmbeddedAttributes(EntityBinding entityBinding) {
|
||||
for ( Map.Entry<String, EmbeddableClass> entry : entityClass.getEmbeddedClasses().entrySet() ) {
|
||||
AttributeContainer entity = entityBinding.getEntity();
|
||||
bindEmbeddedAttributes( entityBinding, entity, entityClass );
|
||||
|
||||
// bind potential mapped super class embeddables
|
||||
ConfiguredClass parent = entityClass.getParent();
|
||||
Hierarchical superTypeContainer = entityBinding.getEntity().getSuperType();
|
||||
while ( containsPotentialMappedSuperclassAttributes( parent ) ) {
|
||||
bindEmbeddedAttributes( entityBinding, superTypeContainer, parent );
|
||||
parent = parent.getParent();
|
||||
superTypeContainer = superTypeContainer.getSuperType();
|
||||
}
|
||||
}
|
||||
|
||||
private void bindEmbeddedAttributes(EntityBinding entityBinding, AttributeContainer attributeContainer, ConfiguredClass configuredClass) {
|
||||
for ( Map.Entry<String, EmbeddableClass> entry : configuredClass.getEmbeddedClasses().entrySet() ) {
|
||||
String attributeName = entry.getKey();
|
||||
EmbeddableClass embeddedClass = entry.getValue();
|
||||
SingularAttribute component = entityBinding.getEntity().getOrCreateComponentAttribute( attributeName );
|
||||
for ( MappedAttribute mappedAttribute : embeddedClass.getMappedAttributes() ) {
|
||||
if ( mappedAttribute instanceof AssociationAttribute ) {
|
||||
bindAssociationAttribute(
|
||||
entityBinding,
|
||||
component.getAttributeContainer(),
|
||||
(AssociationAttribute) mappedAttribute
|
||||
);
|
||||
}
|
||||
else {
|
||||
bindSingleMappedAttribute(
|
||||
entityBinding,
|
||||
component.getAttributeContainer(),
|
||||
(SimpleAttribute) mappedAttribute
|
||||
);
|
||||
}
|
||||
SingularAttribute component = attributeContainer.getOrCreateComponentAttribute( attributeName );
|
||||
for ( SimpleAttribute simpleAttribute : embeddedClass.getSimpleAttributes() ) {
|
||||
bindSingleMappedAttribute(
|
||||
entityBinding,
|
||||
component.getAttributeContainer(),
|
||||
simpleAttribute
|
||||
);
|
||||
}
|
||||
for ( AssociationAttribute associationAttribute : embeddedClass.getAssociationAttributes() ) {
|
||||
bindAssociationAttribute(
|
||||
entityBinding,
|
||||
component.getAttributeContainer(),
|
||||
associationAttribute
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -754,21 +791,5 @@ public class EntityBinder {
|
|||
entityBindingState.setExplicitPolymorphism( PolymorphismType.EXPLICIT.equals( polymorphism ) );
|
||||
entityBindingState.setOptimisticLock( optimisticLock );
|
||||
}
|
||||
|
||||
private Hierarchical getSuperType() {
|
||||
ConfiguredClass parent = entityClass.getParent();
|
||||
if ( parent == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
EntityBinding parentBinding = meta.getEntityBinding( parent.getName() );
|
||||
if ( parentBinding == null ) {
|
||||
throw new AssertionFailure(
|
||||
"Parent entity " + parent.getName() + " of entity " + entityClass.getName() + " not yet created!"
|
||||
);
|
||||
}
|
||||
|
||||
return parentBinding.getEntity();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,12 +23,14 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.source.annotations.entity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.AccessType;
|
||||
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
import org.jboss.jandex.AnnotationValue;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.MappingException;
|
||||
|
@ -38,18 +40,17 @@ import org.hibernate.metamodel.source.annotations.JPADotNames;
|
|||
import org.hibernate.metamodel.source.annotations.util.JandexHelper;
|
||||
|
||||
/**
|
||||
* Represents an entity, mapped superclass or component configured via annotations/xml.
|
||||
* Represents an entity or mapped superclass configured via annotations/xml.
|
||||
*
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class EntityClass extends ConfiguredClass {
|
||||
private final AccessType hierarchyAccessType;
|
||||
|
||||
private final InheritanceType inheritanceType;
|
||||
private final boolean hasOwnTable;
|
||||
private final String primaryTableName;
|
||||
|
||||
private final IdType idType;
|
||||
private final EntityClass jpaEntityParent;
|
||||
|
||||
public EntityClass(ClassInfo classInfo,
|
||||
EntityClass parent,
|
||||
|
@ -61,11 +62,27 @@ public class EntityClass extends ConfiguredClass {
|
|||
this.hierarchyAccessType = hierarchyAccessType;
|
||||
this.inheritanceType = inheritanceType;
|
||||
this.idType = determineIdType();
|
||||
|
||||
this.jpaEntityParent = findJpaEntitySuperClass();
|
||||
this.hasOwnTable = definesItsOwnTable();
|
||||
this.primaryTableName = determinePrimaryTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the next JPA super entity for this entity class or {@code null} in case there is none.
|
||||
*/
|
||||
public EntityClass getEntityParent() {
|
||||
return jpaEntityParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns {@code true} is this entity class is the root of the class hierarchy in the JPA sense, which
|
||||
* means there are no more super classes which are annotated with @Entity. There can, however, be mapped superclasses
|
||||
* or non entities in the actual java type hierarchy.
|
||||
*/
|
||||
public boolean isEntityRoot() {
|
||||
return jpaEntityParent == null;
|
||||
}
|
||||
|
||||
public InheritanceType getInheritanceType() {
|
||||
return inheritanceType;
|
||||
}
|
||||
|
@ -86,7 +103,7 @@ public class EntityClass extends ConfiguredClass {
|
|||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( "EntityClass" );
|
||||
sb.append( "{name=" ).append( getName() );
|
||||
sb.append( "{name=" ).append( getConfiguredClass().getSimpleName() );
|
||||
sb.append( ", hierarchyAccessType=" ).append( hierarchyAccessType );
|
||||
sb.append( ", inheritanceType=" ).append( inheritanceType );
|
||||
sb.append( ", hasOwnTable=" ).append( hasOwnTable );
|
||||
|
@ -97,18 +114,33 @@ public class EntityClass extends ConfiguredClass {
|
|||
}
|
||||
|
||||
private boolean definesItsOwnTable() {
|
||||
// mapped super classes and embeddables don't have their own tables
|
||||
if ( ConfiguredClassType.MAPPED_SUPERCLASS.equals( getConfiguredClassType() ) || ConfiguredClassType.EMBEDDABLE
|
||||
.equals( getConfiguredClassType() ) ) {
|
||||
// mapped super classes don't have their own tables
|
||||
if ( ConfiguredClassType.MAPPED_SUPERCLASS.equals( getConfiguredClassType() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( InheritanceType.SINGLE_TABLE.equals( inheritanceType ) ) {
|
||||
return isRoot();
|
||||
if ( isEntityRoot() ) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private EntityClass findJpaEntitySuperClass() {
|
||||
ConfiguredClass tmpConfiguredClass = this.getParent();
|
||||
while ( tmpConfiguredClass != null ) {
|
||||
if ( ConfiguredClassType.ENTITY.equals( tmpConfiguredClass.getConfiguredClassType() ) ) {
|
||||
return (EntityClass) tmpConfiguredClass;
|
||||
}
|
||||
tmpConfiguredClass = tmpConfiguredClass.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String determinePrimaryTableName() {
|
||||
String tableName = null;
|
||||
if ( hasOwnTable() ) {
|
||||
|
@ -125,26 +157,23 @@ public class EntityClass extends ConfiguredClass {
|
|||
}
|
||||
}
|
||||
else if ( getParent() != null
|
||||
&& !getParent().getConfiguredClassType().equals( ConfiguredClassType.MAPPED_SUPERCLASS )
|
||||
&& !getParent().getConfiguredClassType().equals( ConfiguredClassType.EMBEDDABLE ) ) {
|
||||
&& !getParent().getConfiguredClassType().equals( ConfiguredClassType.MAPPED_SUPERCLASS ) ) {
|
||||
tableName = ( (EntityClass) getParent() ).getPrimaryTableName();
|
||||
}
|
||||
return tableName;
|
||||
}
|
||||
|
||||
private IdType determineIdType() {
|
||||
List<AnnotationInstance> idAnnotations = getClassInfo().annotations().get( JPADotNames.ID );
|
||||
List<AnnotationInstance> embeddedIdAnnotations = getClassInfo()
|
||||
.annotations()
|
||||
.get( JPADotNames.EMBEDDED_ID );
|
||||
List<AnnotationInstance> idAnnotations = findIdAnnotations( JPADotNames.ID );
|
||||
List<AnnotationInstance> embeddedIdAnnotations = findIdAnnotations( JPADotNames.EMBEDDED_ID );
|
||||
|
||||
if ( idAnnotations != null && embeddedIdAnnotations != null ) {
|
||||
if ( !idAnnotations.isEmpty() && !embeddedIdAnnotations.isEmpty() ) {
|
||||
throw new MappingException(
|
||||
"@EmbeddedId and @Id cannot be used together. Check the configuration for " + getName() + "."
|
||||
);
|
||||
}
|
||||
|
||||
if ( embeddedIdAnnotations != null ) {
|
||||
if ( !embeddedIdAnnotations.isEmpty() ) {
|
||||
if ( embeddedIdAnnotations.size() == 1 ) {
|
||||
return IdType.EMBEDDED;
|
||||
}
|
||||
|
@ -153,7 +182,7 @@ public class EntityClass extends ConfiguredClass {
|
|||
}
|
||||
}
|
||||
|
||||
if ( idAnnotations != null ) {
|
||||
if ( !idAnnotations.isEmpty() ) {
|
||||
if ( idAnnotations.size() == 1 ) {
|
||||
return IdType.SIMPLE;
|
||||
}
|
||||
|
@ -163,4 +192,21 @@ public class EntityClass extends ConfiguredClass {
|
|||
}
|
||||
return IdType.NONE;
|
||||
}
|
||||
|
||||
private List<AnnotationInstance> findIdAnnotations(DotName idAnnotationType) {
|
||||
List<AnnotationInstance> idAnnotationList = new ArrayList<AnnotationInstance>();
|
||||
if ( getClassInfo().annotations().get( idAnnotationType ) != null ) {
|
||||
idAnnotationList.addAll( getClassInfo().annotations().get( idAnnotationType ) );
|
||||
}
|
||||
ConfiguredClass parent = getParent();
|
||||
while ( parent != null && ( ConfiguredClassType.MAPPED_SUPERCLASS.equals( parent.getConfiguredClassType() ) ||
|
||||
ConfiguredClassType.NON_ENTITY.equals( parent.getConfiguredClassType() ) ) ) {
|
||||
if ( parent.getClassInfo().annotations().get( idAnnotationType ) != null ) {
|
||||
idAnnotationList.addAll( parent.getClassInfo().annotations().get( idAnnotationType ) );
|
||||
}
|
||||
parent = parent.getParent();
|
||||
|
||||
}
|
||||
return idAnnotationList;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,11 +78,11 @@ public class EntityBindingStateImpl implements EntityBindingState {
|
|||
|
||||
private Set<String> synchronizedTableNames;
|
||||
|
||||
public EntityBindingStateImpl(Hierarchical superType, EntityClass configuredClass) {
|
||||
this.className = configuredClass.getName();
|
||||
public EntityBindingStateImpl(Hierarchical superType, EntityClass entityClass) {
|
||||
this.className = entityClass.getName();
|
||||
this.superType = superType;
|
||||
this.isRoot = configuredClass.isRoot();
|
||||
this.inheritanceType = configuredClass.getInheritanceType();
|
||||
this.isRoot = entityClass.isEntityRoot();
|
||||
this.inheritanceType = entityClass.getInheritanceType();
|
||||
this.synchronizedTableNames = new HashSet<String>();
|
||||
this.batchSize = -1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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.entity;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.action.internal.EntityIdentityInsertAction;
|
||||
import org.hibernate.metamodel.binding.AttributeBinding;
|
||||
import org.hibernate.metamodel.binding.EntityBinding;
|
||||
import org.hibernate.metamodel.binding.EntityIdentifier;
|
||||
import org.hibernate.metamodel.domain.NonEntity;
|
||||
import org.hibernate.metamodel.domain.Superclass;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@code j.p.AttributeOverrides} and {@code j.p.AttributeOverride}.
|
||||
*
|
||||
* @author Hardy Ferentschik
|
||||
*/
|
||||
public class MappedSuperclassWithAttributeOverrideTests extends BaseAnnotationBindingTestCase {
|
||||
@Test
|
||||
public void testMappedSuperclass() {
|
||||
buildMetadataSources( MyMappedSuperClass.class, MyEntity.class );
|
||||
EntityBinding binding = getEntityBinding( MyEntity.class );
|
||||
assertEquals( "Wrong entity name", MyEntity.class.getName(), binding.getEntity().getName() );
|
||||
assertEquals(
|
||||
"Wrong entity name",
|
||||
MyMappedSuperClass.class.getName(),
|
||||
binding.getEntity().getSuperType().getName()
|
||||
);
|
||||
assertTrue( binding.getEntity().getSuperType() instanceof Superclass );
|
||||
AttributeBinding nameBinding = binding.getAttributeBinding( "name" );
|
||||
assertNotNull( "the name attribute should be bound to the subclass", nameBinding );
|
||||
|
||||
AttributeBinding idBinding = binding.getEntityIdentifier().getValueBinding();
|
||||
assertNotNull( "the id attribute should be bound", idBinding );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoEntity() {
|
||||
buildMetadataSources( SubclassOfNoEntity.class, NoEntity.class );
|
||||
EntityBinding binding = getEntityBinding( SubclassOfNoEntity.class );
|
||||
assertEquals( "Wrong entity name", SubclassOfNoEntity.class.getName(), binding.getEntity().getName() );
|
||||
assertEquals( "Wrong entity name", NoEntity.class.getName(), binding.getEntity().getSuperType().getName() );
|
||||
assertTrue( binding.getEntity().getSuperType() instanceof NonEntity );
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
class MyMappedSuperClass {
|
||||
@Id
|
||||
private int id;
|
||||
String name;
|
||||
int age;
|
||||
}
|
||||
|
||||
@Entity
|
||||
class MyEntity extends MyMappedSuperClass {
|
||||
private Long count;
|
||||
}
|
||||
|
||||
class NoEntity {
|
||||
String name;
|
||||
int age;
|
||||
}
|
||||
|
||||
@Entity
|
||||
class SubclassOfNoEntity extends NoEntity {
|
||||
@Id
|
||||
private int id;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ public class GenericTypeDiscoveryTest extends BaseAnnotationIndexTestCase {
|
|||
info = configuredClass.getClassInfo();
|
||||
assertEquals( "wrong class", DotName.createSimple( PricedStuff.class.getName() ), info.name() );
|
||||
assertFalse(
|
||||
"PricedStuff should not mapped properties", configuredClass.getMappedAttributes().iterator().hasNext()
|
||||
"PricedStuff should not mapped properties", configuredClass.getSimpleAttributes().iterator().hasNext()
|
||||
);
|
||||
|
||||
assertTrue( iter.hasNext() );
|
||||
|
@ -88,7 +88,7 @@ public class GenericTypeDiscoveryTest extends BaseAnnotationIndexTestCase {
|
|||
configuredClass = iter.next();
|
||||
info = configuredClass.getClassInfo();
|
||||
assertEquals( "wrong class", DotName.createSimple( Paper.class.getName() ), info.name() );
|
||||
assertFalse( "Paper should not mapped properties", configuredClass.getMappedAttributes().iterator().hasNext() );
|
||||
assertFalse( "Paper should not mapped properties", configuredClass.getSimpleAttributes().iterator().hasNext() );
|
||||
|
||||
assertFalse( iter.hasNext() );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue