HHH-18096 Support for JPA 3.2 database generator options

This commit is contained in:
Andrea Boriero 2024-05-14 12:17:09 +02:00 committed by Steve Ebersole
parent ee1c583d2e
commit 49964af5a9
7 changed files with 124 additions and 8 deletions

View File

@ -131,6 +131,14 @@ public class GenerationStrategyInterpreter {
);
}
final String options = tableGeneratorAnnotation.getString( "options" );
if ( StringHelper.isNotEmpty( options ) ) {
definitionBuilder.addParam(
org.hibernate.id.enhanced.TableGenerator.TABLE_OPTIONS,
options
);
}
definitionBuilder.addParam(
org.hibernate.id.enhanced.TableGenerator.INCREMENT_PARAM,
String.valueOf( tableGeneratorAnnotation.getInteger( "allocationSize" ) )

View File

@ -596,6 +596,8 @@ public class ManagedTypeProcessor {
jaxbEntity, classDetails, xmlDocumentContext
);
XmlAnnotationHelper.applyTableGenerators( jaxbEntity.getTableGenerators(), classDetails, xmlDocumentContext );
renderClass( classDetails, xmlDocumentContext );
}

View File

@ -131,6 +131,7 @@ import jakarta.persistence.SecondaryTables;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.TableGenerator;
import jakarta.persistence.TableGenerators;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.persistence.UniqueConstraint;
@ -389,6 +390,27 @@ public class XmlAnnotationHelper {
} );
}
public static <A extends Annotation> void applyUniqueConstraints(
List<JaxbUniqueConstraintImpl> jaxbUniqueConstraints,
MutableAnnotationUsage<A> annotationUsage,
XmlDocumentContext xmlDocumentContext) {
if ( CollectionHelper.isEmpty( jaxbUniqueConstraints ) ) {
return;
}
final List<AnnotationUsage<UniqueConstraint>> uniqueConstraintUsages = new ArrayList<>( jaxbUniqueConstraints.size() );
annotationUsage.setAttributeValue( "uniqueConstraints", uniqueConstraintUsages );
jaxbUniqueConstraints.forEach( (jaxbUniqueConstraint) -> {
final MutableAnnotationUsage<UniqueConstraint> ucUsage =
JpaAnnotations.UNIQUE_CONSTRAINT.createUsage( xmlDocumentContext.getModelBuildingContext() );
XmlAnnotationHelper.applyOptionalAttribute( ucUsage, "name", jaxbUniqueConstraint.getName() );
XmlAnnotationHelper.applyOptionalAttribute( ucUsage, "options", jaxbUniqueConstraint.getOptions() );
ucUsage.setAttributeValue( "columnNames", jaxbUniqueConstraint.getColumnName() );
uniqueConstraintUsages.add( ucUsage );
} );
}
public static <A extends Annotation> void applyIndexes(
List<JaxbIndexImpl> jaxbIndexes,
AnnotationTarget target,
@ -405,6 +427,29 @@ public class XmlAnnotationHelper {
applyOr( jaxbIndex, JaxbIndexImpl::getName, "name", indexAnn, JpaAnnotations.INDEX );
applyOr( jaxbIndex, JaxbIndexImpl::getColumnList, "columnList", indexAnn, JpaAnnotations.INDEX );
applyOr( jaxbIndex, JaxbIndexImpl::isUnique, "unique", indexAnn, JpaAnnotations.INDEX );
applyOr( jaxbIndex, JaxbIndexImpl::getOptions, "options", indexAnn, JpaAnnotations.INDEX );
indexes.add( indexAnn );
} );
annotationUsage.setAttributeValue( "indexes", indexes );
}
public static <A extends Annotation> void applyIndexes(
List<JaxbIndexImpl> jaxbIndexes,
MutableAnnotationUsage<A> annotationUsage,
XmlDocumentContext xmlDocumentContext) {
if ( CollectionHelper.isEmpty( jaxbIndexes ) ) {
return;
}
final List<AnnotationUsage<Index>> indexes = new ArrayList<>( jaxbIndexes.size() );
jaxbIndexes.forEach( jaxbIndex -> {
final MutableAnnotationUsage<Index> indexAnn =
JpaAnnotations.INDEX.createUsage( xmlDocumentContext.getModelBuildingContext() );
applyOr( jaxbIndex, JaxbIndexImpl::getName, "name", indexAnn, JpaAnnotations.INDEX );
applyOr( jaxbIndex, JaxbIndexImpl::getColumnList, "columnList", indexAnn, JpaAnnotations.INDEX );
applyOr( jaxbIndex, JaxbIndexImpl::isUnique, "unique", indexAnn, JpaAnnotations.INDEX );
applyOr( jaxbIndex, JaxbIndexImpl::getOptions, "options", indexAnn, JpaAnnotations.INDEX );
indexes.add( indexAnn );
} );
@ -528,6 +573,24 @@ public class XmlAnnotationHelper {
XmlProcessingHelper.applyAttributeIfSpecified( "options", jaxbGenerator.getOptions(), sequenceAnn );
}
public static void applyTableGenerators(
JaxbTableGeneratorImpl jaxbGenerator,
MutableClassDetails classDetails,
XmlDocumentContext xmlDocumentContext) {
if ( jaxbGenerator == null ) {
return;
}
final MutableAnnotationUsage<TableGenerator> tableAnn = classDetails.replaceAnnotationUsage(
JpaAnnotations.TABLE_GENERATOR,
xmlDocumentContext.getModelBuildingContext()
);
applyTableGeneratorAttributes( jaxbGenerator, tableAnn );
applyUniqueConstraints( jaxbGenerator.getUniqueConstraints(), tableAnn, xmlDocumentContext );
applyIndexes( jaxbGenerator.getIndexes(), tableAnn, xmlDocumentContext );
}
public static void applyTableGenerator(
JaxbTableGeneratorImpl jaxbGenerator,
MutableMemberDetails memberDetails,
@ -537,6 +600,14 @@ public class XmlAnnotationHelper {
}
final MutableAnnotationUsage<TableGenerator> tableAnn = memberDetails.applyAnnotationUsage( JpaAnnotations.TABLE_GENERATOR, xmlDocumentContext.getModelBuildingContext() );
applyTableGeneratorAttributes( jaxbGenerator, tableAnn );
applyUniqueConstraints( jaxbGenerator.getUniqueConstraints(), memberDetails, tableAnn, xmlDocumentContext );
applyIndexes( jaxbGenerator.getIndexes(), memberDetails, tableAnn, xmlDocumentContext );
}
private static void applyTableGeneratorAttributes(
JaxbTableGeneratorImpl jaxbGenerator,
MutableAnnotationUsage<TableGenerator> tableAnn) {
XmlProcessingHelper.applyAttributeIfSpecified( "name", jaxbGenerator.getName(), tableAnn );
XmlProcessingHelper.applyAttributeIfSpecified( "table", jaxbGenerator.getTable(), tableAnn );
XmlProcessingHelper.applyAttributeIfSpecified( "catalog", jaxbGenerator.getCatalog(), tableAnn );
@ -546,8 +617,7 @@ public class XmlAnnotationHelper {
XmlProcessingHelper.applyAttributeIfSpecified( "pkColumnValue", jaxbGenerator.getPkColumnValue(), tableAnn );
XmlProcessingHelper.applyAttributeIfSpecified( "initialValue", jaxbGenerator.getInitialValue(), tableAnn );
XmlProcessingHelper.applyAttributeIfSpecified( "allocationSize", jaxbGenerator.getInitialValue(), tableAnn );
applyUniqueConstraints( jaxbGenerator.getUniqueConstraints(), memberDetails, tableAnn, xmlDocumentContext );
applyIndexes( jaxbGenerator.getIndexes(), memberDetails, tableAnn, xmlDocumentContext );
XmlProcessingHelper.applyAttributeIfSpecified( "options", jaxbGenerator.getOptions(), tableAnn );
}
public static void applyUuidGenerator(

View File

@ -196,6 +196,11 @@ public class TableGenerator implements PersistentIdentifierGenerator {
*/
public static final int DEF_SEGMENT_LENGTH = 255;
/**
* Configures the options of the table to use.
*/
public static final String TABLE_OPTIONS = "options";
private boolean storeLastUsedValue;
@ -221,6 +226,7 @@ public class TableGenerator implements PersistentIdentifierGenerator {
private String contributor;
private String options;
/**
* Type mapping for the identifier.
*
@ -359,6 +365,7 @@ public class TableGenerator implements PersistentIdentifierGenerator {
if ( contributor == null ) {
contributor = "orm";
}
options = parameters.getProperty( TABLE_OPTIONS );
}
private static OptimizerDescriptor determineOptimizationStrategy(Properties parameters, int incrementSize) {
@ -727,6 +734,9 @@ public class TableGenerator implements PersistentIdentifierGenerator {
qualifiedTableName.getObjectName(),
(identifier) -> new Table( contributor, namespace, identifier, false )
);
if ( StringHelper.isNotEmpty( options ) ) {
table.setOptions( options );
}
final BasicTypeRegistry basicTypeRegistry = database.getTypeConfiguration().getBasicTypeRegistry();
// todo : not sure the best solution here. do we add the columns if missing? other?

View File

@ -23,6 +23,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
@BaseUnitTest
public class TableOptionsTest {
static final String TABLE_GENERATOR_NAME = "TEST_TABLE_GENERATOR";
static final String TABLE_GENERATOR_OPTIONS = "option_0";
static final String TABLE_NAME = "PRIMARY_TABLE";
static final String TABLE_OPTIONS = "option_1";
@ -53,7 +57,7 @@ public class TableOptionsTest {
}
@Test
public void testTableCommentAreCreated() throws Exception {
public void testTableOptionsAreCreated() throws Exception {
createSchema( TestEntity.class );
assertTrue(
tableCreationStatementContainsOptions( output, TABLE_NAME, TABLE_OPTIONS ),
@ -67,12 +71,17 @@ public class TableOptionsTest {
assertTrue(
tableCreationStatementContainsOptions( output, JOIN_TABLE_NAME, JOIN_TABLE_OPTIONS ),
"Join Table " + JOIN_TABLE_NAME + " options has not been created "
"JoinTable " + JOIN_TABLE_NAME + " options has not been created "
);
assertTrue(
tableCreationStatementContainsOptions( output, COLLECTION_TABLE_NAME, COLLECTION_TABLE_OPTIONS ),
"Join Table " + COLLECTION_TABLE_NAME + " options has not been created "
"JoinTable " + COLLECTION_TABLE_NAME + " options has not been created "
);
assertTrue(
tableCreationStatementContainsOptions( output, TABLE_GENERATOR_NAME, TABLE_GENERATOR_OPTIONS ),
"TableGenerator " + COLLECTION_TABLE_NAME + " options has not been created "
);
}
@ -98,6 +107,11 @@ public class TableOptionsTest {
tableCreationStatementContainsOptions( output, COLLECTION_TABLE_NAME, COLLECTION_TABLE_OPTIONS ),
"Join Table " + COLLECTION_TABLE_NAME + " options has not been created "
);
assertTrue(
tableCreationStatementContainsOptions( output, TABLE_GENERATOR_NAME, TABLE_GENERATOR_OPTIONS ),
"TableGenerator " + TABLE_GENERATOR_NAME + " options has not been created "
);
}
private static boolean tableCreationStatementContainsOptions(
@ -130,7 +144,7 @@ public class TableOptionsTest {
.setHaltOnError( true )
.setOutputFile( output.getAbsolutePath() )
.setFormat( false )
.create( EnumSet.of( TargetType.SCRIPT ), metadata );
.createOnly( EnumSet.of( TargetType.SCRIPT ), metadata );
}
private void createSchema(Class... annotatedClasses) {
@ -146,7 +160,7 @@ public class TableOptionsTest {
.setHaltOnError( true )
.setOutputFile( output.getAbsolutePath() )
.setFormat( false )
.create( EnumSet.of( TargetType.SCRIPT ), metadata );
.createOnly( EnumSet.of( TargetType.SCRIPT ), metadata );
}
}

View File

@ -7,12 +7,15 @@ import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.SecondaryTable;
import jakarta.persistence.Table;
import jakarta.persistence.TableGenerator;
@Entity
@Table(
@ -25,6 +28,12 @@ import jakarta.persistence.Table;
)
public class TestEntity {
@Id
@TableGenerator(
name = "id-table-generator",
table = TableOptionsTest.TABLE_GENERATOR_NAME,
options = TableOptionsTest.TABLE_GENERATOR_OPTIONS
)
@GeneratedValue(strategy = GenerationType.TABLE, generator = "id-table-generator")
private Long id;
@Column(name = "NAME_COLUMN")

View File

@ -10,8 +10,11 @@
<entity class="TestEntity" metadata-complete="true">
<table name="PRIMARY_TABLE" options="option_1"/>
<secondary-table name="SECOND_TABLE" options="option_2"/>
<table-generator name="id-table-generator" table="TEST_TABLE_GENERATOR" options="option_0"/>
<attributes>
<id name="id"/>
<id name="id">
<generated-value strategy="TABLE" generator="id-table-generator"/>
</id>
<basic name="name">
<column name="NAME_COLUMN"/>
</basic>