Skip to content

Commit 94d34f0

Browse files
committed
HHH-18620 - Add @NativeGenerator
1 parent 3818b6d commit 94d34f0

File tree

21 files changed

+483
-198
lines changed

21 files changed

+483
-198
lines changed

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.hibernate.type.descriptor.jdbc.JdbcType;
5252
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
5353

54+
import jakarta.persistence.GenerationType;
5455
import jakarta.persistence.TemporalType;
5556

5657
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
@@ -283,10 +284,9 @@ public boolean hasSelfReferentialForeignKeyBug() {
283284
return true;
284285
}
285286

286-
287287
@Override
288-
public String getNativeIdentifierGeneratorStrategy() {
289-
return "identity";
288+
public GenerationType getNativeValueGenerationStrategy() {
289+
return GenerationType.IDENTITY;
290290
}
291291

292292
// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575

7676
import org.jboss.logging.Logger;
7777

78+
import jakarta.persistence.GenerationType;
7879
import jakarta.persistence.TemporalType;
7980

8081
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
@@ -654,8 +655,8 @@ public boolean requiresParensForTupleDistinctCounts() {
654655
}
655656

656657
@Override
657-
public String getNativeIdentifierGeneratorStrategy() {
658-
return "sequence";
658+
public GenerationType getNativeValueGenerationStrategy() {
659+
return GenerationType.SEQUENCE;
659660
}
660661

661662
@Override

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
101101
import org.hibernate.type.spi.TypeConfiguration;
102102

103+
import jakarta.persistence.GenerationType;
103104
import jakarta.persistence.TemporalType;
104105

105106
import static java.util.regex.Pattern.CASE_INSENSITIVE;
@@ -953,8 +954,8 @@ public AggregateSupport getAggregateSupport() {
953954
}
954955

955956
@Override
956-
public String getNativeIdentifierGeneratorStrategy() {
957-
return "sequence";
957+
public GenerationType getNativeValueGenerationStrategy() {
958+
return GenerationType.SEQUENCE;
958959
}
959960

960961
// features which change between 8i, 9i, and 10g ~~~~~~~~~~~~~~~~~~~~~~~~~~

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
9494
import org.hibernate.type.spi.TypeConfiguration;
9595

96+
import jakarta.persistence.GenerationType;
9697
import jakarta.persistence.TemporalType;
9798

9899
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
@@ -885,8 +886,8 @@ public boolean supportsCaseInsensitiveLike() {
885886
}
886887

887888
@Override
888-
public String getNativeIdentifierGeneratorStrategy() {
889-
return "sequence";
889+
public GenerationType getNativeValueGenerationStrategy() {
890+
return GenerationType.SEQUENCE;
890891
}
891892

892893
@Override
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.annotations;
6+
7+
import java.lang.annotation.Target;
8+
import java.lang.annotation.Retention;
9+
10+
import org.hibernate.dialect.Dialect;
11+
12+
import jakarta.persistence.SequenceGenerator;
13+
import jakarta.persistence.TableGenerator;
14+
15+
import static java.lang.annotation.ElementType.FIELD;
16+
import static java.lang.annotation.ElementType.METHOD;
17+
import static java.lang.annotation.ElementType.PACKAGE;
18+
import static java.lang.annotation.ElementType.TYPE;
19+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
20+
21+
/**
22+
* Generator that picks a strategy based on the {@linkplain Dialect#getNativeValueGenerationStrategy() dialect}.
23+
*
24+
* @since 7.0
25+
*
26+
* @author Steve Ebersole
27+
*/
28+
@Target({METHOD, FIELD, TYPE, PACKAGE})
29+
@Retention(RUNTIME)
30+
@IdGeneratorType(org.hibernate.id.NativeGenerator.class)
31+
public @interface NativeGenerator {
32+
SequenceGenerator sequenceForm() default @SequenceGenerator();
33+
TableGenerator tableForm() default @TableGenerator();
34+
}

hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorAnnotationHelper.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828
import org.hibernate.mapping.SimpleValue;
2929
import org.hibernate.models.spi.AnnotationDescriptor;
3030
import org.hibernate.models.spi.ClassDetails;
31+
import org.hibernate.models.spi.ClassDetailsRegistry;
3132
import org.hibernate.models.spi.MemberDetails;
3233
import org.hibernate.models.spi.SourceModelBuildingContext;
34+
import org.hibernate.models.spi.SourceModelContext;
3335

3436
import jakarta.persistence.SequenceGenerator;
3537
import jakarta.persistence.TableGenerator;
@@ -92,13 +94,9 @@ public static <A extends Annotation> A findLocalizedMatch(
9294
}
9395

9496
// lastly, on the package
95-
final String packageInfoFqn = StringHelper.qualifier( idMember.getDeclaringType().getClassName() ) + ".package-info";
96-
try {
97-
final ClassDetails packageInfo =
98-
context.getMetadataCollector()
99-
.getSourceModelBuildingContext()
100-
.getClassDetailsRegistry()
101-
.resolveClassDetails( packageInfoFqn );
97+
final ClassDetails packageInfo = locatePackageInfoDetails( idMember.getDeclaringType(), context );
98+
if ( packageInfo !=
99+
null ) {
102100
for ( A generatorAnnotation : packageInfo.getRepeatedAnnotationUsages( generatorAnnotationType, sourceModelContext ) ) {
103101
if ( nameExtractor != null ) {
104102
final String registrationName = nameExtractor.apply( generatorAnnotation );
@@ -118,11 +116,27 @@ public static <A extends Annotation> A findLocalizedMatch(
118116
}
119117
}
120118
}
119+
120+
return possibleMatch;
121+
}
122+
123+
public static ClassDetails locatePackageInfoDetails(ClassDetails classDetails, MetadataBuildingContext buildingContext) {
124+
return locatePackageInfoDetails( classDetails, buildingContext.getMetadataCollector().getSourceModelBuildingContext() );
125+
}
126+
127+
public static ClassDetails locatePackageInfoDetails(ClassDetails classDetails, SourceModelContext modelContext) {
128+
return locatePackageInfoDetails( classDetails, modelContext.getClassDetailsRegistry() );
129+
}
130+
131+
public static ClassDetails locatePackageInfoDetails(ClassDetails classDetails, ClassDetailsRegistry classDetailsRegistry) {
132+
final String packageInfoFqn = StringHelper.qualifier( classDetails.getName() ) + ".package-info";
133+
try {
134+
return classDetailsRegistry.resolveClassDetails( packageInfoFqn );
135+
}
121136
catch (ClassLoadingException e) {
122137
// means there is no package-info
138+
return null;
123139
}
124-
125-
return possibleMatch;
126140
}
127141

128142
public static void handleUuidStrategy(

hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ private static <G extends Generator> G instantiateGeneratorViaDefaultConstructor
637637
}
638638
}
639639

640-
private static <A extends Annotation> void callInitialize(
640+
public static <A extends Annotation> void callInitialize(
641641
A annotation,
642642
MemberDetails memberDetails,
643643
GeneratorCreationContext creationContext,

hibernate-core/src/main/java/org/hibernate/boot/model/internal/IdGeneratorResolverSecondPass.java

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import org.hibernate.internal.util.collections.CollectionHelper;
3535
import org.hibernate.mapping.PersistentClass;
3636
import org.hibernate.mapping.SimpleValue;
37+
import org.hibernate.models.spi.AnnotationTarget;
38+
import org.hibernate.models.spi.ClassDetails;
3739
import org.hibernate.models.spi.MemberDetails;
3840
import org.hibernate.resource.beans.container.spi.BeanContainer;
3941

@@ -317,6 +319,10 @@ private void handleUnnamedAutoGenerator() {
317319
return;
318320
}
319321

322+
if ( handleAsMetaAnnotated() ) {
323+
return;
324+
}
325+
320326
if ( idMember.getType().isImplementor( UUID.class )
321327
|| idMember.getType().isImplementor( String.class ) ) {
322328
GeneratorAnnotationHelper.handleUuidStrategy( idValue, idMember, buildingContext );
@@ -326,6 +332,62 @@ private void handleUnnamedAutoGenerator() {
326332
handleSequenceGenerator( null, null );
327333
}
328334

335+
private boolean handleAsMetaAnnotated() {
336+
final Annotation fromMember = findGeneratorAnnotation( idMember );
337+
if ( fromMember != null ) {
338+
handleIdGeneratorType( fromMember );
339+
return true;
340+
}
341+
342+
final Annotation fromClass = findGeneratorAnnotation( idMember.getDeclaringType() );
343+
if ( fromClass != null ) {
344+
handleIdGeneratorType( fromClass );
345+
return true;
346+
}
347+
348+
final ClassDetails packageInfoDetails = GeneratorAnnotationHelper.locatePackageInfoDetails( idMember.getDeclaringType(), buildingContext );
349+
if ( packageInfoDetails != null ) {
350+
final Annotation fromPackage = findGeneratorAnnotation( packageInfoDetails );
351+
if ( fromPackage != null ) {
352+
handleIdGeneratorType( fromPackage );
353+
return true;
354+
}
355+
}
356+
357+
return false;
358+
}
359+
360+
private Annotation findGeneratorAnnotation(AnnotationTarget annotationTarget) {
361+
final List<? extends Annotation> metaAnnotated = annotationTarget.getMetaAnnotated( IdGeneratorType.class, buildingContext.getMetadataCollector().getSourceModelBuildingContext() );
362+
if ( CollectionHelper.size( metaAnnotated ) > 0 ) {
363+
return metaAnnotated.get( 0 );
364+
}
365+
366+
return null;
367+
}
368+
369+
private void handleIdGeneratorType(Annotation generatorAnnotation) {
370+
final IdGeneratorType markerAnnotation = generatorAnnotation.annotationType().getAnnotation( IdGeneratorType.class );
371+
idValue.setCustomIdGeneratorCreator( (creationContext) -> {
372+
373+
final BeanContainer beanContainer = GeneratorBinder.beanContainer( buildingContext );
374+
final Generator identifierGenerator = GeneratorBinder.instantiateGenerator(
375+
beanContainer,
376+
markerAnnotation.value()
377+
);
378+
final Map<String,Object> configuration = new HashMap<>();
379+
GeneratorParameters.collectParameters(
380+
idValue,
381+
buildingContext.getMetadataCollector().getDatabase().getDialect(),
382+
entityMapping.getRootClass(),
383+
configuration::put
384+
);
385+
GeneratorBinder.callInitialize( generatorAnnotation, idMember, creationContext, identifierGenerator );
386+
callConfigure( creationContext, identifierGenerator, configuration, idValue );
387+
return identifierGenerator;
388+
} );
389+
}
390+
329391
private void handleNamedAutoGenerator() {
330392
if ( handleAsLocalAutoGenerator() ) {
331393
return;
@@ -347,29 +409,7 @@ private void handleNamedAutoGenerator() {
347409
return;
348410
}
349411

350-
final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector();
351-
final List<? extends Annotation> metaAnnotated =
352-
idMember.getMetaAnnotated( IdGeneratorType.class, metadataCollector.getSourceModelBuildingContext() );
353-
if ( CollectionHelper.size( metaAnnotated ) > 0 ) {
354-
final Annotation generatorAnnotation = metaAnnotated.get( 0 );
355-
final IdGeneratorType markerAnnotation = generatorAnnotation.annotationType().getAnnotation( IdGeneratorType.class );
356-
idValue.setCustomIdGeneratorCreator( (creationContext) -> {
357-
358-
final BeanContainer beanContainer = GeneratorBinder.beanContainer( buildingContext );
359-
final Generator identifierGenerator = instantiateGenerator(
360-
beanContainer,
361-
markerAnnotation.value()
362-
);
363-
final Map<String,Object> configuration = new HashMap<>();
364-
GeneratorParameters.collectParameters(
365-
idValue,
366-
metadataCollector.getDatabase().getDialect(),
367-
entityMapping.getRootClass(),
368-
configuration::put
369-
);
370-
callConfigure( creationContext, identifierGenerator, configuration, idValue );
371-
return identifierGenerator;
372-
} );
412+
if ( handleAsMetaAnnotated() ) {
373413
return;
374414
}
375415

hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575

7676
import org.jboss.logging.Logger;
7777

78+
import jakarta.persistence.GenerationType;
7879
import jakarta.persistence.TemporalType;
7980

8081
import static java.lang.Integer.parseInt;
@@ -620,8 +621,8 @@ public boolean requiresParensForTupleDistinctCounts() {
620621
}
621622

622623
@Override
623-
public String getNativeIdentifierGeneratorStrategy() {
624-
return "sequence";
624+
public GenerationType getNativeValueGenerationStrategy() {
625+
return GenerationType.SEQUENCE;
625626
}
626627

627628
@Override

hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@
196196

197197
import org.jboss.logging.Logger;
198198

199+
import jakarta.persistence.GenerationType;
199200
import jakarta.persistence.TemporalType;
200201
import org.checkerframework.checker.nullness.qual.Nullable;
201202

@@ -2045,11 +2046,21 @@ public LobMergeStrategy getLobMergeStrategy() {
20452046
* {@code "native"} is specified in {@code hbm.xml}.
20462047
*
20472048
* @return The name identifying the native generator strategy.
2049+
*
2050+
* @deprecated Use {@linkplain #getNativeValueGenerationStrategy()} instead
20482051
*/
2052+
@Deprecated(since = "7.0", forRemoval = true)
20492053
public String getNativeIdentifierGeneratorStrategy() {
2054+
return getNativeValueGenerationStrategy().name().toLowerCase( Locale.ROOT );
2055+
}
2056+
2057+
/**
2058+
* The native type of generation supported by this Dialect.
2059+
*/
2060+
public GenerationType getNativeValueGenerationStrategy() {
20502061
return getIdentityColumnSupport().supportsIdentityColumns()
2051-
? "identity"
2052-
: "sequence";
2062+
? GenerationType.IDENTITY
2063+
: GenerationType.SEQUENCE;
20532064
}
20542065

20552066
// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

0 commit comments

Comments
 (0)