diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java index 52d9e8bfb2..446fc52a45 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java @@ -97,6 +97,8 @@ public class AnnotatedColumn { private AnnotatedColumns parent; + private String options; + public AnnotatedColumns getParent() { return parent; } @@ -263,6 +265,8 @@ public class AnnotatedColumn { for ( CheckConstraint constraint : checkConstraints ) { mappingColumn.addCheckConstraint( constraint ); } + mappingColumn.setOptions( options ); + // if ( isNotEmpty( comment ) ) { // mappingColumn.setComment( comment ); // } @@ -313,6 +317,7 @@ public class AnnotatedColumn { mappingColumn.addCheckConstraint( constraint ); } mappingColumn.setDefaultValue( defaultValue ); + mappingColumn.setOptions( options ); if ( writeExpression != null ) { final int numberOfJdbcParams = StringHelper.count( writeExpression, '?' ); @@ -806,6 +811,7 @@ public class AnnotatedColumn { annotatedColumn.applyColumnDefault( inferredData, numberOfColumns ); annotatedColumn.applyGeneratedAs( inferredData, numberOfColumns ); annotatedColumn.applyColumnCheckConstraint( column ); + annotatedColumn.applyColumnOptions( column ); annotatedColumn.applyCheckConstraint( inferredData, numberOfColumns ); annotatedColumn.extractDataFromPropertyData( propertyHolder, inferredData ); annotatedColumn.bind(); @@ -1052,4 +1058,13 @@ public class AnnotatedColumn { MetadataBuildingContext getBuildingContext() { return getParent().getBuildingContext(); } + + private void applyColumnOptions(AnnotationUsage column) { + options = column.findAttributeValue( "options" ); + } + + void setOptions(String options){ + this.options = options; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java index 96bd3a6058..e04c76f07e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedDiscriminatorColumn.java @@ -75,6 +75,7 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn { column.setLogicalColumnName( discriminatorColumn.getString( "name" ) ); } column.setNullable( false ); + column.setOptions( discriminatorColumn.getString( "options" ) ); } else { discriminatorType = DiscriminatorType.STRING; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java index 0ac73e6844..c06673aeaf 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java @@ -196,6 +196,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { setUpdatable( joinColumn.getBoolean( "updatable" ) ); setReferencedColumn( joinColumn.getString( "referencedColumnName" ) ); applyColumnCheckConstraint( joinColumn ); + setOptions( joinColumn.getString( "options" ) ); final String table = joinColumn.getString( "table" ); if ( table.isEmpty() ) { @@ -237,15 +238,18 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { final String columnName; final String columnDefinition; final String referencedColumnName; + final String options; if ( primaryKeyJoinColumn != null ) { columnName = primaryKeyJoinColumn.getString( "name" ); columnDefinition = primaryKeyJoinColumn.getString( "columnDefinition" ); referencedColumnName = primaryKeyJoinColumn.getString( "referencedColumnName" ); + options = primaryKeyJoinColumn.getString( "options" ); } else { columnName = joinColumn.getString( "name" ); columnDefinition = joinColumn.getString( "columnDefinition" ); referencedColumnName = joinColumn.getString( "referencedColumnName" ); + options = joinColumn.getString( "options" ); } final ObjectNameNormalizer normalizer = context.getObjectNameNormalizer(); @@ -261,6 +265,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { // column.setPropertyHolder(propertyHolder); // column.setJoins(joins); // column.setContext( context ); + column.setOptions( options ); column.setImplicit( false ); column.setNullable( false ); column.setParent( parent ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java index a3e9da2a9b..82410bcf90 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java @@ -647,12 +647,10 @@ public abstract class CollectionBinder { } final List> mapKeyJoinColumns = property.getAnnotationUsage( MapKeyJoinColumns.class ).getList( "value" ); final List> joinKeyColumns = CollectionHelper.arrayList( mapKeyJoinColumns.size() ); - int index = 0; for ( AnnotationUsage mapKeyJoinColumn : mapKeyJoinColumns ) { final MutableAnnotationUsage joinColumn = MapKeyJoinColumnDelegator.fromMapKeyJoinColumn( mapKeyJoinColumn, property, context ); joinKeyColumns.add( joinColumn ); - index++; } return joinKeyColumns; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ColumnsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ColumnsBuilder.java index 9ad20c8aef..3da5a9b16b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ColumnsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ColumnsBuilder.java @@ -6,7 +6,6 @@ */ package org.hibernate.boot.model.internal; -import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; @@ -25,10 +24,8 @@ import org.hibernate.models.spi.MemberDetails; import org.hibernate.models.spi.MutableAnnotationUsage; import org.hibernate.models.spi.SourceModelBuildingContext; -import jakarta.persistence.CheckConstraint; import jakarta.persistence.Column; import jakarta.persistence.ElementCollection; -import jakarta.persistence.ForeignKey; import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumns; import jakarta.persistence.JoinTable; @@ -361,77 +358,4 @@ class ColumnsBuilder { } } - @SuppressWarnings("ClassExplicitlyAnnotation") - private static final class JoinColumnAdapter implements JoinColumn { - private final PrimaryKeyJoinColumn column; - - public JoinColumnAdapter(PrimaryKeyJoinColumn column) { - this.column = column; - } - - @Override - public String name() { - return column.name(); - } - - @Override - public String referencedColumnName() { - return column.referencedColumnName(); - } - - @Override - public boolean unique() { - return false; - } - - @Override - public boolean nullable() { - return false; - } - - @Override - public boolean insertable() { - return false; - } - - @Override - public boolean updatable() { - return false; - } - - @Override - public String columnDefinition() { - return column.columnDefinition(); - } - - @Override - public String table() { - return ""; - } - - @Override - public String options() { - return column.options(); - } - - @Override - public String comment() { - return ""; - } - - @Override - public ForeignKey foreignKey() { - return column.foreignKey(); - } - - @Override - public CheckConstraint[] check() { - return new CheckConstraint[0]; - } - - @Override - public Class annotationType() { - return JoinColumn.class; - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexColumn.java index 940d292208..a6f312a250 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexColumn.java @@ -114,6 +114,7 @@ public class IndexColumn extends AnnotatedColumn { // column.setJoins( secondaryTables ); column.setInsertable( orderColumn.getBoolean( "insertable" ) ); column.setUpdatable( orderColumn.getBoolean( "updatable" ) ); + column.setOptions( orderColumn.getString( "options" ) ); // column.setContext( context ); // column.setPropertyHolder( propertyHolder ); createParent( propertyHolder, secondaryTables, column, context ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java index d4fb79c34d..c9b77a71a4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java @@ -592,6 +592,10 @@ public class ManagedTypeProcessor { xmlDocumentContext ); + XmlAnnotationHelper.applyPrimaryKeyJoinColumns( + jaxbEntity, classDetails, xmlDocumentContext + ); + renderClass( classDetails, xmlDocumentContext ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java index e317481ceb..d78b2ecdb8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java @@ -52,6 +52,7 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbDiscriminatorColumnImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbDiscriminatorFormulaImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbElementCollectionImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntity; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListenerContainerImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityOrMappedSuperclass; import org.hibernate.boot.jaxb.mapping.spi.JaxbGeneratedValueImpl; @@ -66,6 +67,7 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbNationalizedImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbNaturalId; import org.hibernate.boot.jaxb.mapping.spi.JaxbNotFoundCapable; import org.hibernate.boot.jaxb.mapping.spi.JaxbPluralAttribute; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPrimaryKeyJoinColumnImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbSchemaAware; import org.hibernate.boot.jaxb.mapping.spi.JaxbSecondaryTableImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbSequenceGeneratorImpl; @@ -123,6 +125,7 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.IdClass; import jakarta.persistence.Index; import jakarta.persistence.Inheritance; +import jakarta.persistence.PrimaryKeyJoinColumns; import jakarta.persistence.SecondaryTable; import jakarta.persistence.SecondaryTables; import jakarta.persistence.SequenceGenerator; @@ -1539,4 +1542,30 @@ public class XmlAnnotationHelper { values.add( tableAnn ); } } + + public static void applyPrimaryKeyJoinColumns( + JaxbEntityImpl jaxbEntity, + MutableClassDetails classDetails, + XmlDocumentContext xmlDocumentContext) { + List primaryKeyJoinColumns = jaxbEntity.getPrimaryKeyJoinColumns(); + if ( CollectionHelper.isEmpty( primaryKeyJoinColumns ) ) { + return; + } + + final SourceModelBuildingContext modelBuildingContext = xmlDocumentContext.getModelBuildingContext(); + final MutableAnnotationUsage primaryKeyJoinColumnsAnnotationUsage = classDetails.replaceAnnotationUsage( + JpaAnnotations.PRIMARY_KEY_JOIN_COLUMN, + JpaAnnotations.PRIMARY_KEY_JOIN_COLUMNS, + modelBuildingContext + ); + + final ArrayList primaryKeyJoinColumnList = arrayList( primaryKeyJoinColumns.size() ); + primaryKeyJoinColumnsAnnotationUsage.setAttributeValue( "value", primaryKeyJoinColumnList ); + + for ( JaxbPrimaryKeyJoinColumnImpl primaryKeyJoinColumn : primaryKeyJoinColumns ) { + primaryKeyJoinColumnList.add( + JoinColumnProcessing.createPrimaryKeyJoinColumnUsage( primaryKeyJoinColumn, xmlDocumentContext ) + ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/db/JoinColumnProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/db/JoinColumnProcessing.java index 4e82ff80ad..c3d04f9a14 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/db/JoinColumnProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/db/JoinColumnProcessing.java @@ -194,28 +194,10 @@ public class JoinColumnProcessing { final List> columnUsages = CollectionHelper.arrayList( jaxbJoinColumns.size() ); - jaxbJoinColumns.forEach( (jaxbJoinColumn) -> { - final MutableAnnotationUsage columnUsage = - JpaAnnotations.PRIMARY_KEY_JOIN_COLUMN.createUsage( xmlDocumentContext.getModelBuildingContext() ); - columnUsages.add( columnUsage ); - - ColumnProcessing.applyColumnDetails( - jaxbJoinColumn, - (MutableAnnotationUsage) columnUsage, - xmlDocumentContext - ); - XmlAnnotationHelper.applyOptionalAttribute( - columnUsage, - "referencedColumnName", - ((JaxbColumnJoined) jaxbJoinColumn).getReferencedColumnName() - ); - - ForeignKeyProcessing.applyForeignKey( - ( (JaxbColumnJoined) jaxbJoinColumn ).getForeignKey(), - (MutableAnnotationUsage) columnUsage, - xmlDocumentContext - ); - } ); + jaxbJoinColumns.forEach( + (jaxbJoinColumn) -> + columnUsages.add( createPrimaryKeyJoinColumnUsage( jaxbJoinColumn, xmlDocumentContext ) ) + ); tableAnn.setAttributeValue( "pkJoinColumns", @@ -223,4 +205,30 @@ public class JoinColumnProcessing { ); } + public static MutableAnnotationUsage createPrimaryKeyJoinColumnUsage( + JaxbPrimaryKeyJoinColumnImpl jaxbJoinColumn, + XmlDocumentContext xmlDocumentContext) { + final MutableAnnotationUsage columnUsage = + JpaAnnotations.PRIMARY_KEY_JOIN_COLUMN.createUsage( xmlDocumentContext.getModelBuildingContext() ); + + ColumnProcessing.applyColumnDetails( + jaxbJoinColumn, + (MutableAnnotationUsage) columnUsage, + xmlDocumentContext + ); + + XmlAnnotationHelper.applyOptionalAttribute( + columnUsage, + "referencedColumnName", + ((JaxbColumnJoined) jaxbJoinColumn ).getReferencedColumnName() + ); + + ForeignKeyProcessing.applyForeignKey( + ( (JaxbColumnJoined) jaxbJoinColumn ).getForeignKey(), + (MutableAnnotationUsage) columnUsage, + xmlDocumentContext + ); + return columnUsage; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java index 71a3034eb3..9dd099dd76 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java @@ -80,6 +80,7 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn private Size columnSize; private String collation; private java.util.List checkConstraints = new ArrayList<>(); + private String options; public Column() { } @@ -788,6 +789,14 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn return quoted ? name : name.toLowerCase( Locale.ROOT ); } + public String getOptions() { + return options; + } + + public void setOptions(String options) { + this.options = options; + } + /** * Shallow copy, the value is not copied */ @@ -817,6 +826,7 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn copy.customWrite = customWrite; // copy.specializedTypeDeclaration = specializedTypeDeclaration; copy.columnSize = columnSize; + copy.options = options; return copy; } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnDefinitions.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnDefinitions.java index 46ef3f07ef..dc8db23f59 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnDefinitions.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnDefinitions.java @@ -10,6 +10,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.Size; +import org.hibernate.internal.util.StringHelper; import org.hibernate.mapping.CheckConstraint; import org.hibernate.mapping.Column; import org.hibernate.mapping.Constraint; @@ -111,6 +112,14 @@ class ColumnDefinitions { appendColumnDefinition( statement, column, metadata, dialect ); appendComment( statement, column, dialect ); appendConstraints( statement, column, table, dialect, context ); + appendOptions(statement, column, dialect); + } + + private static void appendOptions(StringBuilder statement, Column column, Dialect dialect) { + final String options = column.getOptions(); + if ( StringHelper.isNotEmpty( options ) ) { + statement.append( " " ).append( options ); + } } private static void appendConstraints( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/columnoptions/AnotherTestEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/columnoptions/AnotherTestEntity.java new file mode 100644 index 0000000000..607e260dd6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/columnoptions/AnotherTestEntity.java @@ -0,0 +1,18 @@ +package org.hibernate.orm.test.schemaupdate.columnoptions; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.PrimaryKeyJoinColumn; +import jakarta.persistence.PrimaryKeyJoinColumns; +import jakarta.persistence.Table; + +@Entity +@Table(name = "ANOTHER_TEST_ENTITY") +@PrimaryKeyJoinColumns( + value = @PrimaryKeyJoinColumn(name = "joined_fk", options = ColumnOptionsTest.PRIMARY_KEY_JOIN_COLUMN_OPTIONS) +) +public class AnotherTestEntity extends TestEntity { + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/columnoptions/ColumnOptionsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/columnoptions/ColumnOptionsTest.java new file mode 100644 index 0000000000..00d9668cb8 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/columnoptions/ColumnOptionsTest.java @@ -0,0 +1,333 @@ +package org.hibernate.orm.test.schemaupdate.columnoptions; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.Locale; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.schema.TargetType; + +import org.hibernate.testing.orm.junit.BaseUnitTest; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.util.ServiceRegistryUtil; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@BaseUnitTest +@JiraKey("HHH-18057") +public class ColumnOptionsTest { + static final String COLUMN_NAME = "NAME"; + static final String COLUMN_OPTIONS = "option_1"; + + static final String DISCRIMINATOR_COLUMN_NAME = "DISC_COLUMN"; + static final String DISCRIMINATOR_COLUMN_OPTIONS = "option_2"; + + static final String PRIMARY_KEY_JOIN_COLUMN_NAME = "PRIMARY_KEY_COLUMN"; + static final String PRIMARY_KEY_JOIN_COLUMN_OPTIONS = "option_3"; + + static final String JOIN_COLUMN_NAME = "JOIN_COLUMN"; + static final String JOIN_COLUMN_OPTIONS = "option_4"; + + static final String ELEMENT_COLLECTION_MAP_KEY_COLUMN_NAME = "MAP_KEY_COLUMN"; + static final String ELEMENT_COLLECTION_MAP_KEY_COLUMN_OPTIONS = "option_5"; + + static final String ELEMENT_COLLECTION_MAP_KEY_JOIN_COLUMN_NAME = "MAP_KEY_JOIN_COLUMN"; + static final String ELEMENT_COLLECTION_MAP_KEY_JOIN_COLUMN_OPTIONS = "option_6"; + + static final String ONE_TO_MANY_MAP_KEY_COLUMN_NAME = "MAP_KEY_COLUMN_2"; + static final String ONE_TO_MANY_MAP_KEY_COLUMN_OPTIONS = "option_7"; + + static final String ONE_TO_MANY_MAP_KEY_JOIN_COLUMN_NAME = "MAP_KEY_JOIN_COLUMN_2"; + static final String ONE_TO_MANY_MAP_KEY_JOIN_COLUMN_OPTIONS = "option_8"; + + static final String MANY_TO_MANY_MAP_KEY_COLUMN_NAME = "MAP_KEY_COLUMN_3"; + static final String MANY_TO_MANY_MAP_KEY_COLUMN_OPTIONS = "option_9"; + + static final String MANY_TO_MANY_MAP_KEY_JOIN_COLUMN_NAME = "MAP_KEY_JOIN_COLUMN_3"; + static final String MANY_TO_MANY_MAP_KEY_JOIN_COLUMN_OPTIONS = "option__10"; + + static final String ORDER_COLUMN_NAME = "ORDER_COLUMN"; + static final String ORDER_COLUMN_OPTIONS = "option__11"; + + private File output; + private StandardServiceRegistry ssr; + private MetadataImplementor metadata; + + @BeforeEach + public void setUp() throws IOException { + output = File.createTempFile( "update_script", ".sql" ); + output.deleteOnExit(); + ssr = ServiceRegistryUtil.serviceRegistry(); + } + + @AfterEach + public void tearsDown() { + output.delete(); + StandardServiceRegistryBuilder.destroy( ssr ); + } + + @Test + public void testTableCommentAreCreated() throws Exception { + createSchema( TestEntity.class, AnotherTestEntity.class ); + assertTrue( + tableCreationStatementContainsOptions( output, COLUMN_NAME, COLUMN_OPTIONS ), + "Column " + COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + DISCRIMINATOR_COLUMN_NAME, + DISCRIMINATOR_COLUMN_OPTIONS + ), + "DiscriminatorColumn " + DISCRIMINATOR_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( output, JOIN_COLUMN_NAME, JOIN_COLUMN_OPTIONS ), + "JoinColumn " + JOIN_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ELEMENT_COLLECTION_MAP_KEY_COLUMN_NAME, + ELEMENT_COLLECTION_MAP_KEY_COLUMN_OPTIONS + ), + "ElementCollection MapKeyColumn " + ELEMENT_COLLECTION_MAP_KEY_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ONE_TO_MANY_MAP_KEY_COLUMN_NAME, + ONE_TO_MANY_MAP_KEY_COLUMN_OPTIONS + ), + "OneToMany MapKeyColumn " + ONE_TO_MANY_MAP_KEY_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + MANY_TO_MANY_MAP_KEY_COLUMN_NAME, + MANY_TO_MANY_MAP_KEY_COLUMN_OPTIONS + ), + "ManyToMany MapKeyColumn " + MANY_TO_MANY_MAP_KEY_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ONE_TO_MANY_MAP_KEY_COLUMN_NAME, + ONE_TO_MANY_MAP_KEY_COLUMN_OPTIONS + ), + "OneToMany MapKeyColumn " + ONE_TO_MANY_MAP_KEY_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + PRIMARY_KEY_JOIN_COLUMN_NAME, + PRIMARY_KEY_JOIN_COLUMN_OPTIONS + ), + "PrimaryKeyJoinColumn " + PRIMARY_KEY_JOIN_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ELEMENT_COLLECTION_MAP_KEY_JOIN_COLUMN_NAME, + ELEMENT_COLLECTION_MAP_KEY_JOIN_COLUMN_OPTIONS + ), + "ElementCollection MapKeyJoinColumn " + ELEMENT_COLLECTION_MAP_KEY_JOIN_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ONE_TO_MANY_MAP_KEY_JOIN_COLUMN_NAME, + ONE_TO_MANY_MAP_KEY_JOIN_COLUMN_OPTIONS + ), + "OneToMany MapKeyJoinColumn " + ONE_TO_MANY_MAP_KEY_JOIN_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + MANY_TO_MANY_MAP_KEY_JOIN_COLUMN_NAME, + MANY_TO_MANY_MAP_KEY_JOIN_COLUMN_OPTIONS + ), + "ManyToMany MapKeyJoinColumn " + MANY_TO_MANY_MAP_KEY_JOIN_COLUMN_OPTIONS + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ORDER_COLUMN_NAME, + ORDER_COLUMN_OPTIONS + ), + "OrderColumn " + ORDER_COLUMN_NAME + " options have not been created " + ); + } + + @Test + public void testXmlMappingTableCommentAreCreated() throws Exception { + createSchema( "org/hibernate/orm/test/schemaupdate/columnoptions/TestEntity.xml" ); + assertTrue( + tableCreationStatementContainsOptions( output, COLUMN_NAME, COLUMN_OPTIONS ), + "Column " + COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + DISCRIMINATOR_COLUMN_NAME, + DISCRIMINATOR_COLUMN_OPTIONS + ), + "DiscriminatorColumn " + DISCRIMINATOR_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( output, JOIN_COLUMN_NAME, JOIN_COLUMN_OPTIONS ), + "JoinColumn " + JOIN_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ELEMENT_COLLECTION_MAP_KEY_COLUMN_NAME, + ELEMENT_COLLECTION_MAP_KEY_COLUMN_OPTIONS + ), + "ElementCollection MapKeyColumn " + ELEMENT_COLLECTION_MAP_KEY_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ONE_TO_MANY_MAP_KEY_COLUMN_NAME, + ONE_TO_MANY_MAP_KEY_COLUMN_OPTIONS + ), + "OneToMany MapKeyColumn " + ONE_TO_MANY_MAP_KEY_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + MANY_TO_MANY_MAP_KEY_COLUMN_NAME, + MANY_TO_MANY_MAP_KEY_COLUMN_OPTIONS + ), + "ManyToMany MapKeyColumn " + MANY_TO_MANY_MAP_KEY_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ONE_TO_MANY_MAP_KEY_COLUMN_NAME, + ONE_TO_MANY_MAP_KEY_COLUMN_OPTIONS + ), + "OneToMany MapKeyColumn " + ONE_TO_MANY_MAP_KEY_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + PRIMARY_KEY_JOIN_COLUMN_NAME, + PRIMARY_KEY_JOIN_COLUMN_OPTIONS + ), + "PrimaryKeyJoinColumn " + PRIMARY_KEY_JOIN_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ELEMENT_COLLECTION_MAP_KEY_JOIN_COLUMN_NAME, + ELEMENT_COLLECTION_MAP_KEY_JOIN_COLUMN_OPTIONS + ), + "ElementCollection MapKeyJoinColumn " + ELEMENT_COLLECTION_MAP_KEY_JOIN_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ONE_TO_MANY_MAP_KEY_JOIN_COLUMN_NAME, + ONE_TO_MANY_MAP_KEY_JOIN_COLUMN_OPTIONS + ), + "OneToMany MapKeyJoinColumn " + ONE_TO_MANY_MAP_KEY_JOIN_COLUMN_NAME + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + MANY_TO_MANY_MAP_KEY_JOIN_COLUMN_NAME, + MANY_TO_MANY_MAP_KEY_JOIN_COLUMN_OPTIONS + ), + "ManyToMany MapKeyJoinColumn " + MANY_TO_MANY_MAP_KEY_JOIN_COLUMN_OPTIONS + " options have not been created " + ); + + assertTrue( + tableCreationStatementContainsOptions( + output, + ORDER_COLUMN_NAME, + ORDER_COLUMN_OPTIONS + ), + "OrderColumn " + ORDER_COLUMN_NAME + " options have not been created " + ); + } + + private static boolean tableCreationStatementContainsOptions( + File output, + String columnName, + String options) throws Exception { + String[] fileContent = new String( Files.readAllBytes( output.toPath() ) ).toLowerCase() + .split( System.lineSeparator() ); + for ( int i = 0; i < fileContent.length; i++ ) { + String statement = fileContent[i].toUpperCase( Locale.ROOT ); + if ( statement.contains( options.toUpperCase( Locale.ROOT ) ) ) { + return true; + } + } + return false; + } + + private void createSchema(String... xmlMapping) { + final MetadataSources metadataSources = new MetadataSources( ssr ); + + for ( String xml : xmlMapping ) { + metadataSources.addResource( xml ); + } + metadata = (MetadataImplementor) metadataSources.buildMetadata(); + metadata.orderColumns( false ); + metadata.validate(); + new SchemaExport() + .setHaltOnError( true ) + .setOutputFile( output.getAbsolutePath() ) + .setFormat( false ) + .create( EnumSet.of( TargetType.SCRIPT ), metadata ); + } + + private void createSchema(Class... annotatedClasses) { + final MetadataSources metadataSources = new MetadataSources( ssr ); + + for ( Class c : annotatedClasses ) { + metadataSources.addAnnotatedClass( c ); + } + metadata = (MetadataImplementor) metadataSources.buildMetadata(); + metadata.orderColumns( false ); + metadata.validate(); + new SchemaExport() + .setHaltOnError( true ) + .setOutputFile( output.getAbsolutePath() ) + .setFormat( false ) + .createOnly( EnumSet.of( TargetType.SCRIPT ), metadata ); + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/columnoptions/TestEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/columnoptions/TestEntity.java new file mode 100644 index 0000000000..fd8729bd28 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/columnoptions/TestEntity.java @@ -0,0 +1,166 @@ +package org.hibernate.orm.test.schemaupdate.columnoptions; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinColumns; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapKeyColumn; +import jakarta.persistence.MapKeyJoinColumn; +import jakarta.persistence.MapKeyTemporal; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderColumn; +import jakarta.persistence.Table; +import jakarta.persistence.TemporalType; + +@Entity +@Table(name = "TEST_ENTITY") +@Inheritance(strategy = InheritanceType.JOINED) +@DiscriminatorColumn(name = ColumnOptionsTest.DISCRIMINATOR_COLUMN_NAME, options = ColumnOptionsTest.DISCRIMINATOR_COLUMN_OPTIONS) +public class TestEntity { + @Id + private int id; + + @Column(name = ColumnOptionsTest.COLUMN_NAME, options = ColumnOptionsTest.COLUMN_OPTIONS) + private String name; + + @ManyToOne + @JoinColumns( + value = @JoinColumn(name = ColumnOptionsTest.JOIN_COLUMN_NAME, options = ColumnOptionsTest.JOIN_COLUMN_OPTIONS) + + ) + private TestEntity testEntity; + + @MapKeyTemporal(TemporalType.DATE) + @ElementCollection + @MapKeyColumn(name = ColumnOptionsTest.ELEMENT_COLLECTION_MAP_KEY_COLUMN_NAME, options = ColumnOptionsTest.ELEMENT_COLLECTION_MAP_KEY_COLUMN_OPTIONS) + private Map colorPerDate = new HashMap<>(); + + @OneToMany + @MapKeyColumn(name = ColumnOptionsTest.ONE_TO_MANY_MAP_KEY_COLUMN_NAME, options = ColumnOptionsTest.ONE_TO_MANY_MAP_KEY_COLUMN_OPTIONS) + private Map testEntityMap = new HashMap<>(); + + @ManyToMany + @MapKeyColumn(name = ColumnOptionsTest.MANY_TO_MANY_MAP_KEY_COLUMN_NAME, options = ColumnOptionsTest.MANY_TO_MANY_MAP_KEY_COLUMN_OPTIONS) + private Map testEntityMap2 = new HashMap<>(); + + @ElementCollection + @CollectionTable( + name = "ELEMENT_COLLECTION_TABLE") + @MapKeyJoinColumn(name = ColumnOptionsTest.ELEMENT_COLLECTION_MAP_KEY_JOIN_COLUMN_NAME, insertable = false, options = ColumnOptionsTest.ELEMENT_COLLECTION_MAP_KEY_JOIN_COLUMN_OPTIONS) + private Map stringMap = new HashMap<>(); + + @OneToMany + @JoinTable(name = "TEST_ENTITY_3") + @MapKeyJoinColumn(name = ColumnOptionsTest.ONE_TO_MANY_MAP_KEY_JOIN_COLUMN_NAME, options = ColumnOptionsTest.ONE_TO_MANY_MAP_KEY_JOIN_COLUMN_OPTIONS) + private Map testEntityMap3 = new HashMap<>(); + + @ManyToMany + @JoinTable(name = "TEST_ENTITY_4") + @MapKeyJoinColumn(name = ColumnOptionsTest.MANY_TO_MANY_MAP_KEY_JOIN_COLUMN_NAME, options = ColumnOptionsTest.MANY_TO_MANY_MAP_KEY_JOIN_COLUMN_OPTIONS) + private Map testEntityMap4 = new HashMap<>(); + + @ElementCollection + @OrderColumn(name = ColumnOptionsTest.ORDER_COLUMN_NAME, options = ColumnOptionsTest.ORDER_COLUMN_OPTIONS) + int[] theNumbers; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public TestEntity getTestEntity() { + return testEntity; + } + + public void setTestEntity(TestEntity testEntity) { + this.testEntity = testEntity; + } + + public Map getColorPerDate() { + return colorPerDate; + } + + public void setColorPerDate(Map colorPerDate) { + this.colorPerDate = colorPerDate; + } + + public Map getTestEntityMap() { + return testEntityMap; + } + + public void setTestEntityMap(Map testEntityMap) { + this.testEntityMap = testEntityMap; + } + + public Map getTestEntityMap2() { + return testEntityMap2; + } + + public void setTestEntityMap2(Map testEntityMap2) { + this.testEntityMap2 = testEntityMap2; + } + + public Map getStringMap() { + return stringMap; + } + + public void setStringMap(Map stringMap) { + this.stringMap = stringMap; + } + + public Map getTestEntityMap3() { + return testEntityMap3; + } + + public void setTestEntityMap3(Map testEntityMap3) { + this.testEntityMap3 = testEntityMap3; + } + + public Map getTestEntityMap4() { + return testEntityMap4; + } + + public void setTestEntityMap4(Map testEntityMap4) { + this.testEntityMap4 = testEntityMap4; + } + + public int[] getTheNumbers() { + return theNumbers; + } + + public void setTheNumbers(int[] theNumbers) { + this.theNumbers = theNumbers; + } + +// public AnotherTestEntity getAnotherTestEntity() { +// return anotherTestEntity; +// } +// +// public void setAnotherTestEntity(AnotherTestEntity anotherTestEntity) { +// this.anotherTestEntity = anotherTestEntity; +// } +} diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/schemaupdate/columnoptions/TestEntity.xml b/hibernate-core/src/test/resources/org/hibernate/orm/test/schemaupdate/columnoptions/TestEntity.xml new file mode 100644 index 0000000000..cddd6206ea --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/orm/test/schemaupdate/columnoptions/TestEntity.xml @@ -0,0 +1,54 @@ + + + + org.hibernate.orm.test.schemaupdate.columnoptions + + + + + + + + + + + + + + + + + + + + + + + + + + + + DATE + + + + + + + + + + + + + +
+ + + \ No newline at end of file