Skip to content

Commit a052c26

Browse files
committed
HHH-18620 - Add @NativeGenerator
1 parent c979b9c commit a052c26

File tree

5 files changed

+394
-411
lines changed

5 files changed

+394
-411
lines changed
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.boot.model.internal;
6+
7+
import java.lang.annotation.Annotation;
8+
import java.util.HashMap;
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
import org.hibernate.MappingException;
13+
import org.hibernate.annotations.IdGeneratorType;
14+
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
15+
import org.hibernate.boot.model.relational.Database;
16+
import org.hibernate.boot.spi.MetadataBuildingContext;
17+
import org.hibernate.dialect.Dialect;
18+
import org.hibernate.generator.Generator;
19+
import org.hibernate.internal.util.collections.CollectionHelper;
20+
import org.hibernate.mapping.Column;
21+
import org.hibernate.mapping.PersistentClass;
22+
import org.hibernate.mapping.SimpleValue;
23+
import org.hibernate.models.spi.AnnotationTarget;
24+
import org.hibernate.models.spi.ClassDetails;
25+
import org.hibernate.models.spi.MemberDetails;
26+
27+
import jakarta.persistence.GeneratedValue;
28+
29+
import static org.hibernate.boot.model.internal.GeneratorAnnotationHelper.handleIdGeneratorType;
30+
import static org.hibernate.boot.model.internal.GeneratorParameters.identityTablesString;
31+
import static org.hibernate.boot.model.internal.GeneratorStrategies.mapLegacyNamedGenerator;
32+
import static org.hibernate.id.IdentifierGenerator.ENTITY_NAME;
33+
import static org.hibernate.id.IdentifierGenerator.JPA_ENTITY_NAME;
34+
import static org.hibernate.id.OptimizableGenerator.IMPLICIT_NAME_BASE;
35+
import static org.hibernate.id.PersistentIdentifierGenerator.PK;
36+
import static org.hibernate.id.PersistentIdentifierGenerator.TABLE;
37+
import static org.hibernate.id.PersistentIdentifierGenerator.TABLES;
38+
39+
/**
40+
* Template support for IdGeneratorResolver implementations dealing with entity identifiers
41+
*
42+
* @author Steve Ebersole
43+
*/
44+
public abstract class AbstractEntityIdGeneratorResolver implements IdGeneratorResolver {
45+
protected final PersistentClass entityMapping;
46+
protected final SimpleValue idValue;
47+
protected final MemberDetails idMember;
48+
protected final GeneratedValue generatedValue;
49+
protected final MetadataBuildingContext buildingContext;
50+
51+
public AbstractEntityIdGeneratorResolver(
52+
PersistentClass entityMapping,
53+
SimpleValue idValue,
54+
MemberDetails idMember,
55+
GeneratedValue generatedValue,
56+
MetadataBuildingContext buildingContext) {
57+
this.entityMapping = entityMapping;
58+
this.idValue = idValue;
59+
this.idMember = idMember;
60+
this.generatedValue = generatedValue;
61+
this.buildingContext = buildingContext;
62+
}
63+
64+
@Override
65+
public final void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
66+
switch ( generatedValue.strategy() ) {
67+
case UUID -> GeneratorAnnotationHelper.handleUuidStrategy( idValue, idMember, buildingContext );
68+
case IDENTITY -> GeneratorAnnotationHelper.handleIdentityStrategy( idValue );
69+
case SEQUENCE -> handleSequenceStrategy();
70+
case TABLE -> handleTableStrategy();
71+
case AUTO -> handleAutoStrategy();
72+
}
73+
}
74+
75+
private void handleSequenceStrategy() {
76+
if ( generatedValue.generator().isEmpty() ) {
77+
handleUnnamedSequenceGenerator();
78+
}
79+
else {
80+
handleNamedSequenceGenerator();
81+
}
82+
}
83+
84+
protected abstract void handleUnnamedSequenceGenerator();
85+
86+
protected abstract void handleNamedSequenceGenerator();
87+
88+
private void handleTableStrategy() {
89+
if ( generatedValue.generator().isEmpty() ) {
90+
handleUnnamedTableGenerator();
91+
}
92+
else {
93+
handleNamedTableGenerator();
94+
}
95+
}
96+
97+
protected abstract void handleUnnamedTableGenerator();
98+
99+
protected abstract void handleNamedTableGenerator();
100+
101+
private void handleAutoStrategy() {
102+
if ( generatedValue.generator().isEmpty() ) {
103+
handleUnnamedAutoGenerator();
104+
}
105+
else {
106+
handleNamedAutoGenerator();
107+
}
108+
}
109+
110+
protected abstract void handleUnnamedAutoGenerator();
111+
112+
protected abstract void handleNamedAutoGenerator();
113+
114+
protected boolean handleAsMetaAnnotated() {
115+
final Annotation fromMember = findGeneratorAnnotation( idMember );
116+
if ( fromMember != null ) {
117+
handleIdGeneratorType( fromMember, idValue, idMember, buildingContext );
118+
return true;
119+
}
120+
121+
final Annotation fromClass = findGeneratorAnnotation( idMember.getDeclaringType() );
122+
if ( fromClass != null ) {
123+
handleIdGeneratorType( fromClass, idValue, idMember, buildingContext );
124+
return true;
125+
}
126+
127+
final ClassDetails packageInfoDetails = GeneratorAnnotationHelper.locatePackageInfoDetails( idMember.getDeclaringType(), buildingContext );
128+
if ( packageInfoDetails != null ) {
129+
final Annotation fromPackage = findGeneratorAnnotation( packageInfoDetails );
130+
if ( fromPackage != null ) {
131+
handleIdGeneratorType( fromPackage, idValue, idMember, buildingContext );
132+
return true;
133+
}
134+
}
135+
136+
return false;
137+
}
138+
139+
private Annotation findGeneratorAnnotation(AnnotationTarget annotationTarget) {
140+
final List<? extends Annotation> metaAnnotated = annotationTarget.getMetaAnnotated( IdGeneratorType.class, buildingContext.getMetadataCollector().getSourceModelBuildingContext() );
141+
if ( CollectionHelper.size( metaAnnotated ) > 0 ) {
142+
return metaAnnotated.get( 0 );
143+
}
144+
145+
return null;
146+
}
147+
148+
protected boolean handleAsLegacyGenerator() {
149+
// Handle a few legacy Hibernate generators...
150+
final String nameFromGeneratedValue = generatedValue.generator();
151+
if ( !nameFromGeneratedValue.isEmpty() ) {
152+
final Class<? extends Generator> legacyNamedGenerator = mapLegacyNamedGenerator( nameFromGeneratedValue, idValue );
153+
if ( legacyNamedGenerator != null ) {
154+
final Map<String,String> configuration = buildLegacyGeneratorConfig();
155+
//noinspection unchecked,rawtypes
156+
GeneratorBinder.createGeneratorFrom(
157+
new IdentifierGeneratorDefinition( nameFromGeneratedValue, legacyNamedGenerator.getName(), configuration ),
158+
idValue,
159+
(Map) configuration,
160+
buildingContext
161+
);
162+
return true;
163+
}
164+
}
165+
166+
return false;
167+
}
168+
169+
private HashMap<String, String> buildLegacyGeneratorConfig() {
170+
final Database database = buildingContext.getMetadataCollector().getDatabase();
171+
final Dialect dialect = database.getDialect();
172+
173+
final HashMap<String, String> configuration = new HashMap<>();
174+
175+
final String tableName = idValue.getTable().getQuotedName( dialect );
176+
configuration.put( TABLE, tableName );
177+
178+
final Column idColumn = (Column) idValue.getSelectables().get( 0);
179+
final String idColumnName = idColumn.getQuotedName( dialect );
180+
configuration.put( PK, idColumnName );
181+
182+
configuration.put( ENTITY_NAME, entityMapping.getEntityName() );
183+
configuration.put( JPA_ENTITY_NAME, entityMapping.getJpaEntityName() );
184+
185+
// The table name is not really a good default for subselect entities,
186+
// so use the JPA entity name which is short
187+
configuration.put(
188+
IMPLICIT_NAME_BASE,
189+
idValue.getTable().isSubselect()
190+
? entityMapping.getJpaEntityName()
191+
: idValue.getTable().getName()
192+
);
193+
194+
configuration.put( TABLES, identityTablesString( dialect, entityMapping.getRootClass() ) );
195+
196+
return configuration;
197+
}
198+
}

0 commit comments

Comments
 (0)