From 0eb87b73b948d518fd01e09b1bcf818efe2997f5 Mon Sep 17 00:00:00 2001 From: Strong Liu Date: Wed, 15 Jun 2011 16:18:52 +0800 Subject: [PATCH] HHH-6287 bind @Table.uniqueConstraints --- .../AbstractTableSpecification.java | 20 +++-- .../hibernate/metamodel/relational/Table.java | 23 ++++-- .../relational/TableSpecification.java | 4 +- .../relational/state/ValueCreator.java | 4 +- .../annotations/entity/EntityBinder.java | 41 +++++++++- .../binding/SimpleValueBindingTests.java | 2 +- .../relational/TableManipulationTests.java | 10 +-- .../entity/BatchSizeBindingTests.java | 2 +- .../entity/UniqueConstraintBindingTests.java | 81 +++++++++++++++++++ 9 files changed, 161 insertions(+), 26 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/UniqueConstraintBindingTests.java diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/relational/AbstractTableSpecification.java b/hibernate-core/src/main/java/org/hibernate/metamodel/relational/AbstractTableSpecification.java index 3bf0240425..32b504c11b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/relational/AbstractTableSpecification.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/relational/AbstractTableSpecification.java @@ -24,6 +24,8 @@ package org.hibernate.metamodel.relational; import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -34,26 +36,32 @@ import java.util.List; * @author Steve Ebersole */ public abstract class AbstractTableSpecification implements TableSpecification, ValueContainer { - private final LinkedHashSet values = new LinkedHashSet(); + private final LinkedHashMap values = new LinkedHashMap(); private PrimaryKey primaryKey = new PrimaryKey( this ); private List foreignKeys = new ArrayList(); @Override public Iterable values() { - return values; + return values.values(); } @Override - public Column createColumn(String name) { + public Column getOrCreateColumn(String name) { + if(values.containsKey( name )){ + return (Column) values.get( name ); + } final Column column = new Column( this, values.size(), name ); - values.add( column ); + values.put(name, column ); return column; } @Override - public DerivedValue createDerivedValue(String fragment) { + public DerivedValue getOrCreateDerivedValue(String fragment) { + if(values.containsKey( fragment )){ + return (DerivedValue) values.get( fragment ); + } final DerivedValue value = new DerivedValue( this, values.size(), fragment ); - values.add( value ); + values.put(fragment, value ); return value; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/relational/Table.java b/hibernate-core/src/main/java/org/hibernate/metamodel/relational/Table.java index d0a19a47cb..190b790fb9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/relational/Table.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/relational/Table.java @@ -25,6 +25,7 @@ package org.hibernate.metamodel.relational; import java.util.ArrayList; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Set; @@ -39,8 +40,8 @@ public class Table extends AbstractTableSpecification implements ValueContainer, private final Identifier tableName; private final String qualifiedName; - private List indexes; - private List uniqueKeys; + private LinkedHashMap indexes; + private LinkedHashMap uniqueKeys; private List checkConstraints; private Set comments; @@ -81,29 +82,35 @@ public class Table extends AbstractTableSpecification implements ValueContainer, @Override public Iterable getIndexes() { - return indexes; + return indexes.values(); } public Index getOrCreateIndex(String name) { + if(indexes!=null && indexes.containsKey( name )){ + return indexes.get( name ); + } Index index = new Index( this, name ); if ( indexes == null ) { - indexes = new ArrayList(); + indexes = new LinkedHashMap(); } - indexes.add( index ); + indexes.put(name, index ); return index; } @Override public Iterable getUniqueKeys() { - return uniqueKeys; + return uniqueKeys.values(); } public UniqueKey getOrCreateUniqueKey(String name) { + if(uniqueKeys!=null && uniqueKeys.containsKey( name )){ + return uniqueKeys.get( name ); + } UniqueKey uniqueKey = new UniqueKey( this, name ); if ( uniqueKeys == null ) { - uniqueKeys = new ArrayList(); + uniqueKeys = new LinkedHashMap(); } - uniqueKeys.add( uniqueKey ); + uniqueKeys.put(name, uniqueKey ); return uniqueKey; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/relational/TableSpecification.java b/hibernate-core/src/main/java/org/hibernate/metamodel/relational/TableSpecification.java index c6b7d81eb4..c786169265 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/relational/TableSpecification.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/relational/TableSpecification.java @@ -50,7 +50,7 @@ public interface TableSpecification extends ValueContainer, Loggable { * * @return The generated column */ - public Column createColumn(String name); + public Column getOrCreateColumn(String name); /** * Factory method for creating a {@link Column} associated with this container. @@ -68,7 +68,7 @@ public interface TableSpecification extends ValueContainer, Loggable { * * @return The generated value. */ - public DerivedValue createDerivedValue(String fragment); + public DerivedValue getOrCreateDerivedValue(String fragment); public Iterable getForeignKeys(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/relational/state/ValueCreator.java b/hibernate-core/src/main/java/org/hibernate/metamodel/relational/state/ValueCreator.java index 58439d563f..3c5963c5b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/relational/state/ValueCreator.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/relational/state/ValueCreator.java @@ -54,14 +54,14 @@ public class ValueCreator { if ( columnName == null ) { throw new IllegalArgumentException( "columnName must be non-null." ); } - Column value = table.createColumn( columnName ); + Column value = table.getOrCreateColumn( columnName ); value.initialize( state, forceNonNullable, forceUnique ); return value; } public static DerivedValue createDerivedValue(TableSpecification table, DerivedValueRelationalState state) { - return table.createDerivedValue( state.getFormula() ); + return table.getOrCreateDerivedValue( state.getFormula() ); } public static SimpleValue createSimpleValue(TableSpecification table, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityBinder.java index f9d8c8af77..e9bc782107 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/entity/EntityBinder.java @@ -57,6 +57,8 @@ import org.hibernate.metamodel.domain.Entity; import org.hibernate.metamodel.domain.Hierarchical; import org.hibernate.metamodel.relational.Identifier; import org.hibernate.metamodel.relational.Schema; +import org.hibernate.metamodel.relational.TableSpecification; +import org.hibernate.metamodel.relational.UniqueKey; import org.hibernate.metamodel.source.annotations.HibernateDotNames; import org.hibernate.metamodel.source.annotations.JPADotNames; import org.hibernate.metamodel.source.annotations.entity.state.binding.AttributeBindingStateImpl; @@ -116,12 +118,49 @@ public class EntityBinder { // bind all attributes - simple as well as associations bindAttributes( entityBinding ); - + bindTableUniqueConstraints( entityBinding ); // last, but not least we initialize and register the new EntityBinding entityBinding.initialize( entityBindingState ); meta.addEntity( entityBinding ); } + private void bindTableUniqueConstraints(EntityBinding entityBinding) { + AnnotationInstance tableAnnotation = JandexHelper.getSingleAnnotation( + configuredClass.getClassInfo(), + JPADotNames.TABLE + ); + if ( tableAnnotation == null ) { + return; + } + TableSpecification table = entityBinding.getBaseTable(); + bindUniqueConstraints( tableAnnotation, table ); + } + + /** + * Bind {@link javax.persistence.UniqueConstraint} to table as a {@link UniqueKey} + * + * @param tableAnnotation JPA annotations which has a {@code uniqueConstraints} attribute. + * @param table Table which the UniqueKey bind to. + */ + private void bindUniqueConstraints(AnnotationInstance tableAnnotation,TableSpecification table) { + AnnotationValue value = tableAnnotation.value( "uniqueConstraints" ); + if ( value == null ) { + return; + } + AnnotationInstance[] uniqueConstraints = value.asNestedArray(); + for ( AnnotationInstance unique : uniqueConstraints ) { + String name = unique.value( "name" ).asString(); + UniqueKey uniqueKey = table.getOrCreateUniqueKey( name ); + String[] columnNames = unique.value( "columnNames" ).asStringArray(); + if ( columnNames.length == 0 ) { + //todo throw exception? + } + for ( String columnName : columnNames ) { + uniqueKey.addColumn( table.getOrCreateColumn( columnName ) ); + } + } + } + private void bindInheritance(EntityBinding entityBinding) { entityBinding.setInheritanceType( configuredClass.getInheritanceType() ); switch ( configuredClass.getInheritanceType() ) { diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/binding/SimpleValueBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/binding/SimpleValueBindingTests.java index e16f66ab75..79459607eb 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/binding/SimpleValueBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/binding/SimpleValueBindingTests.java @@ -64,7 +64,7 @@ public class SimpleValueBindingTests extends BaseUnitTestCase { entityBinding.getEntityIdentifier().setValueBinding( attributeBinding ); - Column idColumn = table.createColumn( "id" ); + Column idColumn = table.getOrCreateColumn( "id" ); idColumn.setDatatype( BIGINT ); idColumn.setSize( Size.precision( 18, 0 ) ); table.getPrimaryKey().addColumn( idColumn ); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/relational/TableManipulationTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/relational/TableManipulationTests.java index d2b7d44175..6e453ad5c5 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/relational/TableManipulationTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/relational/TableManipulationTests.java @@ -52,7 +52,7 @@ public class TableManipulationTests extends BaseUnitTestCase { assertNull( table.getPrimaryKey().getName() ); assertFalse( table.values().iterator().hasNext() ); - Column idColumn = table.createColumn( "id" ); + Column idColumn = table.getOrCreateColumn( "id" ); idColumn.setDatatype( INTEGER ); idColumn.setSize( Size.precision( 18, 0 ) ); table.getPrimaryKey().addColumn( idColumn ); @@ -60,7 +60,7 @@ public class TableManipulationTests extends BaseUnitTestCase { assertEquals( "my_table_pk", table.getPrimaryKey().getName() ); assertEquals( "my_table.PK", table.getPrimaryKey().getExportIdentifier() ); - Column col_1 = table.createColumn( "col_1" ); + Column col_1 = table.getOrCreateColumn( "col_1" ); col_1.setDatatype( VARCHAR ); col_1.setSize( Size.length( 512 ) ); @@ -90,7 +90,7 @@ public class TableManipulationTests extends BaseUnitTestCase { Schema schema = new Schema( null, null ); Table book = schema.createTable( Identifier.toIdentifier( "BOOK" ) ); - Column bookId = book.createColumn( "id" ); + Column bookId = book.getOrCreateColumn( "id" ); bookId.setDatatype( INTEGER ); bookId.setSize( Size.precision( 18, 0 ) ); book.getPrimaryKey().addColumn( bookId ); @@ -98,13 +98,13 @@ public class TableManipulationTests extends BaseUnitTestCase { Table page = schema.createTable( Identifier.toIdentifier( "PAGE" ) ); - Column pageId = page.createColumn( "id" ); + Column pageId = page.getOrCreateColumn( "id" ); pageId.setDatatype( INTEGER ); pageId.setSize( Size.precision( 18, 0 ) ); page.getPrimaryKey().addColumn( pageId ); page.getPrimaryKey().setName( "PAGE_PK" ); - Column pageBookId = page.createColumn( "BOOK_ID" ); + Column pageBookId = page.getOrCreateColumn( "BOOK_ID" ); pageId.setDatatype( INTEGER ); pageId.setSize( Size.precision( 18, 0 ) ); ForeignKey pageBookFk = page.createForeignKey( book, "PAGE_BOOK_FK" ); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/BatchSizeBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/BatchSizeBindingTests.java index 2e75a762f8..0cb638aa9e 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/BatchSizeBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/BatchSizeBindingTests.java @@ -1,7 +1,7 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Inc. diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/UniqueConstraintBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/UniqueConstraintBindingTests.java new file mode 100644 index 0000000000..c76ecb4b31 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/UniqueConstraintBindingTests.java @@ -0,0 +1,81 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ + +package org.hibernate.metamodel.source.annotations.entity; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import org.junit.Test; + +import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.relational.Column; +import org.hibernate.metamodel.relational.TableSpecification; +import org.hibernate.metamodel.relational.UniqueKey; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; + +/** + * test for {@link javax.persistence.UniqueConstraint} + * + * @author Strong Liu + */ +public class UniqueConstraintBindingTests extends BaseAnnotationBindingTestCase { + @Test + public void testTableUniqueconstraints() { + buildMetadataSources( TableWithUniqueConstraint.class ); + EntityBinding binding = getEntityBinding( TableWithUniqueConstraint.class ); + TableSpecification table = binding.getBaseTable(); + Iterable uniqueKeyIterable = table.getUniqueKeys(); + assertNotNull( uniqueKeyIterable ); + int i = 0; + for ( UniqueKey key : uniqueKeyIterable ) { + i++; + assertEquals( "u1", key.getName() ); + assertTrue( table == key.getTable() ); + assertNotNull( key.getColumns() ); + int j = 0; + for ( Column column : key.getColumns() ) { + j++; + + } + assertEquals( 2, j ); + } + assertEquals( 1, i ); + } + + + @Entity + @Table(uniqueConstraints = { @UniqueConstraint(name = "u1", columnNames = { "name", "age" }) }) + class TableWithUniqueConstraint { + @Id + int id; + String name; + int age; + } +}