HHH-18139 isolate generator creation in GeneratorBinder
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
46dd56c715
commit
c8c92cfcbf
|
@ -58,6 +58,8 @@ import static org.hibernate.boot.model.internal.AnnotatedClassType.ENTITY;
|
|||
import static org.hibernate.boot.model.internal.FilterDefBinder.bindFilterDefs;
|
||||
import static org.hibernate.boot.model.internal.GeneratorBinder.buildGenerators;
|
||||
import static org.hibernate.boot.model.internal.GeneratorBinder.buildIdGenerator;
|
||||
import static org.hibernate.boot.model.internal.GeneratorBinder.buildSequenceIdGenerator;
|
||||
import static org.hibernate.boot.model.internal.GeneratorBinder.buildTableIdGenerator;
|
||||
import static org.hibernate.boot.model.internal.InheritanceState.getInheritanceStateOfSuperEntity;
|
||||
import static org.hibernate.boot.model.internal.InheritanceState.getSuperclassInheritanceState;
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
|
@ -155,16 +157,16 @@ public final class AnnotationBinder {
|
|||
}
|
||||
|
||||
private static void handleIdGenerators(ClassDetails packageInfoClassDetails, MetadataBuildingContext context) {
|
||||
packageInfoClassDetails.forEachAnnotationUsage( SequenceGenerator.class, (usage) -> {
|
||||
IdentifierGeneratorDefinition idGen = buildIdGenerator( usage, context );
|
||||
packageInfoClassDetails.forEachAnnotationUsage( SequenceGenerator.class, usage -> {
|
||||
IdentifierGeneratorDefinition idGen = buildSequenceIdGenerator( usage );
|
||||
context.getMetadataCollector().addIdentifierGenerator( idGen );
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add sequence generator with name: {0}", idGen.getName() );
|
||||
}
|
||||
} );
|
||||
|
||||
packageInfoClassDetails.forEachAnnotationUsage( TableGenerator.class, (usage) -> {
|
||||
IdentifierGeneratorDefinition idGen = buildIdGenerator( usage, context );
|
||||
packageInfoClassDetails.forEachAnnotationUsage( TableGenerator.class, usage -> {
|
||||
IdentifierGeneratorDefinition idGen = buildTableIdGenerator( usage );
|
||||
context.getMetadataCollector().addIdentifierGenerator( idGen );
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add table generator with name: {0}", idGen.getName() );
|
||||
|
@ -173,13 +175,13 @@ public final class AnnotationBinder {
|
|||
}
|
||||
|
||||
private static void bindGenericGenerators(AnnotationTarget annotatedElement, MetadataBuildingContext context) {
|
||||
annotatedElement.forEachAnnotationUsage( GenericGenerator.class, (usage) -> {
|
||||
annotatedElement.forEachAnnotationUsage( GenericGenerator.class, usage -> {
|
||||
bindGenericGenerator( usage, context );
|
||||
} );
|
||||
}
|
||||
|
||||
private static void bindGenericGenerator(AnnotationUsage<GenericGenerator> def, MetadataBuildingContext context) {
|
||||
context.getMetadataCollector().addIdentifierGenerator( buildIdGenerator( def, context ) );
|
||||
context.getMetadataCollector().addIdentifierGenerator( buildIdGenerator( def ) );
|
||||
}
|
||||
|
||||
public static void bindQueries(AnnotationTarget annotationTarget, MetadataBuildingContext context) {
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
package org.hibernate.boot.model.internal;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
@ -22,22 +23,43 @@ import org.hibernate.annotations.ValueGenerationType;
|
|||
import org.hibernate.boot.internal.GenerationStrategyInterpreter;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.model.relational.ExportableProducer;
|
||||
import org.hibernate.boot.model.source.internal.hbm.MappingDocument;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.boot.spi.InFlightMetadataCollector;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.boot.spi.PropertyData;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.generator.AnnotationBasedGenerator;
|
||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.generator.GeneratorCreationContext;
|
||||
import org.hibernate.generator.OnExecutionGenerator;
|
||||
import org.hibernate.id.Assigned;
|
||||
import org.hibernate.id.Configurable;
|
||||
import org.hibernate.id.ForeignGenerator;
|
||||
import org.hibernate.id.GUIDGenerator;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.IdentityGenerator;
|
||||
import org.hibernate.id.IncrementGenerator;
|
||||
import org.hibernate.id.OptimizableGenerator;
|
||||
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||
import org.hibernate.id.SelectGenerator;
|
||||
import org.hibernate.id.UUIDGenerator;
|
||||
import org.hibernate.id.UUIDHexGenerator;
|
||||
import org.hibernate.id.enhanced.LegacyNamingStrategy;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.id.enhanced.SingleNamingStrategy;
|
||||
import org.hibernate.id.factory.spi.CustomIdGeneratorCreationContext;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.GeneratorCreator;
|
||||
import org.hibernate.mapping.IdentifierGeneratorCreator;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.models.spi.AnnotationTarget;
|
||||
import org.hibernate.models.spi.AnnotationUsage;
|
||||
import org.hibernate.models.spi.ClassDetails;
|
||||
|
@ -58,13 +80,186 @@ import jakarta.persistence.Version;
|
|||
import static org.hibernate.boot.model.internal.AnnotationHelper.extractParameterMap;
|
||||
import static org.hibernate.boot.model.internal.BinderHelper.isCompositeId;
|
||||
import static org.hibernate.boot.model.internal.BinderHelper.isGlobalGeneratorNameGlobal;
|
||||
import static org.hibernate.id.factory.internal.IdentifierGeneratorUtil.collectParameters;
|
||||
import static org.hibernate.internal.util.ReflectHelper.getDefaultConstructor;
|
||||
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
||||
import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY;
|
||||
|
||||
public class GeneratorBinder {
|
||||
|
||||
private static final Logger LOG = CoreLogging.logger( BinderHelper.class );
|
||||
|
||||
public static Generator createLegacyIdentifierGenerator(
|
||||
SimpleValue simpleValue,
|
||||
Dialect dialect,
|
||||
String defaultCatalog,
|
||||
String defaultSchema,
|
||||
RootClass rootClass) {
|
||||
final Class<? extends Generator> generatorClass = generatorClass( simpleValue );
|
||||
final Constructor<? extends Generator> defaultConstructor = getDefaultConstructor( generatorClass );
|
||||
if ( defaultConstructor == null ) {
|
||||
throw new org.hibernate.InstantiationException( "No default constructor for id generator class", generatorClass );
|
||||
}
|
||||
final Generator identifierGenerator;
|
||||
try {
|
||||
identifierGenerator = defaultConstructor.newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new org.hibernate.InstantiationException( "Could not instantiate id generator", generatorClass, e );
|
||||
}
|
||||
if ( identifierGenerator instanceof Configurable ) {
|
||||
final Properties parameters = collectParameters( simpleValue, dialect, defaultCatalog, defaultSchema, rootClass );
|
||||
final Configurable configurable = (Configurable) identifierGenerator;
|
||||
configurable.configure( simpleValue.getType(), parameters, simpleValue.getServiceRegistry() );
|
||||
}
|
||||
return identifierGenerator;
|
||||
}
|
||||
|
||||
private static Class<? extends Generator> generatorClass(SimpleValue simpleValue) {
|
||||
String strategy = simpleValue.getIdentifierGeneratorStrategy();
|
||||
if ( "native".equals(strategy) ) {
|
||||
strategy =
|
||||
simpleValue.getMetadata().getDatabase().getDialect()
|
||||
.getNativeIdentifierGeneratorStrategy();
|
||||
}
|
||||
switch (strategy) {
|
||||
case "assigned":
|
||||
return Assigned.class;
|
||||
case "enhanced-sequence":
|
||||
case "sequence":
|
||||
return SequenceStyleGenerator.class;
|
||||
case "enhanced-table":
|
||||
case "table":
|
||||
return org.hibernate.id.enhanced.TableGenerator.class;
|
||||
case "identity":
|
||||
return IdentityGenerator.class;
|
||||
case "increment":
|
||||
return IncrementGenerator.class;
|
||||
case "foreign":
|
||||
return ForeignGenerator.class;
|
||||
case "uuid":
|
||||
case "uuid.hex":
|
||||
return UUIDHexGenerator.class;
|
||||
case "uuid2":
|
||||
return UUIDGenerator.class;
|
||||
case "select":
|
||||
return SelectGenerator.class;
|
||||
case "guid":
|
||||
return GUIDGenerator.class;
|
||||
}
|
||||
final Class<? extends Generator> clazz =
|
||||
simpleValue.getServiceRegistry().requireService( ClassLoaderService.class )
|
||||
.classForName( strategy );
|
||||
if ( !Generator.class.isAssignableFrom( clazz ) ) {
|
||||
// in principle, this shouldn't happen, since @GenericGenerator
|
||||
// constrains the type to subtypes of Generator
|
||||
throw new MappingException( clazz.getName() + " does not implement 'Generator'" );
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public static Properties collectParameters(
|
||||
SimpleValue simpleValue,
|
||||
Dialect dialect,
|
||||
String defaultCatalog,
|
||||
String defaultSchema,
|
||||
RootClass rootClass) {
|
||||
final ConfigurationService configService =
|
||||
simpleValue.getMetadata().getMetadataBuildingOptions().getServiceRegistry()
|
||||
.requireService( ConfigurationService.class );
|
||||
|
||||
final Properties params = new Properties();
|
||||
|
||||
// This is for backwards compatibility only;
|
||||
// when this method is called by Hibernate ORM, defaultSchema and defaultCatalog are always
|
||||
// null, and defaults are handled later.
|
||||
if ( defaultSchema != null ) {
|
||||
params.setProperty( PersistentIdentifierGenerator.SCHEMA, defaultSchema);
|
||||
}
|
||||
|
||||
if ( defaultCatalog != null ) {
|
||||
params.setProperty( PersistentIdentifierGenerator.CATALOG, defaultCatalog);
|
||||
}
|
||||
|
||||
// default initial value and allocation size per-JPA defaults
|
||||
params.setProperty( OptimizableGenerator.INITIAL_PARAM,
|
||||
String.valueOf( OptimizableGenerator.DEFAULT_INITIAL_VALUE ) );
|
||||
|
||||
params.setProperty( OptimizableGenerator.INCREMENT_PARAM,
|
||||
String.valueOf( defaultIncrement( configService ) ) );
|
||||
//init the table here instead of earlier, so that we can get a quoted table name
|
||||
//TODO: would it be better to simply pass the qualified table name, instead of
|
||||
// splitting it up into schema/catalog/table names
|
||||
final String tableName = simpleValue.getTable().getQuotedName( dialect );
|
||||
params.setProperty( PersistentIdentifierGenerator.TABLE, tableName );
|
||||
|
||||
//pass the column name (a generated id almost always has a single column)
|
||||
final Column column = (Column) simpleValue.getSelectables().get(0);
|
||||
final String columnName = column.getQuotedName( dialect );
|
||||
params.setProperty( PersistentIdentifierGenerator.PK, columnName );
|
||||
|
||||
//pass the entity-name, if not a collection-id
|
||||
if ( rootClass != null ) {
|
||||
params.setProperty( IdentifierGenerator.ENTITY_NAME, rootClass.getEntityName() );
|
||||
params.setProperty( IdentifierGenerator.JPA_ENTITY_NAME, rootClass.getJpaEntityName() );
|
||||
// The table name is not really a good default for subselect entities,
|
||||
// so use the JPA entity name which is short
|
||||
params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE,
|
||||
simpleValue.getTable().isSubselect()
|
||||
? rootClass.getJpaEntityName()
|
||||
: simpleValue.getTable().getName() );
|
||||
|
||||
params.setProperty( PersistentIdentifierGenerator.TABLES,
|
||||
identityTablesString( dialect, rootClass ) );
|
||||
}
|
||||
else {
|
||||
params.setProperty( PersistentIdentifierGenerator.TABLES, tableName );
|
||||
params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE, tableName );
|
||||
}
|
||||
|
||||
if ( simpleValue.getIdentifierGeneratorParameters() != null ) {
|
||||
params.putAll( simpleValue.getIdentifierGeneratorParameters() );
|
||||
}
|
||||
|
||||
// TODO : we should pass along all settings once "config lifecycle" is hashed out...
|
||||
|
||||
params.put( IdentifierGenerator.CONTRIBUTOR_NAME,
|
||||
simpleValue.getBuildingContext().getCurrentContributorName() );
|
||||
|
||||
final Map<String, Object> settings = configService.getSettings();
|
||||
if ( settings.containsKey( AvailableSettings.PREFERRED_POOLED_OPTIMIZER ) ) {
|
||||
params.put( AvailableSettings.PREFERRED_POOLED_OPTIMIZER,
|
||||
settings.get( AvailableSettings.PREFERRED_POOLED_OPTIMIZER ) );
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private static String identityTablesString(Dialect dialect, RootClass rootClass) {
|
||||
final StringBuilder tables = new StringBuilder();
|
||||
for ( Table table : rootClass.getIdentityTables() ) {
|
||||
tables.append( table.getQuotedName( dialect ) );
|
||||
if ( tables.length()>0 ) {
|
||||
tables.append( ", " );
|
||||
}
|
||||
}
|
||||
return tables.toString();
|
||||
}
|
||||
|
||||
private static int defaultIncrement(ConfigurationService configService) {
|
||||
final String idNamingStrategy =
|
||||
configService.getSetting( AvailableSettings.ID_DB_STRUCTURE_NAMING_STRATEGY,
|
||||
StandardConverters.STRING, null );
|
||||
if ( LegacyNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|
||||
|| LegacyNamingStrategy.class.getName().equals( idNamingStrategy )
|
||||
|| SingleNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|
||||
|| SingleNamingStrategy.class.getName().equals( idNamingStrategy ) ) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return OptimizableGenerator.DEFAULT_INCREMENT_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply an id generation strategy and parameters to the
|
||||
* given {@link SimpleValue} which represents an identifier.
|
||||
|
@ -79,8 +274,6 @@ public class GeneratorBinder {
|
|||
LOG.debugf( "#makeIdGenerator(%s, %s, %s, %s, ...)", id, idAttributeMember, generatorType, generatorName );
|
||||
|
||||
//generator settings
|
||||
id.setIdentifierGeneratorStrategy( generatorType );
|
||||
|
||||
final Map<String,Object> parameters = new HashMap<>();
|
||||
|
||||
//always settable
|
||||
|
@ -95,12 +288,8 @@ public class GeneratorBinder {
|
|||
|
||||
if ( !generatorName.isEmpty() ) {
|
||||
//we have a named generator
|
||||
final IdentifierGeneratorDefinition definition = makeIdentifierGeneratorDefinition(
|
||||
generatorName,
|
||||
idAttributeMember,
|
||||
localGenerators,
|
||||
buildingContext
|
||||
);
|
||||
final IdentifierGeneratorDefinition definition =
|
||||
makeIdentifierGeneratorDefinition( generatorName, idAttributeMember, localGenerators, buildingContext );
|
||||
if ( definition == null ) {
|
||||
throw new AnnotationException( "No id generator was declared with the name '" + generatorName
|
||||
+ "' specified by '@GeneratedValue'"
|
||||
|
@ -109,21 +298,20 @@ public class GeneratorBinder {
|
|||
//This is quite vague in the spec but a generator could override the generator choice
|
||||
final String identifierGeneratorStrategy = definition.getStrategy();
|
||||
//yuk! this is a hack not to override 'AUTO' even if generator is set
|
||||
final boolean avoidOverriding = identifierGeneratorStrategy.equals( "identity" )
|
||||
final boolean avoidOverriding =
|
||||
identifierGeneratorStrategy.equals( "identity" )
|
||||
|| identifierGeneratorStrategy.equals( "seqhilo" );
|
||||
if ( generatorType == null || !avoidOverriding ) {
|
||||
id.setIdentifierGeneratorStrategy( identifierGeneratorStrategy );
|
||||
if ( DEFAULT_ID_GEN_STRATEGY.equals( identifierGeneratorStrategy ) ) {
|
||||
id.setNullValue( "undefined" );
|
||||
}
|
||||
generatorType = identifierGeneratorStrategy;
|
||||
}
|
||||
//checkIfMatchingGenerator(definition, generatorType, generatorName);
|
||||
parameters.putAll( definition.getParameters() );
|
||||
}
|
||||
id.setIdentifierGeneratorStrategy( generatorType );
|
||||
id.setIdentifierGeneratorParameters( parameters );
|
||||
if ( DEFAULT_ID_GEN_STRATEGY.equals( generatorType ) ) {
|
||||
id.setNullValue( "undefined" );
|
||||
}
|
||||
id.setIdentifierGeneratorParameters( parameters );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,23 +379,20 @@ public class GeneratorBinder {
|
|||
final InFlightMetadataCollector metadataCollector = context.getMetadataCollector();
|
||||
final Map<String, IdentifierGeneratorDefinition> generators = new HashMap<>();
|
||||
|
||||
annotatedElement.forEachAnnotationUsage( TableGenerator.class, (usage) -> {
|
||||
IdentifierGeneratorDefinition idGenerator = buildIdGenerator( usage, context );
|
||||
generators.put(
|
||||
idGenerator.getName(),
|
||||
idGenerator
|
||||
);
|
||||
metadataCollector.addIdentifierGenerator( idGenerator );
|
||||
} );
|
||||
|
||||
annotatedElement.forEachAnnotationUsage( SequenceGenerator.class, (usage) -> {
|
||||
IdentifierGeneratorDefinition idGenerator = buildIdGenerator( usage, context );
|
||||
annotatedElement.forEachAnnotationUsage( TableGenerator.class, usage -> {
|
||||
IdentifierGeneratorDefinition idGenerator = buildTableIdGenerator( usage );
|
||||
generators.put( idGenerator.getName(), idGenerator );
|
||||
metadataCollector.addIdentifierGenerator( idGenerator );
|
||||
} );
|
||||
|
||||
annotatedElement.forEachAnnotationUsage( GenericGenerator.class, (usage) -> {
|
||||
final IdentifierGeneratorDefinition idGenerator = buildIdGenerator( usage, context );
|
||||
annotatedElement.forEachAnnotationUsage( SequenceGenerator.class, usage -> {
|
||||
IdentifierGeneratorDefinition idGenerator = buildSequenceIdGenerator( usage );
|
||||
generators.put( idGenerator.getName(), idGenerator );
|
||||
metadataCollector.addIdentifierGenerator( idGenerator );
|
||||
} );
|
||||
|
||||
annotatedElement.forEachAnnotationUsage( GenericGenerator.class, usage -> {
|
||||
final IdentifierGeneratorDefinition idGenerator = buildIdGenerator( usage );
|
||||
generators.put( idGenerator.getName(), idGenerator );
|
||||
metadataCollector.addIdentifierGenerator( idGenerator );
|
||||
} );
|
||||
|
@ -252,50 +437,50 @@ public class GeneratorBinder {
|
|||
);
|
||||
}
|
||||
|
||||
static IdentifierGeneratorDefinition buildIdGenerator(
|
||||
AnnotationUsage<?> generatorAnnotation,
|
||||
MetadataBuildingContext context) {
|
||||
static IdentifierGeneratorDefinition buildIdGenerator(AnnotationUsage<GenericGenerator> generatorAnnotation) {
|
||||
if ( generatorAnnotation == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final IdentifierGeneratorDefinition.Builder definitionBuilder = new IdentifierGeneratorDefinition.Builder();
|
||||
if ( TableGenerator.class.isAssignableFrom( generatorAnnotation.getAnnotationType() ) ) {
|
||||
//noinspection unchecked
|
||||
GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretTableGenerator(
|
||||
(AnnotationUsage<TableGenerator>) generatorAnnotation,
|
||||
definitionBuilder
|
||||
);
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add table generator with name: {0}", definitionBuilder.getName() );
|
||||
}
|
||||
definitionBuilder.setName( generatorAnnotation.getString( "name" ) );
|
||||
final Class<? extends Generator> generatorClass =
|
||||
generatorAnnotation.getClassDetails( "type" ).toJavaClass();
|
||||
final String strategy = generatorClass.equals(Generator.class)
|
||||
? generatorAnnotation.getString( "strategy" )
|
||||
: generatorClass.getName();
|
||||
definitionBuilder.setStrategy( strategy );
|
||||
definitionBuilder.addParams( extractParameterMap( generatorAnnotation.getList( "parameters" ) ) );
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add generic generator with name: {0}", definitionBuilder.getName() );
|
||||
}
|
||||
else if ( SequenceGenerator.class.isAssignableFrom( generatorAnnotation.getAnnotationType() ) ) {
|
||||
//noinspection unchecked
|
||||
GenerationStrategyInterpreter.STRATEGY_INTERPRETER.interpretSequenceGenerator(
|
||||
(AnnotationUsage<SequenceGenerator>) generatorAnnotation,
|
||||
definitionBuilder
|
||||
);
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add sequence generator with name: {0}", definitionBuilder.getName() );
|
||||
}
|
||||
return definitionBuilder.build();
|
||||
}
|
||||
|
||||
static IdentifierGeneratorDefinition buildTableIdGenerator(AnnotationUsage<TableGenerator> generatorAnnotation) {
|
||||
if ( generatorAnnotation == null ) {
|
||||
return null;
|
||||
}
|
||||
else if ( GenericGenerator.class.isAssignableFrom( generatorAnnotation.getAnnotationType() ) ) {
|
||||
//noinspection unchecked
|
||||
final AnnotationUsage<GenericGenerator> genericGenerator = (AnnotationUsage<GenericGenerator>) generatorAnnotation;
|
||||
definitionBuilder.setName( genericGenerator.getString( "name" ) );
|
||||
final Class<? extends Generator> generatorClass = genericGenerator.getClassDetails( "type" ).toJavaClass();
|
||||
final String strategy = generatorClass.equals(Generator.class)
|
||||
? genericGenerator.getString( "strategy" )
|
||||
: generatorClass.getName();
|
||||
definitionBuilder.setStrategy( strategy );
|
||||
definitionBuilder.addParams( extractParameterMap( genericGenerator.getList( "parameters" ) ) );
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add generic generator with name: {0}", definitionBuilder.getName() );
|
||||
}
|
||||
|
||||
final IdentifierGeneratorDefinition.Builder definitionBuilder = new IdentifierGeneratorDefinition.Builder();
|
||||
GenerationStrategyInterpreter.STRATEGY_INTERPRETER
|
||||
.interpretTableGenerator( generatorAnnotation, definitionBuilder );
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add table generator with name: {0}", definitionBuilder.getName() );
|
||||
}
|
||||
else {
|
||||
throw new AssertionFailure( "Unknown Generator annotation: " + generatorAnnotation );
|
||||
return definitionBuilder.build();
|
||||
}
|
||||
|
||||
static IdentifierGeneratorDefinition buildSequenceIdGenerator(AnnotationUsage<SequenceGenerator> generatorAnnotation) {
|
||||
if ( generatorAnnotation == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final IdentifierGeneratorDefinition.Builder definitionBuilder = new IdentifierGeneratorDefinition.Builder();
|
||||
GenerationStrategyInterpreter.STRATEGY_INTERPRETER
|
||||
.interpretSequenceGenerator( generatorAnnotation, definitionBuilder );
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Add sequence generator with name: {0}", definitionBuilder.getName() );
|
||||
}
|
||||
return definitionBuilder.build();
|
||||
}
|
||||
|
@ -513,13 +698,14 @@ public class GeneratorBinder {
|
|||
private static void callConfigure(GeneratorCreationContext creationContext, Generator generator) {
|
||||
if ( generator instanceof Configurable ) {
|
||||
final Value value = creationContext.getProperty().getValue();
|
||||
( (Configurable) generator ).configure( value.getType(), collectParameters(
|
||||
Properties parameters = collectParameters(
|
||||
(SimpleValue) value,
|
||||
creationContext.getDatabase().getDialect(),
|
||||
creationContext.getDefaultCatalog(),
|
||||
creationContext.getDefaultSchema(),
|
||||
creationContext.getPersistentClass().getRootClass()
|
||||
), creationContext.getServiceRegistry() );
|
||||
);
|
||||
( (Configurable) generator ).configure( value.getType(), parameters, creationContext.getServiceRegistry() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,4 +757,43 @@ public class GeneratorBinder {
|
|||
foreignGeneratorBuilder.addParam( "property", mapsIdProperty.getPropertyName() );
|
||||
return foreignGeneratorBuilder.build();
|
||||
}
|
||||
|
||||
public static void makeIdentifier(
|
||||
final MappingDocument sourceDocument,
|
||||
IdentifierGeneratorDefinition generator,
|
||||
String unsavedValue,
|
||||
SimpleValue identifierValue,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
if ( generator != null ) {
|
||||
final Map<String,Object> params = new HashMap<>();
|
||||
|
||||
// see if the specified generator name matches a registered <identifier-generator/>
|
||||
String generatorName = generator.getStrategy();
|
||||
final IdentifierGeneratorDefinition generatorDef =
|
||||
sourceDocument.getMetadataCollector().getIdentifierGenerator( generatorName );
|
||||
if ( generatorDef != null ) {
|
||||
generatorName = generatorDef.getStrategy();
|
||||
params.putAll( generatorDef.getParameters() );
|
||||
}
|
||||
|
||||
// YUCK! but cannot think of a clean way to do this given the string-config based scheme
|
||||
params.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER,
|
||||
buildingContext.getObjectNameNormalizer() );
|
||||
|
||||
params.putAll( generator.getParameters() );
|
||||
|
||||
identifierValue.setIdentifierGeneratorStrategy( generatorName );
|
||||
identifierValue.setIdentifierGeneratorParameters( params );
|
||||
}
|
||||
|
||||
if ( isNotEmpty( unsavedValue ) ) {
|
||||
identifierValue.setNullValue( unsavedValue );
|
||||
}
|
||||
else if ( DEFAULT_ID_GEN_STRATEGY.equals( identifierValue.getIdentifierGeneratorStrategy() ) ) {
|
||||
identifierValue.setNullValue( "undefined" );
|
||||
}
|
||||
else {
|
||||
identifierValue.setNullValue( null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@ import org.hibernate.boot.model.naming.ImplicitIndexColumnNameSource;
|
|||
import org.hibernate.boot.model.naming.ImplicitMapKeyColumnNameSource;
|
||||
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
|
||||
import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource;
|
||||
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.model.relational.Namespace;
|
||||
import org.hibernate.boot.model.source.internal.ImplicitColumnNamingSecondPass;
|
||||
|
@ -108,7 +107,6 @@ import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
|||
import org.hibernate.engine.spi.FilterDefinition;
|
||||
import org.hibernate.generator.internal.GeneratedGeneration;
|
||||
import org.hibernate.generator.internal.SourceGeneration;
|
||||
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
@ -162,6 +160,7 @@ import org.hibernate.usertype.CompositeUserType;
|
|||
import org.hibernate.usertype.ParameterizedType;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdentifier;
|
||||
import static org.hibernate.boot.model.naming.Identifier.toIdentifier;
|
||||
import static org.hibernate.boot.model.source.internal.hbm.Helper.reflectedPropertyClass;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_ENTITY_WHERE_CLAUSE_FOR_COLLECTIONS;
|
||||
|
@ -169,7 +168,6 @@ import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
|
|||
import static org.hibernate.internal.util.StringHelper.getNonEmptyOrConjunctionIfBothNonEmpty;
|
||||
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
||||
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
|
||||
import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY;
|
||||
|
||||
/**
|
||||
* Responsible for coordinating the binding of all information inside entity tags ({@code <class/>}, etc).
|
||||
|
@ -182,7 +180,6 @@ public class ModelBinder {
|
|||
private final MetadataBuildingContext metadataBuildingContext;
|
||||
|
||||
private final Database database;
|
||||
private final ObjectNameNormalizer objectNameNormalizer;
|
||||
private final ImplicitNamingStrategy implicitNamingStrategy;
|
||||
private final RelationalObjectBinder relationalObjectBinder;
|
||||
|
||||
|
@ -194,12 +191,6 @@ public class ModelBinder {
|
|||
this.metadataBuildingContext = context;
|
||||
|
||||
this.database = context.getMetadataCollector().getDatabase();
|
||||
this.objectNameNormalizer = new ObjectNameNormalizer() {
|
||||
@Override
|
||||
protected MetadataBuildingContext getBuildingContext() {
|
||||
return context;
|
||||
}
|
||||
};
|
||||
this.implicitNamingStrategy = context.getBuildingOptions().getImplicitNamingStrategy();
|
||||
this.relationalObjectBinder = new RelationalObjectBinder( context );
|
||||
}
|
||||
|
@ -752,47 +743,11 @@ public class ModelBinder {
|
|||
sourceDocument,
|
||||
idSource.getIdentifierGeneratorDescriptor(),
|
||||
idSource.getUnsavedValue(),
|
||||
idValue
|
||||
idValue,
|
||||
metadataBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
private void makeIdentifier(
|
||||
final MappingDocument sourceDocument,
|
||||
IdentifierGeneratorDefinition generator,
|
||||
String unsavedValue,
|
||||
SimpleValue identifierValue) {
|
||||
if ( generator != null ) {
|
||||
final Map<String,Object> params = new HashMap<>();
|
||||
|
||||
// see if the specified generator name matches a registered <identifier-generator/>
|
||||
String generatorName = generator.getStrategy();
|
||||
final IdentifierGeneratorDefinition generatorDef = sourceDocument.getMetadataCollector()
|
||||
.getIdentifierGenerator( generatorName );
|
||||
if ( generatorDef != null ) {
|
||||
generatorName = generatorDef.getStrategy();
|
||||
params.putAll( generatorDef.getParameters() );
|
||||
}
|
||||
identifierValue.setIdentifierGeneratorStrategy( generatorName );
|
||||
|
||||
// YUCK! but cannot think of a clean way to do this given the string-config based scheme
|
||||
params.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, objectNameNormalizer );
|
||||
|
||||
params.putAll( generator.getParameters() );
|
||||
|
||||
identifierValue.setIdentifierGeneratorParameters( params );
|
||||
}
|
||||
|
||||
if ( isNotEmpty( unsavedValue ) ) {
|
||||
identifierValue.setNullValue( unsavedValue );
|
||||
}
|
||||
else if ( DEFAULT_ID_GEN_STRATEGY.equals( identifierValue.getIdentifierGeneratorStrategy() ) ) {
|
||||
identifierValue.setNullValue( "undefined" );
|
||||
}
|
||||
else {
|
||||
identifierValue.setNullValue( null );
|
||||
}
|
||||
}
|
||||
|
||||
private void bindAggregatedCompositeEntityIdentifier(
|
||||
MappingDocument mappingDocument,
|
||||
EntityHierarchySourceImpl hierarchySource,
|
||||
|
@ -949,7 +904,8 @@ public class ModelBinder {
|
|||
sourceDocument,
|
||||
identifierSource.getIdentifierGeneratorDescriptor(),
|
||||
null,
|
||||
cid
|
||||
cid,
|
||||
metadataBuildingContext
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3348,7 +3304,8 @@ public class ModelBinder {
|
|||
mappingDocument,
|
||||
new IdentifierGeneratorDefinition( idSource.getGeneratorName(), idSource.getParameters() ),
|
||||
null,
|
||||
idBinding
|
||||
idBinding,
|
||||
metadataBuildingContext
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,218 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.id.factory.internal;
|
||||
|
||||
import org.hibernate.InstantiationException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.id.Assigned;
|
||||
import org.hibernate.id.Configurable;
|
||||
import org.hibernate.id.ForeignGenerator;
|
||||
import org.hibernate.id.GUIDGenerator;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.IdentityGenerator;
|
||||
import org.hibernate.id.IncrementGenerator;
|
||||
import org.hibernate.id.OptimizableGenerator;
|
||||
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||
import org.hibernate.id.SelectGenerator;
|
||||
import org.hibernate.id.UUIDGenerator;
|
||||
import org.hibernate.id.UUIDHexGenerator;
|
||||
import org.hibernate.id.enhanced.LegacyNamingStrategy;
|
||||
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||
import org.hibernate.id.enhanced.SingleNamingStrategy;
|
||||
import org.hibernate.id.enhanced.TableGenerator;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.RootClass;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.generator.Generator;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.hibernate.internal.util.ReflectHelper.getDefaultConstructor;
|
||||
|
||||
public class IdentifierGeneratorUtil {
|
||||
|
||||
public static Generator createLegacyIdentifierGenerator(
|
||||
SimpleValue simpleValue,
|
||||
Dialect dialect,
|
||||
String defaultCatalog,
|
||||
String defaultSchema,
|
||||
RootClass rootClass) {
|
||||
final Class<? extends Generator> generatorClass = generatorClass( simpleValue );
|
||||
final Constructor<? extends Generator> defaultConstructor = getDefaultConstructor( generatorClass );
|
||||
if ( defaultConstructor == null ) {
|
||||
throw new InstantiationException( "No default constructor for id generator class", generatorClass );
|
||||
}
|
||||
final Generator identifierGenerator;
|
||||
try {
|
||||
identifierGenerator = defaultConstructor.newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new InstantiationException( "Could not instantiate id generator", generatorClass, e );
|
||||
}
|
||||
if ( identifierGenerator instanceof Configurable ) {
|
||||
final Properties parameters = collectParameters( simpleValue, dialect, defaultCatalog, defaultSchema, rootClass );
|
||||
final Configurable configurable = (Configurable) identifierGenerator;
|
||||
configurable.configure( simpleValue.getType(), parameters, simpleValue.getServiceRegistry() );
|
||||
}
|
||||
return identifierGenerator;
|
||||
}
|
||||
|
||||
private static Class<? extends Generator> generatorClass(SimpleValue simpleValue) {
|
||||
String strategy = simpleValue.getIdentifierGeneratorStrategy();
|
||||
if ( "native".equals(strategy) ) {
|
||||
strategy =
|
||||
simpleValue.getMetadata().getDatabase().getDialect()
|
||||
.getNativeIdentifierGeneratorStrategy();
|
||||
}
|
||||
switch (strategy) {
|
||||
case "assigned":
|
||||
return Assigned.class;
|
||||
case "enhanced-sequence":
|
||||
case "sequence":
|
||||
return SequenceStyleGenerator.class;
|
||||
case "enhanced-table":
|
||||
case "table":
|
||||
return TableGenerator.class;
|
||||
case "identity":
|
||||
return IdentityGenerator.class;
|
||||
case "increment":
|
||||
return IncrementGenerator.class;
|
||||
case "foreign":
|
||||
return ForeignGenerator.class;
|
||||
case "uuid":
|
||||
case "uuid.hex":
|
||||
return UUIDHexGenerator.class;
|
||||
case "uuid2":
|
||||
return UUIDGenerator.class;
|
||||
case "select":
|
||||
return SelectGenerator.class;
|
||||
case "guid":
|
||||
return GUIDGenerator.class;
|
||||
}
|
||||
final Class<? extends Generator> clazz =
|
||||
simpleValue.getServiceRegistry().requireService( ClassLoaderService.class )
|
||||
.classForName( strategy );
|
||||
if ( !Generator.class.isAssignableFrom( clazz ) ) {
|
||||
// in principle, this shouldn't happen, since @GenericGenerator
|
||||
// constrains the type to subtypes of Generator
|
||||
throw new MappingException( clazz.getName() + " does not implement 'Generator'" );
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public static Properties collectParameters(
|
||||
SimpleValue simpleValue,
|
||||
Dialect dialect,
|
||||
String defaultCatalog,
|
||||
String defaultSchema,
|
||||
RootClass rootClass) {
|
||||
final ConfigurationService configService =
|
||||
simpleValue.getMetadata().getMetadataBuildingOptions().getServiceRegistry()
|
||||
.requireService( ConfigurationService.class );
|
||||
|
||||
final Properties params = new Properties();
|
||||
|
||||
// This is for backwards compatibility only;
|
||||
// when this method is called by Hibernate ORM, defaultSchema and defaultCatalog are always
|
||||
// null, and defaults are handled later.
|
||||
if ( defaultSchema != null ) {
|
||||
params.setProperty( PersistentIdentifierGenerator.SCHEMA, defaultSchema);
|
||||
}
|
||||
|
||||
if ( defaultCatalog != null ) {
|
||||
params.setProperty( PersistentIdentifierGenerator.CATALOG, defaultCatalog);
|
||||
}
|
||||
|
||||
// default initial value and allocation size per-JPA defaults
|
||||
params.setProperty( OptimizableGenerator.INITIAL_PARAM,
|
||||
String.valueOf( OptimizableGenerator.DEFAULT_INITIAL_VALUE ) );
|
||||
|
||||
params.setProperty( OptimizableGenerator.INCREMENT_PARAM,
|
||||
String.valueOf( defaultIncrement( configService ) ) );
|
||||
//init the table here instead of earlier, so that we can get a quoted table name
|
||||
//TODO: would it be better to simply pass the qualified table name, instead of
|
||||
// splitting it up into schema/catalog/table names
|
||||
final String tableName = simpleValue.getTable().getQuotedName( dialect );
|
||||
params.setProperty( PersistentIdentifierGenerator.TABLE, tableName );
|
||||
|
||||
//pass the column name (a generated id almost always has a single column)
|
||||
final Column column = (Column) simpleValue.getSelectables().get(0);
|
||||
final String columnName = column.getQuotedName( dialect );
|
||||
params.setProperty( PersistentIdentifierGenerator.PK, columnName );
|
||||
|
||||
//pass the entity-name, if not a collection-id
|
||||
if ( rootClass != null ) {
|
||||
params.setProperty( IdentifierGenerator.ENTITY_NAME, rootClass.getEntityName() );
|
||||
params.setProperty( IdentifierGenerator.JPA_ENTITY_NAME, rootClass.getJpaEntityName() );
|
||||
// The table name is not really a good default for subselect entities,
|
||||
// so use the JPA entity name which is short
|
||||
params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE,
|
||||
simpleValue.getTable().isSubselect()
|
||||
? rootClass.getJpaEntityName()
|
||||
: simpleValue.getTable().getName() );
|
||||
|
||||
params.setProperty( PersistentIdentifierGenerator.TABLES,
|
||||
identityTablesString( dialect, rootClass ) );
|
||||
}
|
||||
else {
|
||||
params.setProperty( PersistentIdentifierGenerator.TABLES, tableName );
|
||||
params.setProperty( OptimizableGenerator.IMPLICIT_NAME_BASE, tableName );
|
||||
}
|
||||
|
||||
if ( simpleValue.getIdentifierGeneratorParameters() != null ) {
|
||||
params.putAll( simpleValue.getIdentifierGeneratorParameters() );
|
||||
}
|
||||
|
||||
// TODO : we should pass along all settings once "config lifecycle" is hashed out...
|
||||
|
||||
params.put( IdentifierGenerator.CONTRIBUTOR_NAME,
|
||||
simpleValue.getBuildingContext().getCurrentContributorName() );
|
||||
|
||||
final Map<String, Object> settings = configService.getSettings();
|
||||
if ( settings.containsKey( AvailableSettings.PREFERRED_POOLED_OPTIMIZER ) ) {
|
||||
params.put( AvailableSettings.PREFERRED_POOLED_OPTIMIZER,
|
||||
settings.get( AvailableSettings.PREFERRED_POOLED_OPTIMIZER ) );
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
private static String identityTablesString(Dialect dialect, RootClass rootClass) {
|
||||
final StringBuilder tables = new StringBuilder();
|
||||
for ( Table table : rootClass.getIdentityTables() ) {
|
||||
tables.append( table.getQuotedName( dialect ) );
|
||||
if ( tables.length()>0 ) {
|
||||
tables.append( ", " );
|
||||
}
|
||||
}
|
||||
return tables.toString();
|
||||
}
|
||||
|
||||
private static int defaultIncrement(ConfigurationService configService) {
|
||||
final String idNamingStrategy =
|
||||
configService.getSetting( AvailableSettings.ID_DB_STRUCTURE_NAMING_STRATEGY,
|
||||
StandardConverters.STRING, null );
|
||||
if ( LegacyNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|
||||
|| LegacyNamingStrategy.class.getName().equals( idNamingStrategy )
|
||||
|| SingleNamingStrategy.STRATEGY_NAME.equals( idNamingStrategy )
|
||||
|| SingleNamingStrategy.class.getName().equals( idNamingStrategy ) ) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return OptimizableGenerator.DEFAULT_INCREMENT_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -66,7 +66,7 @@ import jakarta.persistence.AttributeConverter;
|
|||
|
||||
import static java.lang.Boolean.parseBoolean;
|
||||
import static org.hibernate.boot.model.convert.spi.ConverterDescriptor.TYPE_NAME_PREFIX;
|
||||
import static org.hibernate.id.factory.internal.IdentifierGeneratorUtil.createLegacyIdentifierGenerator;
|
||||
import static org.hibernate.boot.model.internal.GeneratorBinder.createLegacyIdentifierGenerator;
|
||||
import static org.hibernate.internal.util.collections.ArrayHelper.toBooleanArray;
|
||||
|
||||
/**
|
||||
|
@ -398,7 +398,7 @@ public abstract class SimpleValue implements KeyValue {
|
|||
);
|
||||
}
|
||||
else {
|
||||
generator = createLegacyIdentifierGenerator(this, dialect, null, null, rootClass );
|
||||
generator = createLegacyIdentifierGenerator( this, dialect, null, null, rootClass );
|
||||
if ( generator instanceof IdentityGenerator ) {
|
||||
setColumnToIdentity();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue