diff --git a/hibernate-core/src/main/java/org/hibernate/internal/jaxb/mapping/hbm/PluralAttributeElement.java b/hibernate-core/src/main/java/org/hibernate/internal/jaxb/mapping/hbm/PluralAttributeElement.java index adf766fbe0..c6f05dfe64 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/jaxb/mapping/hbm/PluralAttributeElement.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/jaxb/mapping/hbm/PluralAttributeElement.java @@ -30,7 +30,7 @@ import java.util.List; * * @author Steve Ebersole */ -public interface PluralAttributeElement extends MetaAttributeContainer { +public interface PluralAttributeElement extends TableInformationSource, MetaAttributeContainer { public String getName(); public String getAccess(); @@ -42,13 +42,8 @@ public interface PluralAttributeElement extends MetaAttributeContainer { public JaxbManyToManyElement getManyToMany(); public JaxbManyToAnyElement getManyToAny(); - public String getSchema(); - public String getCatalog(); - public String getTable(); public String getComment(); public String getCheck(); - public String getSubselect(); - public String getSubselectAttribute(); public String getWhere(); public JaxbLoaderElement getLoader(); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/jaxb/mapping/hbm/TableInformationSource.java b/hibernate-core/src/main/java/org/hibernate/internal/jaxb/mapping/hbm/TableInformationSource.java new file mode 100644 index 0000000000..82a628381a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/jaxb/mapping/hbm/TableInformationSource.java @@ -0,0 +1,35 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.internal.jaxb.mapping.hbm; + +/** + * @author Steve Ebersole + */ +public interface TableInformationSource { + public String getSchema(); + public String getCatalog(); + public String getTable(); + public String getSubselect(); + public String getSubselectAttribute(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java index dd5b1db444..541b27edea 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java @@ -69,6 +69,7 @@ import org.hibernate.metamodel.spi.relational.Column; import org.hibernate.metamodel.spi.relational.DerivedValue; import org.hibernate.metamodel.spi.relational.ForeignKey; import org.hibernate.metamodel.spi.relational.Identifier; +import org.hibernate.metamodel.spi.relational.InLineView; import org.hibernate.metamodel.spi.relational.Schema; import org.hibernate.metamodel.spi.relational.Table; import org.hibernate.metamodel.spi.relational.TableSpecification; @@ -85,6 +86,7 @@ import org.hibernate.metamodel.spi.source.DerivedValueSource; import org.hibernate.metamodel.spi.source.DiscriminatorSource; import org.hibernate.metamodel.spi.source.EntityHierarchy; import org.hibernate.metamodel.spi.source.EntitySource; +import org.hibernate.metamodel.spi.source.InLineViewSource; import org.hibernate.metamodel.spi.source.LocalBindingContext; import org.hibernate.metamodel.spi.source.MappingException; import org.hibernate.metamodel.spi.source.MetaAttributeContext; @@ -97,6 +99,7 @@ import org.hibernate.metamodel.spi.source.PluralAttributeSource; import org.hibernate.metamodel.spi.source.RelationalValueSource; import org.hibernate.metamodel.spi.source.RelationalValueSourceContainer; import org.hibernate.metamodel.spi.source.RootEntitySource; +import org.hibernate.metamodel.spi.source.SecondaryTableSource; import org.hibernate.metamodel.spi.source.SimpleIdentifierSource; import org.hibernate.metamodel.spi.source.SingularAttributeNature; import org.hibernate.metamodel.spi.source.SingularAttributeSource; @@ -104,6 +107,7 @@ import org.hibernate.metamodel.spi.source.Sortable; import org.hibernate.metamodel.spi.source.SubclassEntityContainer; import org.hibernate.metamodel.spi.source.SubclassEntitySource; import org.hibernate.metamodel.spi.source.TableSource; +import org.hibernate.metamodel.spi.source.TableSpecificationSource; import org.hibernate.metamodel.spi.source.ToOneAttributeSource; import org.hibernate.metamodel.spi.source.UniqueConstraintSource; import org.hibernate.metamodel.spi.source.VersionAttributeSource; @@ -974,51 +978,37 @@ public class Binder { // } private void bindCollectionTable( - PluralAttributeSource attributeSource, - AbstractPluralAttributeBinding pluralAttributeBinding) { + final PluralAttributeSource attributeSource, + final AbstractPluralAttributeBinding pluralAttributeBinding) { if ( attributeSource.getElementSource().getNature() == org.hibernate.metamodel.spi.source.PluralAttributeElementNature.ONE_TO_MANY ) { return; } - final Schema.Name schemaName = Helper.determineDatabaseSchemaName( - attributeSource.getExplicitSchemaName(), - attributeSource.getExplicitCatalogName(), - currentBindingContext - ); - final Schema schema = metadata.getDatabase().locateSchema( schemaName ); - - final String tableName = attributeSource.getExplicitCollectionTableName(); - if ( StringHelper.isNotEmpty( tableName ) ) { - final Identifier tableIdentifier = Identifier.toIdentifier( - currentBindingContext.getNamingStrategy().tableName( tableName ) + TableSpecificationSource tableSpecificationSource = attributeSource.getCollectionTableSpecificationSource(); + if ( TableSource.class.isInstance( tableSpecificationSource ) ) { + Table collectionTable = createTable( + (TableSource) tableSpecificationSource, + new InferredNamingStrategy() { + @Override + public String inferredTableName() { + final EntityBinding owner = pluralAttributeBinding.getContainer().seekEntityBinding(); + final String ownerTableLogicalName = Table.class.isInstance( owner.getPrimaryTable() ) + ? Table.class.cast( owner.getPrimaryTable() ).getTableName().getName() + : null; + return currentBindingContext.getNamingStrategy().collectionTableName( + owner.getEntity().getName(), + ownerTableLogicalName, + null, // todo : here + null, // todo : and here + pluralAttributeBinding.getContainer().getPathBase() + '.' + attributeSource.getName() + ); + } + } ); - Table collectionTable = schema.locateTable( tableIdentifier ); - if ( collectionTable == null ) { - collectionTable = schema.createTable( tableIdentifier ); - } pluralAttributeBinding.setCollectionTable( collectionTable ); } else { - // todo : not sure wel have all the needed info here in all cases, specifically when needing to know the "other side" - final EntityBinding owner = pluralAttributeBinding.getContainer().seekEntityBinding(); - final String ownerTableLogicalName = Table.class.isInstance( owner.getPrimaryTable() ) - ? Table.class.cast( owner.getPrimaryTable() ).getTableName().getName() - : null; - String collectionTableName = currentBindingContext.getNamingStrategy().collectionTableName( - owner.getEntity().getName(), - ownerTableLogicalName, - null, // todo : here - null, // todo : and here - pluralAttributeBinding.getContainer().getPathBase() + '.' + attributeSource.getName() - ); - collectionTableName = quoteIdentifier( collectionTableName ); - pluralAttributeBinding.setCollectionTable( - schema.locateOrCreateTable( - Identifier.toIdentifier( - collectionTableName - ) - ) - ); + pluralAttributeBinding.setCollectionTable( createInLineView( (InLineViewSource) tableSpecificationSource ) ); } if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableComment() ) ) { @@ -1287,40 +1277,99 @@ public class Binder { // Relational ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - private void bindPrimaryTable(EntitySource entitySource, EntityBinding entityBinding) { - final TableSource tableSource = entitySource.getPrimaryTable(); - final Table table = createTable( entityBinding, tableSource ); - entityBinding.setPrimaryTable( table ); - entityBinding.setPrimaryTableName( table.getTableName().getName() ); - } - - private void bindSecondaryTables(EntitySource entitySource, EntityBinding entityBinding) { - for ( TableSource secondaryTableSource : entitySource.getSecondaryTables() ) { - final Table table = createTable( entityBinding, secondaryTableSource ); - entityBinding.addSecondaryTable( secondaryTableSource.getLogicalName(), table ); - } - } - - private Table createTable(EntityBinding entityBinding, TableSource tableSource) { - String tableName = tableSource.getExplicitTableName(); - if ( StringHelper.isEmpty( tableName ) ) { - tableName = currentBindingContext.getNamingStrategy() - .classToTableName( entityBinding.getEntity().getClassName() ); + private void bindPrimaryTable(EntitySource entitySource, final EntityBinding entityBinding) { + final TableSpecificationSource tableSpecificationSource = entitySource.getPrimaryTable(); + if ( TableSource.class.isInstance( tableSpecificationSource ) ) { + final Table table = createTable( + (TableSource) tableSpecificationSource, + new InferredNamingStrategy() { + @Override + public String inferredTableName() { + return currentBindingContext.getNamingStrategy() + .classToTableName( entityBinding.getEntity().getClassName() ); + } + } + ); + entityBinding.setPrimaryTable( table ); + // todo : ugh! + entityBinding.setPrimaryTableName( table.getTableName().getName() ); } else { - tableName = currentBindingContext.getNamingStrategy().tableName( tableName ); + entityBinding.setPrimaryTable( createInLineView( (InLineViewSource) tableSpecificationSource ) ); } - tableName = quoteIdentifier( tableName ); + } + + private InLineView createInLineView(InLineViewSource inLineViewSource) { + final Schema.Name databaseSchemaName = Helper.determineDatabaseSchemaName( + inLineViewSource.getExplicitSchemaName(), + inLineViewSource.getExplicitCatalogName(), + currentBindingContext + ); + final Identifier logicalName = Identifier.toIdentifier( inLineViewSource.getLogicalName() ); + return currentBindingContext.getMetadataImplementor() + .getDatabase() + .locateSchema( databaseSchemaName ) + .createInLineView( logicalName, inLineViewSource.getSelectStatement() ); + } + + private static interface InferredNamingStrategy { + public String inferredTableName(); + } + + private Table createTable(TableSource tableSource, InferredNamingStrategy namingStrategy) { + String explicitTableNameString = tableSource.getExplicitTableName(); + if ( explicitTableNameString == null ) { + explicitTableNameString = namingStrategy.inferredTableName(); + } + explicitTableNameString = quoteIdentifier( explicitTableNameString ); + final Identifier logicalName = Identifier.toIdentifier( explicitTableNameString ); + + explicitTableNameString = currentBindingContext.getNamingStrategy().tableName( explicitTableNameString ); + explicitTableNameString = quoteIdentifier( explicitTableNameString ); + final Identifier physicalName = Identifier.toIdentifier( explicitTableNameString ); final Schema.Name databaseSchemaName = Helper.determineDatabaseSchemaName( tableSource.getExplicitSchemaName(), tableSource.getExplicitCatalogName(), currentBindingContext ); - return currentBindingContext.getMetadataImplementor() + + Table table = currentBindingContext.getMetadataImplementor() .getDatabase() .locateSchema( databaseSchemaName ) - .locateOrCreateTable( Identifier.toIdentifier( tableName ) ); + .locateTable( logicalName ); + if ( table == null ) { + table = currentBindingContext.getMetadataImplementor() + .getDatabase() + .locateSchema( databaseSchemaName ) + .createTable( logicalName, physicalName ); + } + return table; + } + + private void bindSecondaryTables(EntitySource entitySource, EntityBinding entityBinding) { + for ( SecondaryTableSource secondaryTableSource : entitySource.getSecondaryTables() ) { + final TableSpecificationSource source = secondaryTableSource.getTableSource(); + if ( TableSource.class.isInstance( source ) ) { + final Table table = createTable( + (TableSource) source, + new InferredNamingStrategy() { + @Override + public String inferredTableName() { + throw new MappingException( + "Secondary table must specify explicit name", + currentBindingContext.getOrigin() + ); + } + } + ); + // todo : finish up... + // 1) no need to keep secondary tables on EntityBinding because we should be able to look them + // up from Schema + // 2) process foreign key + entityBinding.addSecondaryTable( table.getLogicalName().getName(), table ); + } + } } private void bindTableUniqueConstraints(EntitySource entitySource, EntityBinding entityBinding) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/JPADotNames.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/JPADotNames.java index 3ae5aab10a..c790a38d3a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/JPADotNames.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/JPADotNames.java @@ -111,6 +111,8 @@ import javax.persistence.Version; import org.jboss.jandex.DotName; +import org.hibernate.annotations.Subselect; + /** * Defines the dot names for the JPA annotations * @@ -195,6 +197,7 @@ public interface JPADotNames { DotName SEQUENCE_GENERATOR = DotName.createSimple( SequenceGenerator.class.getName() ); DotName SQL_RESULT_SET_MAPPING = DotName.createSimple( SqlResultSetMapping.class.getName() ); DotName SQL_RESULT_SET_MAPPINGS = DotName.createSimple( SqlResultSetMappings.class.getName() ); + DotName SUBSELECT = DotName.createSimple( Subselect.class.getName() ); DotName TABLE = DotName.createSimple( Table.class.getName() ); DotName TABLE_GENERATOR = DotName.createSimple( TableGenerator.class.getName() ); DotName TEMPORAL = DotName.createSimple( Temporal.class.getName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/EntityClass.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/EntityClass.java index 77bd50fa24..a3c5621bc8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/EntityClass.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/EntityClass.java @@ -23,15 +23,6 @@ */ package org.hibernate.metamodel.internal.source.annotations.entity; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; import javax.persistence.AccessType; import javax.persistence.DiscriminatorType; import javax.persistence.PersistenceException; @@ -42,6 +33,15 @@ import javax.persistence.PostUpdate; import javax.persistence.PrePersist; import javax.persistence.PreRemove; import javax.persistence.PreUpdate; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationValue; @@ -58,10 +58,6 @@ import org.hibernate.annotations.OptimisticLockType; import org.hibernate.annotations.PolymorphismType; import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; -import org.hibernate.internal.util.StringHelper; -import org.hibernate.metamodel.spi.binding.Caching; -import org.hibernate.metamodel.spi.binding.CustomSQL; -import org.hibernate.metamodel.spi.binding.InheritanceType; import org.hibernate.metamodel.internal.source.annotations.AnnotationBindingContext; import org.hibernate.metamodel.internal.source.annotations.HibernateDotNames; import org.hibernate.metamodel.internal.source.annotations.JPADotNames; @@ -69,9 +65,14 @@ import org.hibernate.metamodel.internal.source.annotations.JandexHelper; import org.hibernate.metamodel.internal.source.annotations.attribute.Column; import org.hibernate.metamodel.internal.source.annotations.attribute.FormulaValue; import org.hibernate.metamodel.internal.source.annotations.xml.PseudoJpaDotNames; +import org.hibernate.metamodel.spi.binding.Caching; +import org.hibernate.metamodel.spi.binding.CustomSQL; +import org.hibernate.metamodel.spi.binding.InheritanceType; import org.hibernate.metamodel.spi.source.ConstraintSource; import org.hibernate.metamodel.spi.source.JpaCallbackSource; -import org.hibernate.metamodel.spi.source.TableSource; +import org.hibernate.metamodel.spi.source.PrimaryKeyJoinColumnSource; +import org.hibernate.metamodel.spi.source.SecondaryTableSource; +import org.hibernate.metamodel.spi.source.TableSpecificationSource; /** * Represents an entity or mapped superclass configured via annotations/orm-xml. @@ -87,8 +88,8 @@ public class EntityClass extends ConfiguredClass { private final List synchronizedTableNames; private final int batchSize; - private final TableSource primaryTableSource; - private final Set secondaryTableSources; + private final TableSpecificationSource primaryTableSource; + private final Set secondaryTableSources; private final Set constraintSources; private boolean isMutable; @@ -129,20 +130,17 @@ public class EntityClass extends ConfiguredClass { this.idType = determineIdType(); boolean hasOwnTable = definesItsOwnTable(); this.explicitEntityName = determineExplicitEntityName(); + this.constraintSources = new HashSet(); if ( hasOwnTable ) { - AnnotationInstance tableAnnotation = JandexHelper.getSingleAnnotation( - getClassInfo(), - JPADotNames.TABLE - ); - this.primaryTableSource = createTableSource( tableAnnotation ); + this.primaryTableSource = createPrimaryTableSource(); } else { this.primaryTableSource = null; } - this.secondaryTableSources = createSecondaryTableSources(); + this.customLoaderQueryName = determineCustomLoader(); this.synchronizedTableNames = determineSynchronizedTableNames(); this.batchSize = determineBatchSize(); @@ -194,7 +192,8 @@ public class EntityClass extends ConfiguredClass { return caching; } - public TableSource getPrimaryTableSource() { + public TableSpecificationSource getPrimaryTableSource() { + // todo : this is different from hbm which returns null if "!definesItsOwnTable()" if ( definesItsOwnTable() ) { return primaryTableSource; } @@ -203,7 +202,7 @@ public class EntityClass extends ConfiguredClass { } } - public Set getSecondaryTableSources() { + public Set getSecondaryTableSources() { return secondaryTableSources; } @@ -364,7 +363,7 @@ public class EntityClass extends ConfiguredClass { Class type = String.class; // string is the discriminator default if ( discriminatorFormulaAnnotation != null ) { String expression = JandexHelper.getValue( discriminatorFormulaAnnotation, "value", String.class ); - discriminatorFormula = new FormulaValue( getPrimaryTableSource().getExplicitTableName(), expression ); + discriminatorFormula = new FormulaValue( null, expression ); } discriminatorColumnValues = new Column( null ); //(stliu) give null here, will populate values below discriminatorColumnValues.setNullable( false ); // discriminator column cannot be null @@ -574,78 +573,60 @@ public class EntityClass extends ConfiguredClass { ); } - /** - * todo see {@code Binder#createTable} - * - * @param tableAnnotation a annotation instance, either {@link javax.persistence.Table} or {@link javax.persistence.SecondaryTable} - * - * @return A table source for the specified annotation instance - */ - private TableSource createTableSource(AnnotationInstance tableAnnotation) { - String schema = null; - String catalog = null; - if ( tableAnnotation != null ) { - schema = JandexHelper.getValue( tableAnnotation, "schema", String.class ); - catalog = JandexHelper.getValue( tableAnnotation, "catalog", String.class ); - } - // process the table name - String tableName = null; - String logicalTableName = null; + private TableSpecificationSource createPrimaryTableSource() { + AnnotationInstance tableAnnotation = JandexHelper.getSingleAnnotation( + getClassInfo(), + JPADotNames.TABLE + ); + AnnotationInstance subselectAnnotation = JandexHelper.getSingleAnnotation( + getClassInfo(), + JPADotNames.SUBSELECT + ); if ( tableAnnotation != null ) { - logicalTableName = JandexHelper.getValue( tableAnnotation, "name", String.class ); - if ( StringHelper.isNotEmpty( logicalTableName ) ) { - tableName = logicalTableName; - } - createUniqueConstraints( tableAnnotation, tableName ); + return createPrimaryTableSourceAsTable( tableAnnotation ); } - - TableSourceImpl tableSourceImpl; - if ( tableAnnotation == null || JPADotNames.TABLE.equals( tableAnnotation.name() ) ) { - // for the main table @Table we use 'null' as logical name - tableSourceImpl = new TableSourceImpl( schema, catalog, tableName, null ); + else if ( subselectAnnotation != null ) { + return createPrimaryTableSourceAsInLineView( subselectAnnotation ); } else { - // for secondary tables a name must be specified which is used as logical table name - tableSourceImpl = new TableSourceImpl( schema, catalog, tableName, logicalTableName ); + return new TableSourceImpl( null, null, null ); } - return tableSourceImpl; } - private Set createSecondaryTableSources() { - Set secondaryTableSources = new HashSet(); - AnnotationInstance secondaryTables = JandexHelper.getSingleAnnotation( - getClassInfo(), - JPADotNames.SECONDARY_TABLES - ); - AnnotationInstance secondaryTable = JandexHelper.getSingleAnnotation( - getClassInfo(), - JPADotNames.SECONDARY_TABLE - ); - // collect all @secondaryTable annotations - List secondaryTableAnnotations = new ArrayList(); - if ( secondaryTable != null ) { - secondaryTableAnnotations.add( - secondaryTable - ); + private TableSpecificationSource createPrimaryTableSourceAsTable(AnnotationInstance tableAnnotation) { + final String schemaName = determineSchemaName( tableAnnotation ); + final String catalogName = determineCatalogName( tableAnnotation ); + + final String explicitTableName = tableAnnotation == null + ? null + : JandexHelper.getValue( tableAnnotation, "name", String.class ); + + if ( tableAnnotation != null ) { + createUniqueConstraints( tableAnnotation, null ); } - if ( secondaryTables != null ) { - secondaryTableAnnotations.addAll( - Arrays.asList( - JandexHelper.getValue( secondaryTables, "value", AnnotationInstance[].class ) - ) - ); - } - - // create table sources - for ( AnnotationInstance annotationInstance : secondaryTableAnnotations ) { - secondaryTableSources.add( createTableSource( annotationInstance ) ); - } - - return secondaryTableSources; + return new TableSourceImpl( schemaName, catalogName, explicitTableName ); } + private TableSpecificationSource createPrimaryTableSourceAsInLineView(AnnotationInstance subselectAnnotation) { + return new InLineViewSourceImpl( + JandexHelper.getValue( subselectAnnotation, "value", String.class ), + getEntityName() + ); + } + + private String determineSchemaName(AnnotationInstance tableAnnotation) { + return tableAnnotation == null + ? null + : JandexHelper.getValue( tableAnnotation, "schema", String.class ); + } + + private String determineCatalogName(AnnotationInstance tableAnnotation) { + return tableAnnotation == null + ? null + : JandexHelper.getValue( tableAnnotation, "catalog", String.class ); + } private void createUniqueConstraints(AnnotationInstance tableAnnotation, String tableName) { AnnotationValue value = tableAnnotation.value( "uniqueConstraints" ); @@ -665,6 +646,101 @@ public class EntityClass extends ConfiguredClass { } } + private Set createSecondaryTableSources() { + final Set secondaryTableSources = new HashSet(); + + // process a singular @SecondaryTable annotation + { + AnnotationInstance secondaryTable = JandexHelper.getSingleAnnotation( + getClassInfo(), + JPADotNames.SECONDARY_TABLE + ); + if ( secondaryTable != null ) { + secondaryTableSources.add( createSecondaryTableSource( secondaryTable ) ); + } + } + // process any @SecondaryTables grouping + { + AnnotationInstance secondaryTables = JandexHelper.getSingleAnnotation( + getClassInfo(), + JPADotNames.SECONDARY_TABLES + ); + if ( secondaryTables != null ) { + for ( AnnotationInstance secondaryTable : JandexHelper.getValue( secondaryTables, "value", AnnotationInstance[].class ) ) { + secondaryTableSources.add( createSecondaryTableSource( secondaryTable ) ); + } + } + } + + return secondaryTableSources; + } + + private SecondaryTableSource createSecondaryTableSource(AnnotationInstance tableAnnotation) { + final String schemaName = determineSchemaName( tableAnnotation ); + final String catalogName = determineCatalogName( tableAnnotation ); + final String tableName = JandexHelper.getValue( tableAnnotation, "name", String.class ); + + createUniqueConstraints( tableAnnotation, tableName ); + + final List keys = collectionSecondaryTableKeys( tableAnnotation ); + return new SecondaryTableSourceImpl( new TableSourceImpl( schemaName, catalogName, tableName ), keys ); + } + + private List collectionSecondaryTableKeys(final AnnotationInstance tableAnnotation) { + final AnnotationInstance[] joinColumnAnnotations = JandexHelper.getValue( + tableAnnotation, + "pkJoinColumns", + AnnotationInstance[].class + ); + + if ( joinColumnAnnotations == null ) { + return Collections.emptyList(); + } + final List keys = new ArrayList(); + for ( final AnnotationInstance joinColumnAnnotation : joinColumnAnnotations ) { + keys.add( new PrimaryKeyJoinColumnSourceImpl( joinColumnAnnotation ) ); + } + return keys; + } + + private static class PrimaryKeyJoinColumnSourceImpl implements PrimaryKeyJoinColumnSource { + private final String columnName; + private final String referencedColumnName; + private final String columnDefinition; + + private PrimaryKeyJoinColumnSourceImpl(AnnotationInstance joinColumnAnnotation) { + this( + JandexHelper.getValue( joinColumnAnnotation, "name", String.class ), + JandexHelper.getValue( joinColumnAnnotation, "referencedColumnName", String.class ), + JandexHelper.getValue( joinColumnAnnotation, "columnDefinition", String.class ) + ); + } + + private PrimaryKeyJoinColumnSourceImpl( + String columnName, + String referencedColumnName, + String columnDefinition) { + this.columnName = columnName; + this.referencedColumnName = referencedColumnName; + this.columnDefinition = columnDefinition; + } + + @Override + public String getColumnName() { + return columnName; + } + + @Override + public String getReferencedColumnName() { + return referencedColumnName; + } + + @Override + public String getColumnDefinition() { + return columnDefinition; + } + } + private String determineCustomLoader() { String customLoader = null; // Custom sql loader diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/EntitySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/EntitySourceImpl.java index 7aa27302ef..98d45cf40a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/EntitySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/EntitySourceImpl.java @@ -41,8 +41,9 @@ import org.hibernate.metamodel.internal.source.annotations.attribute.ToOneAttrib import org.hibernate.metamodel.spi.source.AttributeSource; import org.hibernate.metamodel.spi.source.JpaCallbackSource; import org.hibernate.metamodel.spi.source.MetaAttributeSource; +import org.hibernate.metamodel.spi.source.SecondaryTableSource; import org.hibernate.metamodel.spi.source.SubclassEntitySource; -import org.hibernate.metamodel.spi.source.TableSource; +import org.hibernate.metamodel.spi.source.TableSpecificationSource; /** * @author Hardy Ferentschik @@ -86,7 +87,7 @@ public class EntitySourceImpl implements EntitySource { } @Override - public TableSource getPrimaryTable() { + public TableSpecificationSource getPrimaryTable() { return entityClass.getPrimaryTableSource(); } @@ -217,7 +218,7 @@ public class EntitySourceImpl implements EntitySource { } @Override - public Iterable getSecondaryTables() { + public Set getSecondaryTables() { return entityClass.getSecondaryTableSources(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/InLineViewSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/InLineViewSourceImpl.java new file mode 100644 index 0000000000..675791dfe1 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/InLineViewSourceImpl.java @@ -0,0 +1,59 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.internal.source.annotations.entity; + +import org.hibernate.metamodel.spi.source.InLineViewSource; + +/** + * @author Steve Ebersole + */ +public class InLineViewSourceImpl implements InLineViewSource { + private final String selectStatement; + private final String logicalName; + + public InLineViewSourceImpl(String selectStatement, String logicalName) { + this.selectStatement = selectStatement; + this.logicalName = logicalName; + } + + @Override + public String getSelectStatement() { + return selectStatement; + } + + @Override + public String getExplicitSchemaName() { + return null; + } + + @Override + public String getExplicitCatalogName() { + return null; + } + + @Override + public String getLogicalName() { + return logicalName; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/SecondaryTableSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/SecondaryTableSourceImpl.java new file mode 100644 index 0000000000..02e8670e30 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/SecondaryTableSourceImpl.java @@ -0,0 +1,62 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.internal.source.annotations.entity; + +import java.util.Collections; +import java.util.List; + +import org.hibernate.metamodel.spi.source.PrimaryKeyJoinColumnSource; +import org.hibernate.metamodel.spi.source.SecondaryTableSource; +import org.hibernate.metamodel.spi.source.TableSpecificationSource; + +/** + * @author Steve Ebersole + */ +public class SecondaryTableSourceImpl implements SecondaryTableSource { + private final TableSpecificationSource joinTable; + private final List joinColumns; + + public SecondaryTableSourceImpl( + TableSpecificationSource joinTable, + List joinColumns) { + this.joinTable = joinTable; + this.joinColumns = Collections.unmodifiableList( joinColumns ); + } + + @Override + public List getJoinColumns() { + return joinColumns; + } + + @Override + public TableSpecificationSource getTableSource() { + return joinTable; + } + + @Override + public String getForeignKeyName() { + // not supported from annotations, unless docs for @ForeignKey are wrong... + return null; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/TableSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/TableSourceImpl.java index 68786846e7..20702da07e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/TableSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/entity/TableSourceImpl.java @@ -29,13 +29,12 @@ class TableSourceImpl implements TableSource { private final String schema; private final String catalog; private final String tableName; - private final String logicalName; - TableSourceImpl(String schema, String catalog, String tableName, String logicalName) { + TableSourceImpl(String schema, String catalog, String tableName) { this.schema = schema; this.catalog = catalog; - this.tableName = tableName; - this.logicalName = logicalName; + // for some reason annotations passing in "" sometimes :( + this.tableName = tableName.equals( "" ) ? null : tableName; } @Override @@ -53,11 +52,6 @@ class TableSourceImpl implements TableSource { return tableName; } - @Override - public String getLogicalName() { - return logicalName; - } - @Override public boolean equals(Object o) { if ( this == o ) { @@ -72,9 +66,6 @@ class TableSourceImpl implements TableSource { if ( catalog != null ? !catalog.equals( that.catalog ) : that.catalog != null ) { return false; } - if ( logicalName != null ? !logicalName.equals( that.logicalName ) : that.logicalName != null ) { - return false; - } if ( schema != null ? !schema.equals( that.schema ) : that.schema != null ) { return false; } @@ -90,7 +81,6 @@ class TableSourceImpl implements TableSource { int result = schema != null ? schema.hashCode() : 0; result = 31 * result + ( catalog != null ? catalog.hashCode() : 0 ); result = 31 * result + ( tableName != null ? tableName.hashCode() : 0 ); - result = 31 * result + ( logicalName != null ? logicalName.hashCode() : 0 ); return result; } @@ -101,7 +91,6 @@ class TableSourceImpl implements TableSource { sb.append( "{schema='" ).append( schema ).append( '\'' ); sb.append( ", catalog='" ).append( catalog ).append( '\'' ); sb.append( ", tableName='" ).append( tableName ).append( '\'' ); - sb.append( ", logicalName='" ).append( logicalName ).append( '\'' ); sb.append( '}' ); return sb.toString(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/AbstractEntitySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/AbstractEntitySourceImpl.java index 12a2abee8b..99c908956a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/AbstractEntitySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/AbstractEntitySourceImpl.java @@ -25,7 +25,9 @@ package org.hibernate.metamodel.internal.source.hbm; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.hibernate.AssertionFailure; import org.hibernate.EntityMode; @@ -35,6 +37,7 @@ import org.hibernate.internal.jaxb.mapping.hbm.JaxbAnyElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbBagElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbComponentElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbIdbagElement; +import org.hibernate.internal.jaxb.mapping.hbm.JaxbJoinElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbListElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbManyToOneElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbMapElement; @@ -43,6 +46,7 @@ import org.hibernate.internal.jaxb.mapping.hbm.JaxbPropertyElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbSetElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbSynchronizeElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbTuplizerElement; +import org.hibernate.internal.jaxb.mapping.hbm.JoinElementSource; import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.spi.binding.CustomSQL; import org.hibernate.metamodel.spi.source.AttributeSource; @@ -51,9 +55,9 @@ import org.hibernate.metamodel.spi.source.EntitySource; import org.hibernate.metamodel.spi.source.JpaCallbackSource; import org.hibernate.metamodel.spi.source.LocalBindingContext; import org.hibernate.metamodel.spi.source.MetaAttributeSource; +import org.hibernate.metamodel.spi.source.SecondaryTableSource; import org.hibernate.metamodel.spi.source.SingularAttributeSource; import org.hibernate.metamodel.spi.source.SubclassEntitySource; -import org.hibernate.metamodel.spi.source.TableSource; /** * @author Steve Ebersole @@ -62,12 +66,27 @@ import org.hibernate.metamodel.spi.source.TableSource; public abstract class AbstractEntitySourceImpl implements EntitySource { private final MappingDocument sourceMappingDocument; private final EntityElement entityElement; + private final Set secondaryTableSources; private List subclassEntitySources = new ArrayList(); protected AbstractEntitySourceImpl(MappingDocument sourceMappingDocument, EntityElement entityElement) { this.sourceMappingDocument = sourceMappingDocument; this.entityElement = entityElement; + + secondaryTableSources = extractSecondaryTables( entityElement, sourceMappingDocument.getMappingLocalBindingContext() ); + } + + private static Set extractSecondaryTables(EntityElement entityElement, HbmBindingContext bindingContext) { + if ( ! JoinElementSource.class.isInstance( entityElement ) ) { + return Collections.emptySet(); + } + + final Set secondaryTableSources = new HashSet(); + for ( JaxbJoinElement joinElement : ( (JoinElementSource) entityElement ).getJoin() ) { + secondaryTableSources.add( new SecondaryTableSourceImpl( joinElement, bindingContext ) ); + } + return secondaryTableSources; } protected EntityElement entityElement() { @@ -320,11 +339,12 @@ public abstract class AbstractEntitySourceImpl implements EntitySource { } @Override - public Iterable getSecondaryTables() { - return Collections.emptySet(); + public Set getSecondaryTables() { + return secondaryTableSources; } @Override + @SuppressWarnings( {"unchecked"}) public List getJpaCallbackClasses() { return Collections.EMPTY_LIST; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/AbstractPluralAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/AbstractPluralAttributeSourceImpl.java index c0afa2d6c6..c242066683 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/AbstractPluralAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/AbstractPluralAttributeSourceImpl.java @@ -44,6 +44,7 @@ import org.hibernate.metamodel.spi.source.MetaAttributeSource; import org.hibernate.metamodel.spi.source.PluralAttributeElementSource; import org.hibernate.metamodel.spi.source.PluralAttributeKeySource; import org.hibernate.metamodel.spi.source.PluralAttributeSource; +import org.hibernate.metamodel.spi.source.TableSpecificationSource; /** * @author Steve Ebersole @@ -139,6 +140,14 @@ public abstract class AbstractPluralAttributeSourceImpl return elementSource; } + @Override + public TableSpecificationSource getCollectionTableSpecificationSource() { + return Helper.createTableSource( + pluralAttributeElement, + container().getPath() + "." + pluralAttributeElement.getName() + ); + } + @Override public String getExplicitSchemaName() { return pluralAttributeElement.getSchema(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/HbmBindingContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/HbmBindingContext.java index a11fd06103..b97825ce1c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/HbmBindingContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/HbmBindingContext.java @@ -28,6 +28,7 @@ import java.util.List; import org.hibernate.internal.jaxb.mapping.hbm.EntityElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbFetchProfileElement; import org.hibernate.metamodel.spi.source.LocalBindingContext; +import org.hibernate.metamodel.spi.source.MappingException; import org.hibernate.metamodel.spi.source.MetaAttributeContext; /** @@ -43,4 +44,7 @@ public interface HbmBindingContext extends LocalBindingContext { public String determineEntityName(EntityElement entityElement); public void processFetchProfiles(List fetchProfiles, String containingEntityName); + + public MappingException makeMappingException(String message); + public MappingException makeMappingException(String message, Exception cause); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/Helper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/Helper.java index 510a1852e0..ba19d09aa0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/Helper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/Helper.java @@ -41,6 +41,7 @@ import org.hibernate.internal.jaxb.mapping.hbm.JaxbMetaElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbParamElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbSubclassElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbUnionSubclassElement; +import org.hibernate.internal.jaxb.mapping.hbm.TableInformationSource; import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.spi.binding.CustomSQL; import org.hibernate.metamodel.spi.binding.InheritanceType; @@ -53,6 +54,7 @@ import org.hibernate.metamodel.spi.source.MappingException; import org.hibernate.metamodel.spi.source.MetaAttributeContext; import org.hibernate.metamodel.spi.source.MetaAttributeSource; import org.hibernate.metamodel.spi.source.RelationalValueSource; +import org.hibernate.metamodel.spi.source.TableSpecificationSource; /** * A helper for dealing with @@ -287,6 +289,27 @@ public class Helper { return null; } + public static TableSpecificationSource createTableSource(TableInformationSource jaxbTableSource, String context) { + if ( jaxbTableSource.getSubselectAttribute() == null && jaxbTableSource.getSubselect() == null ) { + return new TableSourceImpl( + jaxbTableSource.getSchema(), + jaxbTableSource.getCatalog(), + jaxbTableSource.getTable() + ); + } + else { + return new InLineViewSourceImpl( + jaxbTableSource.getSchema(), + jaxbTableSource.getCatalog(), + jaxbTableSource.getSubselectAttribute() != null + ? jaxbTableSource.getSubselectAttribute() + : jaxbTableSource.getSubselect(), + context + ); + } + + } + /** * For things that define one or more "value sources" there is a lot of variance in terms of how they * look in the XML. As an example, consider {@code } which might have:
    diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/InLineViewSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/InLineViewSourceImpl.java new file mode 100644 index 0000000000..3778f75917 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/InLineViewSourceImpl.java @@ -0,0 +1,66 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.internal.source.hbm; + +import org.hibernate.metamodel.spi.source.InLineViewSource; + +/** + * @author Steve Ebersole + */ +public class InLineViewSourceImpl implements InLineViewSource { + private final String schemaName; + private final String catalogName; + private final String selectStatement; + private final String logicalName; + + public InLineViewSourceImpl( + String schemaName, + String catalogName, + String selectStatement, String logicalName) { + this.schemaName = schemaName; + this.catalogName = catalogName; + this.selectStatement = selectStatement; + this.logicalName = logicalName; + } + + @Override + public String getExplicitSchemaName() { + return schemaName; + } + + @Override + public String getExplicitCatalogName() { + return catalogName; + } + + @Override + public String getSelectStatement() { + return selectStatement; + } + + @Override + public String getLogicalName() { + return logicalName; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MappingDocument.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MappingDocument.java index 414e27fb1e..81ce639886 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MappingDocument.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/MappingDocument.java @@ -35,6 +35,7 @@ import org.hibernate.internal.util.Value; import org.hibernate.metamodel.internal.source.OverriddenMappingDefaults; import org.hibernate.metamodel.spi.domain.Type; import org.hibernate.metamodel.spi.source.MappingDefaults; +import org.hibernate.metamodel.spi.source.MappingException; import org.hibernate.metamodel.spi.source.MetaAttributeContext; import org.hibernate.metamodel.spi.source.MetadataImplementor; import org.hibernate.service.ServiceRegistry; @@ -169,5 +170,15 @@ public class MappingDocument { public void processFetchProfiles(List fetchProfiles, String containingEntityName) { // todo : this really needs to not be part of the context } + + @Override + public MappingException makeMappingException(String message) { + return new MappingException( message, getOrigin() ); + } + + @Override + public MappingException makeMappingException(String message, Exception cause) { + return new MappingException( message, cause, getOrigin() ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/RootEntitySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/RootEntitySourceImpl.java index 3537132b6b..169da98d62 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/RootEntitySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/RootEntitySourceImpl.java @@ -37,22 +37,30 @@ import org.hibernate.internal.util.Value; import org.hibernate.metamodel.spi.binding.Caching; import org.hibernate.metamodel.spi.binding.IdGenerator; import org.hibernate.metamodel.spi.source.AttributeSource; -import org.hibernate.metamodel.spi.source.MappingException; import org.hibernate.metamodel.spi.source.DiscriminatorSource; import org.hibernate.metamodel.spi.source.IdentifierSource; +import org.hibernate.metamodel.spi.source.MappingException; import org.hibernate.metamodel.spi.source.RelationalValueSource; import org.hibernate.metamodel.spi.source.RootEntitySource; import org.hibernate.metamodel.spi.source.SimpleIdentifierSource; import org.hibernate.metamodel.spi.source.SingularAttributeSource; -import org.hibernate.metamodel.spi.source.TableSource; +import org.hibernate.metamodel.spi.source.TableSpecificationSource; import org.hibernate.metamodel.spi.source.VersionAttributeSource; /** * @author Steve Ebersole */ public class RootEntitySourceImpl extends AbstractEntitySourceImpl implements RootEntitySource { - protected RootEntitySourceImpl(MappingDocument sourceMappingDocument, JaxbHibernateMapping.JaxbClass entityElement) { + private final TableSpecificationSource primaryTable; + + protected RootEntitySourceImpl( + MappingDocument sourceMappingDocument, + JaxbHibernateMapping.JaxbClass entityElement) { super( sourceMappingDocument, entityElement ); + this.primaryTable = Helper.createTableSource( + entityElement, + sourceMappingDocument.getMappingLocalBindingContext().determineEntityName( entityElement ) + ); } @Override @@ -196,29 +204,8 @@ public class RootEntitySourceImpl extends AbstractEntitySourceImpl implements Ro } @Override - public TableSource getPrimaryTable() { - return new TableSource() { - @Override - public String getExplicitSchemaName() { - return entityElement().getSchema(); - } - - @Override - public String getExplicitCatalogName() { - return entityElement().getCatalog(); - } - - @Override - public String getExplicitTableName() { - return entityElement().getTable(); - } - - @Override - public String getLogicalName() { - // logical name for the primary table is null - return null; - } - }; + public TableSpecificationSource getPrimaryTable() { + return primaryTable; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SecondaryTableSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SecondaryTableSourceImpl.java new file mode 100644 index 0000000000..3201111789 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SecondaryTableSourceImpl.java @@ -0,0 +1,111 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.internal.source.hbm; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.internal.jaxb.mapping.hbm.JaxbColumnElement; +import org.hibernate.internal.jaxb.mapping.hbm.JaxbJoinElement; +import org.hibernate.metamodel.spi.source.PrimaryKeyJoinColumnSource; +import org.hibernate.metamodel.spi.source.SecondaryTableSource; +import org.hibernate.metamodel.spi.source.TableSpecificationSource; + +/** + * @author Steve Ebersole + */ +public class SecondaryTableSourceImpl implements SecondaryTableSource { + private final JaxbJoinElement joinElement; + private final TableSpecificationSource joinTable; + private final List joinColumns; + + public SecondaryTableSourceImpl(JaxbJoinElement joinElement, HbmBindingContext bindingContext) { + this.joinElement = joinElement; + this.joinTable = Helper.createTableSource( + joinElement, + // todo : need to implement this + null + ); + + joinColumns = new ArrayList(); + if ( joinElement.getKey().getColumnAttribute() != null ) { + if ( joinElement.getKey().getColumn().size() > 0 ) { + throw bindingContext.makeMappingException( " defined both column attribute and nested " ); + } + joinColumns.add( + new PrimaryKeyJoinColumnSource() { + @Override + public String getColumnName() { + return SecondaryTableSourceImpl.this.joinElement.getKey().getColumnAttribute(); + } + + @Override + public String getReferencedColumnName() { + return null; + } + + @Override + public String getColumnDefinition() { + return null; + } + } + ); + } + for ( final JaxbColumnElement columnElement : joinElement.getKey().getColumn() ) { + joinColumns.add( + new PrimaryKeyJoinColumnSource() { + @Override + public String getColumnName() { + return columnElement.getName(); + } + + @Override + public String getReferencedColumnName() { + return null; + } + + @Override + public String getColumnDefinition() { + return columnElement.getSqlType(); + } + } + ); + } + } + + @Override + public TableSpecificationSource getTableSource() { + return joinTable; + } + + @Override + public String getForeignKeyName() { + return joinElement.getKey().getForeignKey(); + } + + @Override + public List getJoinColumns() { + return joinColumns; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SubclassEntitySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SubclassEntitySourceImpl.java index 6bfa64f569..9b6070b004 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SubclassEntitySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SubclassEntitySourceImpl.java @@ -24,78 +24,36 @@ package org.hibernate.metamodel.internal.source.hbm; import org.hibernate.internal.jaxb.mapping.hbm.EntityElement; -import org.hibernate.internal.jaxb.mapping.hbm.JaxbJoinedSubclassElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbSubclassElement; -import org.hibernate.internal.jaxb.mapping.hbm.JaxbUnionSubclassElement; +import org.hibernate.internal.jaxb.mapping.hbm.TableInformationSource; import org.hibernate.metamodel.spi.source.EntitySource; import org.hibernate.metamodel.spi.source.SubclassEntitySource; -import org.hibernate.metamodel.spi.source.TableSource; +import org.hibernate.metamodel.spi.source.TableSpecificationSource; /** * @author Steve Ebersole */ public class SubclassEntitySourceImpl extends AbstractEntitySourceImpl implements SubclassEntitySource { - private final EntitySource container; + private final TableSpecificationSource primaryTable; - protected SubclassEntitySourceImpl( MappingDocument sourceMappingDocument, - EntityElement entityElement, - EntitySource container ) { + protected SubclassEntitySourceImpl( + MappingDocument sourceMappingDocument, + EntityElement entityElement, + EntitySource container) { super( sourceMappingDocument, entityElement ); this.container = container; + this.primaryTable = TableInformationSource.class.isInstance( entityElement ) + ? Helper.createTableSource( + (TableInformationSource) entityElement, + sourceMappingDocument.getMappingLocalBindingContext().determineEntityName( entityElement ) + ) + : null; } @Override - public TableSource getPrimaryTable() { - if ( JaxbJoinedSubclassElement.class.isInstance( entityElement() ) ) { - return new TableSource() { - @Override - public String getExplicitSchemaName() { - return ( (JaxbJoinedSubclassElement) entityElement() ).getSchema(); - } - - @Override - public String getExplicitCatalogName() { - return ( (JaxbJoinedSubclassElement) entityElement() ).getCatalog(); - } - - @Override - public String getExplicitTableName() { - return ( (JaxbJoinedSubclassElement) entityElement() ).getTable(); - } - - @Override - public String getLogicalName() { - // logical name for the primary table is null - return null; - } - }; - } - else if ( JaxbUnionSubclassElement.class.isInstance( entityElement() ) ) { - return new TableSource() { - @Override - public String getExplicitSchemaName() { - return ( (JaxbUnionSubclassElement) entityElement() ).getSchema(); - } - - @Override - public String getExplicitCatalogName() { - return ( (JaxbUnionSubclassElement) entityElement() ).getCatalog(); - } - - @Override - public String getExplicitTableName() { - return ( (JaxbUnionSubclassElement) entityElement() ).getTable(); - } - - @Override - public String getLogicalName() { - // logical name for the primary table is null - return null; - } - }; - } - return null; + public TableSpecificationSource getPrimaryTable() { + return primaryTable; } @Override @@ -105,11 +63,6 @@ public class SubclassEntitySourceImpl extends AbstractEntitySourceImpl implement : null; } - /** - * {@inheritDoc} - * - * @see SubclassEntitySource#superclassEntitySource() - */ @Override public EntitySource superclassEntitySource() { return container; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/TableSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/TableSourceImpl.java new file mode 100644 index 0000000000..ef211a2765 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/TableSourceImpl.java @@ -0,0 +1,56 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.internal.source.hbm; + +import org.hibernate.metamodel.spi.source.TableSource; + +/** + * @author Steve Ebersole + */ +public class TableSourceImpl implements TableSource { + private final String schema; + private final String catalog; + private final String tableName; + + TableSourceImpl(String schema, String catalog, String tableName) { + this.schema = schema; + this.catalog = catalog; + this.tableName = tableName; + } + + @Override + public String getExplicitSchemaName() { + return schema; + } + + @Override + public String getExplicitCatalogName() { + return catalog; + } + + @Override + public String getExplicitTableName() { + return tableName; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java index 9c035276b6..620ccf0dcb 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeBinding.java @@ -32,7 +32,6 @@ import org.hibernate.FetchMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.spi.domain.PluralAttribute; -import org.hibernate.metamodel.spi.relational.Table; import org.hibernate.metamodel.spi.relational.TableSpecification; import org.hibernate.metamodel.spi.source.MetaAttributeContext; import org.hibernate.persister.collection.CollectionPersister; @@ -46,7 +45,7 @@ public abstract class AbstractPluralAttributeBinding extends AbstractAttributeBi private final PluralAttributeKeyBinding pluralAttributeKeyBinding; private final AbstractPluralAttributeElementBinding pluralAttributeElementBinding; - private Table collectionTable; + private TableSpecification collectionTable; private FetchTiming fetchTiming; private FetchStyle fetchStyle; @@ -167,7 +166,7 @@ public abstract class AbstractPluralAttributeBinding extends AbstractAttributeBi return collectionTable; } - public void setCollectionTable(Table collectionTable) { + public void setCollectionTable(TableSpecification collectionTable) { this.collectionTable = collectionTable; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/InLineView.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/InLineView.java index cebddd4d74..9a2e93092d 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/InLineView.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/InLineView.java @@ -36,10 +36,10 @@ import org.hibernate.dialect.Dialect; */ public class InLineView extends AbstractTableSpecification { private final Schema schema; - private final String logicalName; + private final Identifier logicalName; private final String select; - public InLineView(Schema schema, String logicalName, String select) { + public InLineView(Schema schema, Identifier logicalName, String select) { this.schema = schema; this.logicalName = logicalName; this.select = select; @@ -50,7 +50,7 @@ public class InLineView extends AbstractTableSpecification { } @Override - public String getLogicalName() { + public Identifier getLogicalName() { return logicalName; } @@ -60,7 +60,7 @@ public class InLineView extends AbstractTableSpecification { @Override public String getLoggableValueQualifier() { - return logicalName; + return logicalName.getName(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Schema.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Schema.java index a7c33bda4b..dc27473b1f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Schema.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Schema.java @@ -33,7 +33,7 @@ import java.util.Map; */ public class Schema { private final Name name; - private Map inLineViews = new HashMap(); + private Map inLineViews = new HashMap(); private Map tables = new HashMap(); public Schema(Name name) { @@ -49,72 +49,41 @@ public class Schema { } /** - * Returns the table with the specified table name. + * Returns the table with the specified logical table name. * - * @param tableName - the name of the table + * @param logicalTableName - the logical name of the table * * @return the table with the specified table name, * or null if there is no table with the specified * table name. */ - public Table locateTable(Identifier tableName) { - return tables.get( tableName ); + public Table locateTable(Identifier logicalTableName) { + return tables.get( logicalTableName ); } /** * Creates a {@link Table} with the specified name. * - * @param tableName - the name of the table + * @param logicalTableName The logical table name + * @param physicalTableName - the name of the table * * @return the created table. */ - public Table createTable(Identifier tableName) { - Table table = new Table( this, tableName ); - tables.put( tableName, table ); + public Table createTable(Identifier logicalTableName, Identifier physicalTableName) { + Table table = new Table( this, logicalTableName, physicalTableName ); + tables.put( logicalTableName, table ); return table; } - /** - * Locates a {@link Table} with the specified name; if - * it does not exist, then a table is created with - * the specified name. - * - * @param tableName - the name of the table - * - * @return the located or created table. - */ - public Table locateOrCreateTable(Identifier tableName) { - final Table existing = locateTable( tableName ); - if ( existing == null ) { - return createTable( tableName ); - } - return existing; - } - - /* package-protected */ - void remapTableName(Identifier oldTableName) { - Table table = tables.remove( oldTableName ); - if ( table == null ) { - throw new IllegalStateException( - String.format( - "Schema (%s) does not contain a table (%s) to remap.", - name, - oldTableName - ) - ); - } - tables.put( table.getTableName(), table ); - } - public Iterable getTables() { return tables.values(); } - public InLineView getInLineView(String logicalName) { + public InLineView getInLineView(Identifier logicalName) { return inLineViews.get( logicalName ); } - public InLineView createInLineView(String logicalName, String subSelect) { + public InLineView createInLineView(Identifier logicalName, String subSelect) { InLineView inLineView = new InLineView( this, logicalName, subSelect ); inLineViews.put( logicalName, inLineView ); return inLineView; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Table.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Table.java index 63682090f4..68e7bd79e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Table.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/Table.java @@ -37,9 +37,10 @@ import org.hibernate.dialect.Dialect; */ public class Table extends AbstractTableSpecification implements Exportable { private final Schema database; - private Identifier tableName; + private Identifier physicalName; + private Identifier logicalName; private ObjectName objectName; - private String qualifiedName; + private String exportIdentifier; private final LinkedHashMap indexes = new LinkedHashMap(); private final LinkedHashMap uniqueKeys = new LinkedHashMap(); @@ -50,21 +51,15 @@ public class Table extends AbstractTableSpecification implements Exportable { * Constructs a {@link Table} instance. * * @param database - the schema - * @param tableName - the table name as a String + * @param logicalName - The logical name + * @param physicalName - the physical table name. */ - public Table(Schema database, String tableName) { - this( database, Identifier.toIdentifier( tableName ) ); - } - - /** - * Constructs a {@link Table} instance. - * - * @param database - the schema - * @param tableName - the table name as an {@link Identifier} - */ - public Table(Schema database, Identifier tableName) { + public Table(Schema database, Identifier logicalName, Identifier physicalName) { this.database = database; - setTableName( tableName ); + this.logicalName = logicalName; + this.physicalName = physicalName; + this.objectName = new ObjectName( database, physicalName ); + this.exportIdentifier = objectName.toText(); } @Override @@ -78,29 +73,8 @@ public class Table extends AbstractTableSpecification implements Exportable { * @return the logical table name. */ @Override - public String getLogicalName() { - return tableName.getName(); - } - - /** - * Sets the table name, remapping this {@link Table} by the new - * table name in the {@link Schema}, if necessary. - * - * @param tableName - the table name - */ - public final void setTableName(Identifier tableName) { - if ( tableName == null ) { - throw new IllegalArgumentException( "tableName cannot be null." ); - } - if ( !tableName.equals( this.tableName ) ) { - Identifier tableNameOld = this.tableName; - this.tableName = tableName; - objectName = new ObjectName( database.getName().getSchema(), database.getName().getCatalog(), tableName ); - this.qualifiedName = objectName.toText(); - if ( tableNameOld != null ) { - database.remapTableName( tableNameOld ); - } - } + public Identifier getLogicalName() { + return logicalName; } /** @@ -108,22 +82,22 @@ public class Table extends AbstractTableSpecification implements Exportable { * @return the table name. */ public Identifier getTableName() { - return tableName; + return physicalName; } @Override public String getLoggableValueQualifier() { - return qualifiedName; + return exportIdentifier; } @Override public String getExportIdentifier() { - return qualifiedName; + return exportIdentifier; } @Override public String toLoggableString() { - return qualifiedName; + return exportIdentifier; } @Override @@ -341,6 +315,6 @@ public class Table extends AbstractTableSpecification implements Exportable { @Override public String toString() { - return "Table{name=" + qualifiedName + '}'; + return "Table{name=" + exportIdentifier + '}'; } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/TableSpecification.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/TableSpecification.java index 0ec1bb61b8..fa14731496 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/TableSpecification.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/relational/TableSpecification.java @@ -43,7 +43,7 @@ public interface TableSpecification extends ValueContainer, Loggable { * * @return the logical table name. */ - public String getLogicalName(); + public Identifier getLogicalName(); /** * Get the table number. diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/EntitySource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/EntitySource.java index 371bc06f93..a68cba68dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/EntitySource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/EntitySource.java @@ -24,6 +24,7 @@ package org.hibernate.metamodel.spi.source; import java.util.List; +import java.util.Set; import javax.persistence.Entity; import javax.persistence.EntityListeners; import javax.persistence.MappedSuperclass; @@ -78,14 +79,14 @@ public interface EntitySource extends SubclassEntityContainer, AttributeSourceCo * * @return The primary table. */ - public TableSource getPrimaryTable(); + public TableSpecificationSource getPrimaryTable(); /** * Obtain the secondary tables for this entity * * @return returns an iterator over the secondary tables for this entity */ - public Iterable getSecondaryTables(); + public Set getSecondaryTables(); /** * Obtain the name of a custom tuplizer class to be used. diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/InLineViewSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/InLineViewSource.java new file mode 100644 index 0000000000..ff15a9ddaa --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/InLineViewSource.java @@ -0,0 +1,41 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.spi.source; + +/** + * Describes in-line view source information. Generally, either {@link org.hibernate.annotations.Subselect} + * or {@code } + * + * @author Steve Ebersole + */ +public interface InLineViewSource extends TableSpecificationSource { + /** + * Obtain the {@code SQL SELECT} statement to use. Cannot be null! + * + * @return The {@code SQL SELECT} statement + */ + public String getSelectStatement(); + + public String getLogicalName(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeSource.java index 208101c8d5..2d64fa0bde 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PluralAttributeSource.java @@ -37,6 +37,7 @@ public interface PluralAttributeSource public PluralAttributeElementSource getElementSource(); + public TableSpecificationSource getCollectionTableSpecificationSource(); public String getExplicitSchemaName(); public String getExplicitCatalogName(); public String getExplicitCollectionTableName(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PrimaryKeyJoinColumnSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PrimaryKeyJoinColumnSource.java new file mode 100644 index 0000000000..6d82fc5c4d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/PrimaryKeyJoinColumnSource.java @@ -0,0 +1,33 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.spi.source; + +/** + * @author Steve Ebersole + */ +public interface PrimaryKeyJoinColumnSource { + public String getColumnName(); + public String getReferencedColumnName(); + public String getColumnDefinition(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/SecondaryTableSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/SecondaryTableSource.java new file mode 100644 index 0000000000..783ffcf201 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/SecondaryTableSource.java @@ -0,0 +1,52 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.spi.source; + +import java.util.List; + +/** + * @author Steve Ebersole + */ +public interface SecondaryTableSource { + /** + * Obtain the table being joined to. + * + * @return The joined table. + */ + public TableSpecificationSource getTableSource(); + + /** + * Retrieves the columns used to define the foreign key back to the entity table. + * + * @return The columns used to define the foreign key for this secondary table + */ + public List getJoinColumns(); + + /** + * Retrieve any user-specified foreign key name. + * + * @return The user-specified foreign key name, or {@code null} if the user did not specify. + */ + public String getForeignKeyName(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/TableSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/TableSource.java index 2e070207dc..a3a19adcc3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/TableSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/TableSource.java @@ -28,35 +28,11 @@ package org.hibernate.metamodel.spi.source; * * @author Steve Ebersole */ -public interface TableSource { - /** - * Obtain the supplied schema name - * - * @return The schema name. If {@code null}, the binder will apply the default. - */ - public String getExplicitSchemaName(); - - /** - * Obtain the supplied catalog name - * - * @return The catalog name. If {@code null}, the binder will apply the default. - */ - public String getExplicitCatalogName(); - +public interface TableSource extends TableSpecificationSource { /** * Obtain the supplied table name. * - * @return The table name. + * @return The table name, or {@code null} is no name specified. */ public String getExplicitTableName(); - - /** - * Obtain the logical name of the table. This value is used to uniquely reference the table when binding - * values to the binding model. - * - * @return The logical name. Can be {@code null} in the case of the "primary table". - * - * @see RelationalValueSource#getContainingTableName() - */ - public String getLogicalName(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/TableSpecificationSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/TableSpecificationSource.java new file mode 100644 index 0000000000..3360486313 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/TableSpecificationSource.java @@ -0,0 +1,47 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.spi.source; + +/** + * Contract describing source of "table specification" information. + * + * @author Steve Ebersole + * + * @see org.hibernate.metamodel.spi.relational.TableSpecification + */ +public interface TableSpecificationSource { + /** + * Obtain the supplied schema name + * + * @return The schema name. If {@code null}, the binder will apply the default. + */ + public String getExplicitSchemaName(); + + /** + * Obtain the supplied catalog name + * + * @return The catalog name. If {@code null}, the binder will apply the default. + */ + public String getExplicitCatalogName(); +} diff --git a/hibernate-core/src/main/xjb/hbm-mapping-bindings.xjb b/hibernate-core/src/main/xjb/hbm-mapping-bindings.xjb index 51811d9748..c38f6429d6 100644 --- a/hibernate-core/src/main/xjb/hbm-mapping-bindings.xjb +++ b/hibernate-core/src/main/xjb/hbm-mapping-bindings.xjb @@ -20,6 +20,7 @@ org.hibernate.internal.jaxb.mapping.hbm.EntityElement + org.hibernate.internal.jaxb.mapping.hbm.TableInformationSource org.hibernate.internal.jaxb.mapping.hbm.JoinElementSource @@ -28,10 +29,16 @@ org.hibernate.internal.jaxb.mapping.hbm.SubEntityElement + org.hibernate.internal.jaxb.mapping.hbm.TableInformationSource org.hibernate.internal.jaxb.mapping.hbm.SubEntityElement + org.hibernate.internal.jaxb.mapping.hbm.TableInformationSource + + org.hibernate.internal.jaxb.mapping.hbm.TableInformationSource + + org.hibernate.internal.jaxb.mapping.hbm.CustomSqlElement diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/AssertSourcesTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/AssertSourcesTest.java index e1daf40ba3..245902141d 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/AssertSourcesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/AssertSourcesTest.java @@ -40,6 +40,7 @@ import org.hibernate.metamodel.spi.source.SimpleIdentifierSource; import org.hibernate.metamodel.spi.source.SingularAttributeNature; import org.hibernate.metamodel.spi.source.SingularAttributeSource; import org.hibernate.metamodel.spi.source.TableSource; +import org.hibernate.metamodel.spi.source.TableSpecificationSource; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; @@ -98,10 +99,11 @@ public class AssertSourcesTest extends BaseUnitTestCase { assertTrue( entitySource.getJpaCallbackClasses() == null || entitySource.getJpaCallbackClasses().isEmpty() ); - TableSource primaryTable = entitySource.getPrimaryTable(); + TableSpecificationSource primaryTableSpecificationSource = entitySource.getPrimaryTable(); + assertTrue( TableSource.class.isInstance( primaryTableSpecificationSource ) ); + TableSource primaryTable = (TableSource) primaryTableSpecificationSource; // todo : should sources be responsible for figuring out logical names? // these are the things that need to match in terms of lookup keys - assertNull( primaryTable.getLogicalName() ); assertNull( primaryTable.getExplicitCatalogName() ); assertNull( primaryTable.getExplicitSchemaName() ); assertNull( primaryTable.getExplicitTableName() ); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/SimpleValueBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/SimpleValueBindingTests.java index 23ae70504d..eec2be4cba 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/SimpleValueBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/SimpleValueBindingTests.java @@ -35,6 +35,7 @@ import org.hibernate.mapping.PropertyGeneration; import org.hibernate.metamodel.spi.domain.Entity; import org.hibernate.metamodel.spi.domain.SingularAttribute; import org.hibernate.metamodel.spi.relational.Column; +import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.metamodel.spi.relational.JdbcDataType; import org.hibernate.metamodel.spi.relational.Schema; import org.hibernate.metamodel.spi.relational.Size; @@ -56,7 +57,8 @@ public class SimpleValueBindingTests extends BaseUnitTestCase { @Test public void testBasicMiddleOutBuilding() { - Table table = new Table( new Schema( null, null ), "the_table" ); + final Identifier tableName = Identifier.toIdentifier( "the_table" ); + Table table = new Table( new Schema( null, null ), tableName, tableName ); Column idColumn = table.locateOrCreateColumn( "id" ); idColumn.setJdbcDataType( BIGINT ); idColumn.setSize( Size.precision( 18, 0 ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/relational/TableManipulationTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/relational/TableManipulationTests.java index 2e28bafbf3..d744a64125 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/relational/TableManipulationTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/relational/TableManipulationTests.java @@ -48,7 +48,7 @@ public class TableManipulationTests extends BaseUnitTestCase { @Test public void testTableCreation() { Schema schema = new Schema( null, null ); - Table table = schema.createTable( Identifier.toIdentifier( "my_table" ) ); + Table table = schema.createTable( Identifier.toIdentifier( "my_table" ), Identifier.toIdentifier( "my_table" ) ); assertNull( table.getSchema().getName().getSchema() ); assertNull( table.getSchema().getName().getCatalog() ); assertEquals( "my_table", table.getTableName().toString() ); @@ -92,10 +92,10 @@ public class TableManipulationTests extends BaseUnitTestCase { @Test public void testTableSpecificationCounter() { Schema schema = new Schema( null, null ); - Table table = schema.createTable( Identifier.toIdentifier( "my_table" ) ); - InLineView inLineView = schema.createInLineView( "my_inlineview", "subselect" ); - InLineView otherInLineView = schema.createInLineView( "my_other_inlineview", "other subselect" ); - Table otherTable = schema.createTable( Identifier.toIdentifier( "my_other_table" ) ); + Table table = schema.createTable( Identifier.toIdentifier( "my_table" ), Identifier.toIdentifier( "my_table" ) ); + InLineView inLineView = schema.createInLineView( Identifier.toIdentifier( "my_inlineview" ), "subselect" ); + InLineView otherInLineView = schema.createInLineView( Identifier.toIdentifier( "my_other_inlineview" ), "other subselect" ); + Table otherTable = schema.createTable( Identifier.toIdentifier( "my_other_table" ), Identifier.toIdentifier( "my_other_table" ) ); int firstTableNumber = table.getTableNumber(); assertEquals( firstTableNumber, table.getTableNumber() ); @@ -107,7 +107,7 @@ public class TableManipulationTests extends BaseUnitTestCase { @Test public void testBasicForeignKeyDefinition() { Schema schema = new Schema( null, null ); - Table book = schema.createTable( Identifier.toIdentifier( "BOOK" ) ); + Table book = schema.createTable( Identifier.toIdentifier( "BOOK" ), Identifier.toIdentifier( "BOOK" ) ); Column bookId = book.locateOrCreateColumn( "id" ); bookId.setJdbcDataType( INTEGER ); @@ -115,7 +115,7 @@ public class TableManipulationTests extends BaseUnitTestCase { book.getPrimaryKey().addColumn( bookId ); book.getPrimaryKey().setName( "BOOK_PK" ); - Table page = schema.createTable( Identifier.toIdentifier( "PAGE" ) ); + Table page = schema.createTable( Identifier.toIdentifier( "PAGE" ), Identifier.toIdentifier( "PAGE" ) ); Column pageId = page.locateOrCreateColumn( "id" ); pageId.setJdbcDataType( INTEGER ); @@ -137,17 +137,17 @@ public class TableManipulationTests extends BaseUnitTestCase { public void testQualifiedName() { Dialect dialect = new H2Dialect(); Schema schema = new Schema( Identifier.toIdentifier( "schema" ), Identifier.toIdentifier( "`catalog`" ) ); - Table table = schema.createTable( Identifier.toIdentifier( "my_table" ) ); + Table table = schema.createTable( Identifier.toIdentifier( "my_table" ), Identifier.toIdentifier( "my_table" ) ); assertEquals( "my_table", table.getTableName().getName() ); assertEquals( "my_table", table.getTableName().toString() ); assertEquals( "schema.\"catalog\".my_table", table.getQualifiedName( dialect ) ); - table = schema.createTable( Identifier.toIdentifier( "`my_table`" ) ); + table = schema.createTable( Identifier.toIdentifier( "`my_table`" ), Identifier.toIdentifier( "`my_table`" ) ); assertEquals( "my_table", table.getTableName().getName() ); assertEquals( "`my_table`", table.getTableName().toString() ); assertEquals( "schema.\"catalog\".\"my_table\"", table.getQualifiedName( dialect ) ); - InLineView inLineView = schema.createInLineView( "my_inlineview", "select ..." ); + InLineView inLineView = schema.createInLineView( Identifier.toIdentifier( "my_inlineview" ), "select ..." ); assertEquals( "( select ... )", inLineView.getQualifiedName( dialect ) ); } @@ -156,22 +156,10 @@ public class TableManipulationTests extends BaseUnitTestCase { Identifier tableIdentifier = Identifier.toIdentifier( "my_table" ); assertEquals( "my_table", tableIdentifier.getName() ); Schema schema = new Schema( Identifier.toIdentifier( "schema" ), Identifier.toIdentifier( "`catalog`" ) ); - Table table = schema.createTable( tableIdentifier ); + Table table = schema.createTable( tableIdentifier, tableIdentifier ); assertSame( tableIdentifier, table.getTableName() ); assertSame( table, schema.locateTable( Identifier.toIdentifier( "my_table" ) ) ); - assertEquals( "my_table", table.getLogicalName() ); - tableIdentifier = Identifier.toIdentifier( "my_new_table" ); - table.setTableName( tableIdentifier ); - assertEquals( "my_new_table", table.getLogicalName() ); - assertEquals( "my_new_table", table.getTableName().getName() ); - assertSame( table, schema.locateTable( Identifier.toIdentifier( "my_new_table" ) ) ); - assertNull( schema.locateTable( Identifier.toIdentifier( "my_table" ) ) ); - tableIdentifier = Identifier.toIdentifier( "my_newer_table" ); - table.setTableName( tableIdentifier ); - assertEquals( "my_newer_table", table.getLogicalName() ); - assertEquals( "my_newer_table", table.getTableName().getName() ); - assertSame( table, schema.locateTable( Identifier.toIdentifier( "my_newer_table" ) ) ); - assertNull( schema.locateTable( Identifier.toIdentifier( "my_new_table" ) ) ); + assertEquals( "my_table", table.getLogicalName().getName() ); } @Test @@ -179,42 +167,20 @@ public class TableManipulationTests extends BaseUnitTestCase { Identifier tableIdentifier = Identifier.toIdentifier( "`my_table`" ); assertEquals( "my_table", tableIdentifier.getName() ); Schema schema = new Schema( Identifier.toIdentifier( "schema" ), Identifier.toIdentifier( "`catalog`" ) ); - Table table = schema.createTable( tableIdentifier ); + Table table = schema.createTable( tableIdentifier, tableIdentifier ); assertSame( tableIdentifier, table.getTableName() ); assertSame( table, schema.locateTable( Identifier.toIdentifier( "`my_table`" ) ) ); - assertEquals( "my_table", table.getLogicalName() ); + assertEquals( "my_table", table.getLogicalName().getName() ); + assertTrue( table.getLogicalName().isQuoted() ); assertNull( schema.locateTable( Identifier.toIdentifier( "my_table" ) ) ); - tableIdentifier = Identifier.toIdentifier( "`my_new_table`" ); - table.setTableName( tableIdentifier ); - assertEquals( "my_new_table", table.getLogicalName() ); - assertEquals( "my_new_table", table.getTableName().getName() ); - assertSame( table, schema.locateTable( Identifier.toIdentifier( "`my_new_table`" ) ) ); - assertNull( schema.locateTable( Identifier.toIdentifier( "`my_table`" ) ) ); - assertNull( schema.locateTable( Identifier.toIdentifier( "my_new_table" ) ) ); - tableIdentifier = Identifier.toIdentifier( "`my_newer_table`" ); - table.setTableName( tableIdentifier ); - assertEquals( "my_newer_table", table.getLogicalName() ); - assertEquals( "my_newer_table", table.getTableName().getName() ); - assertSame( table, schema.locateTable( Identifier.toIdentifier( "`my_newer_table`" ) ) ); - assertNull( schema.locateTable( Identifier.toIdentifier( "`my_new_table`" ) ) ); - assertNull( schema.locateTable( Identifier.toIdentifier( "my_newer_table" ) ) ); } @Test public void testInLineViewLogicalName() { Schema schema = new Schema( Identifier.toIdentifier( "schema" ), Identifier.toIdentifier( "`catalog`" ) ); - InLineView view = schema.createInLineView( "my_view", "select" ); - assertEquals( "my_view", view.getLogicalName() ); + InLineView view = schema.createInLineView( Identifier.toIdentifier( "my_view" ), "select" ); + assertEquals( "my_view", view.getLogicalName().getName() ); assertEquals( "select", view.getSelect() ); assertSame( view, schema.getInLineView( view.getLogicalName() ) ); } - - @Test - public void testLocateOrCreateTable() { - Schema schema = new Schema( Identifier.toIdentifier( "schema" ), Identifier.toIdentifier( "`catalog`" ) ); - Identifier tableIdentifier = Identifier.toIdentifier( "my_table" ); - Table table = schema.locateOrCreateTable( tableIdentifier ); - assertSame( tableIdentifier, table.getTableName() ); - assertSame( table, schema.locateOrCreateTable( tableIdentifier ) ); - } }