Skip to content

Commit 16af246

Browse files
committed
HHH-18620 - Add @NativeGenerator
1 parent 9e89bdd commit 16af246

File tree

21 files changed

+482
-195
lines changed

21 files changed

+482
-195
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;
@@ -629,8 +630,8 @@ public boolean requiresParensForTupleDistinctCounts() {
629630
}
630631

631632
@Override
632-
public String getNativeIdentifierGeneratorStrategy() {
633-
return "sequence";
633+
public GenerationType getNativeValueGenerationStrategy() {
634+
return GenerationType.SEQUENCE;
634635
}
635636

636637
@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
@@ -112,6 +112,7 @@
112112
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
113113
import org.hibernate.type.spi.TypeConfiguration;
114114

115+
import jakarta.persistence.GenerationType;
115116
import jakarta.persistence.TemporalType;
116117

117118
import static java.util.regex.Pattern.CASE_INSENSITIVE;
@@ -928,8 +929,8 @@ public AggregateSupport getAggregateSupport() {
928929
}
929930

930931
@Override
931-
public String getNativeIdentifierGeneratorStrategy() {
932-
return "sequence";
932+
public GenerationType getNativeValueGenerationStrategy() {
933+
return GenerationType.SEQUENCE;
933934
}
934935

935936
// 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
@@ -92,6 +92,7 @@
9292
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
9393
import org.hibernate.type.spi.TypeConfiguration;
9494

95+
import jakarta.persistence.GenerationType;
9596
import jakarta.persistence.TemporalType;
9697

9798
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
@@ -834,8 +835,8 @@ public boolean supportsCaseInsensitiveLike() {
834835
}
835836

836837
@Override
837-
public String getNativeIdentifierGeneratorStrategy() {
838-
return "sequence";
838+
public GenerationType getNativeValueGenerationStrategy() {
839+
return GenerationType.SEQUENCE;
839840
}
840841

841842
@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: 22 additions & 8 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,12 +94,8 @@ 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 = context.getMetadataCollector()
98-
.getSourceModelBuildingContext()
99-
.getClassDetailsRegistry()
100-
.resolveClassDetails( packageInfoFqn );
97+
final ClassDetails packageInfo = locatePackageInfoDetails( idMember.getDeclaringType(), context );
98+
if ( packageInfo != null ) {
10199
for ( A generatorAnnotation : packageInfo.getRepeatedAnnotationUsages( generatorAnnotationType, sourceModelContext ) ) {
102100
if ( nameExtractor != null ) {
103101
final String registrationName = nameExtractor.apply( generatorAnnotation );
@@ -117,11 +115,27 @@ public static <A extends Annotation> A findLocalizedMatch(
117115
}
118116
}
119117
}
118+
119+
return possibleMatch;
120+
}
121+
122+
public static ClassDetails locatePackageInfoDetails(ClassDetails classDetails, MetadataBuildingContext buildingContext) {
123+
return locatePackageInfoDetails( classDetails, buildingContext.getMetadataCollector().getSourceModelBuildingContext() );
124+
}
125+
126+
public static ClassDetails locatePackageInfoDetails(ClassDetails classDetails, SourceModelContext modelContext) {
127+
return locatePackageInfoDetails( classDetails, modelContext.getClassDetailsRegistry() );
128+
}
129+
130+
public static ClassDetails locatePackageInfoDetails(ClassDetails classDetails, ClassDetailsRegistry classDetailsRegistry) {
131+
final String packageInfoFqn = StringHelper.qualifier( classDetails.getName() ) + ".package-info";
132+
try {
133+
return classDetailsRegistry.resolveClassDetails( packageInfoFqn );
134+
}
120135
catch (ClassLoadingException e) {
121136
// means there is no package-info
137+
return null;
122138
}
123-
124-
return possibleMatch;
125139
}
126140

127141
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
@@ -653,7 +653,7 @@ private static <G extends Generator> G instantiateGeneratorViaDefaultConstructor
653653
}
654654
}
655655

656-
private static <A extends Annotation> void callInitialize(
656+
public static <A extends Annotation> void callInitialize(
657657
A annotation,
658658
MemberDetails memberDetails,
659659
GeneratorCreationContext creationContext,

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

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

@@ -318,6 +320,10 @@ private void handleUnnamedAutoGenerator() {
318320
return;
319321
}
320322

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

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

352-
final List<? extends Annotation> metaAnnotated = idMember.getMetaAnnotated( IdGeneratorType.class, buildingContext.getMetadataCollector().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 = GeneratorBinder.instantiateGenerator(
360-
beanContainer,
361-
markerAnnotation.value()
362-
);
363-
final Map<String,Object> configuration = new HashMap<>();
364-
GeneratorParameters.collectParameters(
365-
idValue,
366-
buildingContext.getMetadataCollector().getDatabase().getDialect(),
367-
entityMapping.getRootClass(),
368-
configuration::put
369-
);
370-
callConfigure( creationContext, identifierGenerator, configuration, idValue );
371-
return identifierGenerator;
372-
} );
414+
if ( handleAsMetaAnnotated() ) {
373415
return;
374416
}
375417

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;
@@ -599,8 +600,8 @@ public boolean requiresParensForTupleDistinctCounts() {
599600
}
600601

601602
@Override
602-
public String getNativeIdentifierGeneratorStrategy() {
603-
return "sequence";
603+
public GenerationType getNativeValueGenerationStrategy() {
604+
return GenerationType.SEQUENCE;
604605
}
605606

606607
@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

@@ -1898,11 +1899,21 @@ public LobMergeStrategy getLobMergeStrategy() {
18981899
* {@code "native"} is specified in {@code hbm.xml}.
18991900
*
19001901
* @return The name identifying the native generator strategy.
1902+
*
1903+
* @deprecated Use {@linkplain #getNativeValueGenerationStrategy()} instead
19011904
*/
1905+
@Deprecated(since = "7.0", forRemoval = true)
19021906
public String getNativeIdentifierGeneratorStrategy() {
1907+
return getNativeValueGenerationStrategy().name().toLowerCase( Locale.ROOT );
1908+
}
1909+
1910+
/**
1911+
* The native type of generation supported by this Dialect.
1912+
*/
1913+
public GenerationType getNativeValueGenerationStrategy() {
19031914
return getIdentityColumnSupport().supportsIdentityColumns()
1904-
? "identity"
1905-
: "sequence";
1915+
? GenerationType.IDENTITY
1916+
: GenerationType.SEQUENCE;
19061917
}
19071918

19081919
// IDENTITY support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

0 commit comments

Comments
 (0)