diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java index a8e7a46b09..cd0e904028 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java @@ -1844,36 +1844,64 @@ public class Binder { private TableSpecification createTable( final TableSpecificationSource tableSpecSource, - final DefaultNamingStrategy defaultNamingStrategy ) { + final DefaultNamingStrategy defaultNamingStrategy) { + final LocalBindingContext bindingContext = bindingContexts.peek(); final MappingDefaults mappingDefaults = bindingContext.getMappingDefaults(); + final String explicitCatalogName = tableSpecSource == null ? null : tableSpecSource.getExplicitCatalogName(); + final String explicitSchemaName = tableSpecSource == null ? null : tableSpecSource.getExplicitSchemaName(); final Schema.Name schemaName = new Schema.Name( - createIdentifier( tableSpecSource.getExplicitCatalogName(), mappingDefaults.getCatalogName() ), - createIdentifier( tableSpecSource.getExplicitSchemaName(), mappingDefaults.getSchemaName() ) + createIdentifier( explicitCatalogName, mappingDefaults.getCatalogName() ), + createIdentifier( explicitSchemaName, mappingDefaults.getSchemaName() ) ); final Schema schema = metadata.getDatabase().locateSchema( schemaName ); - if ( tableSpecSource instanceof TableSource ) { + + TableSpecification tableSpec = null; + if ( tableSpecSource == null ) { + if ( defaultNamingStrategy == null ) { + throw new MappingException( + "An explicit name must be specified for the table", + bindingContext.getOrigin() + ); + } + String tableName = defaultNamingStrategy.defaultName(); + tableSpec = createTableSpecification( bindingContext, schema, tableName ); + } + else if ( tableSpecSource instanceof TableSource ) { final TableSource tableSource = ( TableSource ) tableSpecSource; String tableName = tableSource.getExplicitTableName(); if ( tableName == null ) { if ( defaultNamingStrategy == null ) { - throw new MappingException( "An explicit name must be specified for the table", bindingContext.getOrigin() ); + throw new MappingException( + "An explicit name must be specified for the table", + bindingContext.getOrigin() + ); } tableName = defaultNamingStrategy.defaultName(); } - tableName = quotedIdentifier( tableName ); - final Identifier logicalTableId = Identifier.toIdentifier( tableName ); - tableName = quotedIdentifier( bindingContext.getNamingStrategy().tableName( tableName ) ); - final Identifier physicalTableId = Identifier.toIdentifier( tableName ); - final Table table = schema.locateTable( logicalTableId ); - return ( table == null ? schema.createTable( logicalTableId, physicalTableId ) : table ); + tableSpec = createTableSpecification( bindingContext, schema, tableName ); } - final InLineViewSource inLineViewSource = ( InLineViewSource ) tableSpecSource; - return schema.createInLineView( - Identifier.toIdentifier( inLineViewSource.getLogicalName() ), - inLineViewSource.getSelectStatement() - ); + else { + final InLineViewSource inLineViewSource = ( InLineViewSource ) tableSpecSource; + tableSpec = schema.createInLineView( + Identifier.toIdentifier( inLineViewSource.getLogicalName() ), + inLineViewSource.getSelectStatement() + ); + } + + return tableSpec; + } + + private TableSpecification createTableSpecification(LocalBindingContext bindingContext, Schema schema, String tableName) { + TableSpecification tableSpec; + tableName = quotedIdentifier( tableName ); + final Identifier logicalTableId = Identifier.toIdentifier( tableName ); + tableName = quotedIdentifier( bindingContext.getNamingStrategy().tableName( tableName ) ); + final Identifier physicalTableId = Identifier.toIdentifier( tableName ); + final Table table = schema.locateTable( logicalTableId ); + tableSpec = ( table == null ? schema.createTable( logicalTableId, physicalTableId ) : table ); + return tableSpec; } private String defaultCollectionElementJavaTypeName( diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/PluralAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/PluralAttributeSourceImpl.java index ff202ca03c..18dfe8891c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/PluralAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/PluralAttributeSourceImpl.java @@ -42,7 +42,6 @@ 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.Sortable; -import org.hibernate.metamodel.spi.source.TableSource; import org.hibernate.metamodel.spi.source.TableSpecificationSource; /** @@ -50,18 +49,18 @@ import org.hibernate.metamodel.spi.source.TableSpecificationSource; */ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderable, Sortable { - private final PluralAssociationAttribute attribute; + private final PluralAssociationAttribute associationAttribute; private final Nature nature; private final ExplicitHibernateTypeSource typeSource; private final PluralAttributeKeySource keySource; private final PluralAttributeElementSource elementSource; - public PluralAttributeSourceImpl(final PluralAssociationAttribute attribute) { - this.attribute = attribute; + public PluralAttributeSourceImpl(final PluralAssociationAttribute associationAttribute) { + this.associationAttribute = associationAttribute; this.nature = resolveAttributeNature(); - this.keySource = new PluralAttributeKeySourceImpl( attribute ); + this.keySource = new PluralAttributeKeySourceImpl( associationAttribute ); this.elementSource = determineElementSource(); - this.typeSource = new ExplicitHibernateTypeSourceImpl( attribute ); + this.typeSource = new ExplicitHibernateTypeSourceImpl( associationAttribute ); } @Override @@ -75,19 +74,19 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab } private PluralAttributeElementSource determineElementSource() { - switch ( attribute.getNature() ) { + switch ( associationAttribute.getNature() ) { case MANY_TO_MANY: - return new ManyToManyPluralAttributeElementSourceImpl( attribute ); + return new ManyToManyPluralAttributeElementSourceImpl( associationAttribute ); case MANY_TO_ANY: - return new ManyToAnyPluralAttributeElementSourceImpl( attribute ); + return new ManyToAnyPluralAttributeElementSourceImpl( associationAttribute ); case ONE_TO_MANY: - return new OneToManyPluralAttributeElementSourceImpl( attribute ); + return new OneToManyPluralAttributeElementSourceImpl( associationAttribute ); case ELEMENT_COLLECTION_BASIC: case ELEMENT_COLLECTION_EMBEDDABLE: { - return new BasicPluralAttributeElementSourceImpl( attribute ); + return new BasicPluralAttributeElementSourceImpl( associationAttribute ); } } - throw new AssertionError( "unexpected attribute nature" ); + throw new AssertionError( "Unexpected attribute nature for a association:" + associationAttribute.getNature() ); } @Override @@ -99,22 +98,13 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab public TableSpecificationSource getCollectionTableSpecificationSource() { // todo - see org.hibernate.metamodel.internal.Binder#bindOneToManyCollectionKey // todo - needs to cater for @CollectionTable and @JoinTable - return new TableSource() { - @Override - public String getExplicitSchemaName() { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - @Override - public String getExplicitCatalogName() { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - @Override - public String getExplicitTableName() { - return null; //To change body of implemented methods use File | Settings | File Templates. - } - }; + if ( associationAttribute.getJoinTableAnnotation() == null ) { + return null; + } + else { + return new TableSourceImpl( associationAttribute.getJoinTableAnnotation() ); + } } @Override @@ -124,57 +114,57 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab @Override public String getCollectionTableCheck() { - return attribute.getCheckCondition(); + return associationAttribute.getCheckCondition(); } @Override public Caching getCaching() { - return attribute.getCaching(); + return associationAttribute.getCaching(); } @Override public String getCustomPersisterClassName() { - return attribute.getCustomPersister(); + return associationAttribute.getCustomPersister(); } @Override public String getWhere() { - return attribute.getWhereClause(); + return associationAttribute.getWhereClause(); } @Override public boolean isInverse() { - return attribute.getMappedBy() != null; + return associationAttribute.getMappedBy() != null; } @Override public String getCustomLoaderName() { - return attribute.getCustomLoaderName(); + return associationAttribute.getCustomLoaderName(); } @Override public CustomSQL getCustomSqlInsert() { - return attribute.getCustomInsert(); + return associationAttribute.getCustomInsert(); } @Override public CustomSQL getCustomSqlUpdate() { - return attribute.getCustomUpdate(); + return associationAttribute.getCustomUpdate(); } @Override public CustomSQL getCustomSqlDelete() { - return attribute.getCustomDelete(); + return associationAttribute.getCustomDelete(); } @Override public CustomSQL getCustomSqlDeleteAll() { - return attribute.getCustomDeleteAll(); + return associationAttribute.getCustomDeleteAll(); } @Override public String getName() { - return attribute.getName(); + return associationAttribute.getName(); } @Override @@ -189,12 +179,12 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab @Override public String getPropertyAccessorName() { - return attribute.getAccessType(); + return associationAttribute.getAccessType(); } @Override public boolean isIncludedInOptimisticLocking() { - return attribute.isOptimisticLockable(); + return associationAttribute.isOptimisticLockable(); } @Override @@ -205,12 +195,12 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab @Override public FetchMode getFetchMode() { - return attribute.getFetchMode(); + return associationAttribute.getFetchMode(); } @Override public String getOrder() { - return attribute.getOrderBy(); + return associationAttribute.getOrderBy(); } @Override @@ -220,20 +210,20 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab @Override public String getComparatorName() { - return attribute.getComparatorName(); + return associationAttribute.getComparatorName(); } @Override public boolean isSorted() { - return attribute.isSorted(); + return associationAttribute.isSorted(); } @Override public FetchTiming getFetchTiming() { - if ( attribute.isExtraLazy() ) { + if ( associationAttribute.isExtraLazy() ) { return FetchTiming.EXTRA_DELAYED; } - if ( attribute.isLazy() ) { + if ( associationAttribute.isLazy() ) { return FetchTiming.DELAYED; } return FetchTiming.IMMEDIATE; @@ -241,17 +231,17 @@ public class PluralAttributeSourceImpl implements PluralAttributeSource, Orderab @Override public FetchStyle getFetchStyle() { - return attribute.getFetchStyle(); + return associationAttribute.getFetchStyle(); } private Nature resolveAttributeNature() { - if ( Map.class.isAssignableFrom( attribute.getAttributeType() ) ) { + if ( Map.class.isAssignableFrom( associationAttribute.getAttributeType() ) ) { return PluralAttributeSource.Nature.MAP; } - else if ( List.class.isAssignableFrom( attribute.getAttributeType() ) ) { + else if ( List.class.isAssignableFrom( associationAttribute.getAttributeType() ) ) { return PluralAttributeSource.Nature.LIST; } - else if ( Set.class.isAssignableFrom( attribute.getAttributeType() ) ) { + else if ( Set.class.isAssignableFrom( associationAttribute.getAttributeType() ) ) { return PluralAttributeSource.Nature.SET; } else { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/AssociationAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/AssociationAttribute.java index ed55d05aba..b0eb4a89f7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/AssociationAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/attribute/AssociationAttribute.java @@ -68,7 +68,7 @@ public class AssociationAttribute extends MappedAttribute { private final boolean mapsId; private final String referencedIdAttributeName; private final List joinColumnValues; - private final boolean definesExplicitJoinTable; + private final AnnotationInstance joinTableAnnotation; private AttributeTypeResolver resolver; public static AssociationAttribute createAssociationAttribute( @@ -119,7 +119,7 @@ public class AssociationAttribute extends MappedAttribute { this.referencedIdAttributeName = determineMapsId(); this.mapsId = referencedIdAttributeName != null; - this.definesExplicitJoinTable = determineExplicitJoinTable( annotations ); + this.joinTableAnnotation = determineExplicitJoinTable( annotations ); } public boolean isIgnoreNotFound() { @@ -162,8 +162,8 @@ public class AssociationAttribute extends MappedAttribute { return joinColumnValues; } - public boolean definesExplicitJoinTable() { - return definesExplicitJoinTable; + public AnnotationInstance getJoinTableAnnotation() { + return joinTableAnnotation; } @Override @@ -363,7 +363,8 @@ public class AssociationAttribute extends MappedAttribute { return joinColumns; } - private boolean determineExplicitJoinTable(Map> annotations) { + private AnnotationInstance determineExplicitJoinTable(Map> annotations) { + AnnotationInstance annotationInstance = null; AnnotationInstance collectionTableAnnotation = JandexHelper.getSingleAnnotation( annotations, JPADotNames.COLLECTION_TABLE @@ -389,6 +390,7 @@ public class AssociationAttribute extends MappedAttribute { getContext().getOrigin() ); } + annotationInstance = collectionTableAnnotation; } if ( joinTableAnnotation != null ) { @@ -400,9 +402,10 @@ public class AssociationAttribute extends MappedAttribute { getContext().getOrigin() ); } + annotationInstance = joinTableAnnotation; } - return collectionTableAnnotation != null || joinTableAnnotation != null; + return annotationInstance; } } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/ElementCollectionBindingTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/ElementCollectionBindingTest.java index 7680296ae1..99107ef51f 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/ElementCollectionBindingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/internal/source/annotations/entity/ElementCollectionBindingTest.java @@ -32,10 +32,17 @@ import javax.persistence.JoinTable; import org.junit.Test; +import org.hibernate.jaxb.spi.SourceType; +import org.hibernate.metamodel.spi.binding.EntityBinding; +import org.hibernate.metamodel.spi.binding.ListBinding; +import org.hibernate.metamodel.spi.relational.TableSpecification; import org.hibernate.metamodel.spi.source.MappingException; import org.hibernate.testing.junit4.BaseAnnotationBindingTestCase; import org.hibernate.testing.junit4.Resources; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.fail; + /** * Tests for different types of @ElementCollection mappings. * @@ -61,10 +68,17 @@ public class ElementCollectionBindingTest extends BaseAnnotationBindingTestCase } } - @Test(expected = MappingException.class) - @Resources(annotatedClasses = { TestEntity.class }) + @Test public void testElementCollectionWithJoinTableThrowsException() { - getEntityBinding( TestEntity.class ); + try { + sources.addAnnotatedClass( TestEntity.class ); + sources.buildMetadata(); + fail( "Invalid use of @JoinTable with @ElementCollection" ); + } + catch ( MappingException e ) { + assertEquals( "Unexpected error origin", TestEntity.class.getName(), e.getOrigin().getName() ); + assertEquals( "Unexpected type", SourceType.ANNOTATION, e.getOrigin().getType() ); + } } @Entity @@ -86,10 +100,70 @@ public class ElementCollectionBindingTest extends BaseAnnotationBindingTestCase } } - @Test(expected = MappingException.class) - @Resources(annotatedClasses = { TestEntity.class }) + @Test public void testCollectionTableAndJoinTableThrowsException() { - getEntityBinding( TestEntity.class ); + try { + sources.addAnnotatedClass( TestEntity2.class ); + sources.buildMetadata(); + fail( "Invalid use of @JoinTable AND @CollectionTable" ); + } + catch ( MappingException e ) { + assertEquals( "Unexpected error origin", TestEntity2.class.getName(), e.getOrigin().getName() ); + assertEquals( "Unexpected type", SourceType.ANNOTATION, e.getOrigin().getType() ); + } + } + + @Entity + class TestEntity3 { + @Id + private int id; + + @ElementCollection + private List strings; + + public int getId() { + return id; + } + + public List getStrings() { + return strings; + } + } + + @Test + @Resources(annotatedClasses = TestEntity3.class) + public void testDefaultJoinTableName() { + EntityBinding entityBinding = getEntityBinding( TestEntity3.class ); + ListBinding listBinding = (ListBinding) entityBinding.locateAttributeBinding( "strings" ); + TableSpecification tableSpec = listBinding.getPluralAttributeKeyBinding().getCollectionTable(); + assertEquals( "Wrong default collection table name", "ElementCollectionBindingTest$TestEntity3_strings", tableSpec.getLogicalName().getText() ); + } + + @Entity + class TestEntity4 { + @Id + private int id; + + @ElementCollection + @CollectionTable(name = "STRING_COLLECTION") + private List strings; + + public int getId() { + return id; + } + + public List getStrings() { + return strings; + } + } + + @Test + @Resources(annotatedClasses = TestEntity4.class) + public void testExplicitJoinTableName() { + EntityBinding entityBinding = getEntityBinding( TestEntity4.class ); + ListBinding listBinding = (ListBinding) entityBinding.locateAttributeBinding( "strings" ); + TableSpecification tableSpec = listBinding.getPluralAttributeKeyBinding().getCollectionTable(); + assertEquals( "Wrong default collection table name", "STRING_COLLECTION", tableSpec.getLogicalName().getText() ); } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseAnnotationBindingTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseAnnotationBindingTestCase.java index 53e049fc0f..3e073fe6ab 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseAnnotationBindingTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseAnnotationBindingTestCase.java @@ -29,8 +29,8 @@ import java.util.List; import org.junit.After; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.MethodRule; -import org.junit.runners.model.FrameworkMethod; +import org.junit.rules.TestRule; +import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.hibernate.metamodel.MetadataSources; @@ -47,10 +47,10 @@ public abstract class BaseAnnotationBindingTestCase extends BaseUnitTestCase { protected List> annotatedClasses = new ArrayList>(); @Rule - public MethodRule buildMetaData = new MethodRule() { + public TestRule buildMetaData = new TestRule() { @Override - public Statement apply(final Statement statement, FrameworkMethod frameworkMethod, Object o) { - return new KeepSetupFailureStatement( statement, frameworkMethod ); + public Statement apply(Statement base, Description description) { + return new KeepSetupFailureStatement( base, description ); } }; @@ -74,13 +74,13 @@ public abstract class BaseAnnotationBindingTestCase extends BaseUnitTestCase { class KeepSetupFailureStatement extends Statement { private final Statement origStatement; - private final FrameworkMethod origFrameworkMethod; + private final Description description; private Throwable setupError; private boolean expectedException; - KeepSetupFailureStatement(Statement statement, FrameworkMethod frameworkMethod) { + KeepSetupFailureStatement(Statement statement, Description description) { this.origStatement = statement; - this.origFrameworkMethod = frameworkMethod; + this.description = description; } @Override @@ -104,10 +104,10 @@ public abstract class BaseAnnotationBindingTestCase extends BaseUnitTestCase { } } - private void createBindings() throws Throwable { + private void createBindings() { try { sources = new MetadataSources( new ServiceRegistryBuilder().buildServiceRegistry() ); - Resources resourcesAnnotation = origFrameworkMethod.getAnnotation( Resources.class ); + Resources resourcesAnnotation = description.getAnnotation( Resources.class ); if ( resourcesAnnotation != null ) { sources.getMetadataBuilder().with( resourcesAnnotation.cacheMode() ); @@ -123,11 +123,10 @@ public abstract class BaseAnnotationBindingTestCase extends BaseUnitTestCase { } catch ( final Throwable t ) { setupError = t; - Test testAnnotation = origFrameworkMethod.getAnnotation( Test.class ); + Test testAnnotation = description.getAnnotation( Test.class ); Class expected = testAnnotation.expected(); if ( t.getClass().equals( expected ) ) { expectedException = true; - return; } } }