clarify some logic around @GeneratedValue

This commit is contained in:
Gavin 2023-04-11 15:39:59 +02:00 committed by Gavin King
parent 91eb9e1f20
commit c70d9853c7
6 changed files with 68 additions and 77 deletions

View File

@ -95,22 +95,27 @@ public class IdGeneratorInterpreterImpl implements IdGeneratorStrategyInterprete
case TABLE:
return org.hibernate.id.enhanced.TableGenerator.class.getName();
case AUTO:
if ( "increment".equalsIgnoreCase( context.getGeneratedValueGeneratorName() ) ) {
return IncrementGenerator.class.getName();
}
final Class<?> javaType = context.getIdType();
if ( UUID.class.isAssignableFrom( javaType ) ) {
if ( UUID.class.isAssignableFrom( context.getIdType() ) ) {
return UUIDGenerator.class.getName();
}
return SequenceStyleGenerator.class.getName();
else if ( "increment".equalsIgnoreCase( context.getGeneratedValueGeneratorName() ) ) {
// special case for @GeneratedValue(name="increment")
// for some reason we consider there to be an implicit
// generator named 'increment' (doesn't seem very useful)
return IncrementGenerator.class.getName();
}
else {
return SequenceStyleGenerator.class.getName();
}
default:
// UNKNOWN
//case UUID:
// (use the name instead for compatibility with javax.persistence)
if ( "UUID".equals( generationType.name() ) ) {
return UUIDGenerator.class.getName();
}
throw new UnsupportedOperationException( "Unsupported generation type:" + generationType );
else {
throw new UnsupportedOperationException( "Unsupported generation type:" + generationType );
}
}
}

View File

@ -13,8 +13,10 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.Internal;
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext;
import org.hibernate.id.IdentifierGenerator;
import jakarta.persistence.GenerationType;
@ -109,12 +111,14 @@ public class IdentifierGeneratorDefinition implements Serializable {
return buildTableGeneratorDefinition( name, generationInterpreter );
// really AUTO and IDENTITY work the same in this respect, aside from the actual strategy name
case IDENTITY:
strategyName = "identity";
break;
throw new AnnotationException(
"@GeneratedValue annotation specified 'strategy=IDENTITY' and 'generator'"
+ " but the generator name is unnecessary"
);
case AUTO:
strategyName = generationInterpreter.determineGeneratorName(
generationType,
new IdGeneratorStrategyInterpreter.GeneratorNameDeterminationContext() {
new GeneratorNameDeterminationContext() {
@Override
public Class<?> getIdType() {
return idType;
@ -127,7 +131,17 @@ public class IdentifierGeneratorDefinition implements Serializable {
);
break;
default:
throw new AssertionFailure( "unknown generator type: " + generationType );
//case UUID:
// (use the name instead for compatibility with javax.persistence)
if ( "UUID".equals( generationType.name() ) ) {
throw new AnnotationException(
"@GeneratedValue annotation specified 'strategy=UUID' and 'generator'"
+ " but the generator name is unnecessary"
);
}
else {
throw new AssertionFailure( "unknown generator type: " + generationType );
}
}
return new IdentifierGeneratorDefinition(
@ -137,7 +151,8 @@ public class IdentifierGeneratorDefinition implements Serializable {
);
}
private static IdentifierGeneratorDefinition buildTableGeneratorDefinition(String name, IdGeneratorStrategyInterpreter generationInterpreter) {
private static IdentifierGeneratorDefinition buildTableGeneratorDefinition(
String name, IdGeneratorStrategyInterpreter generationInterpreter) {
final Builder builder = new Builder();
generationInterpreter.interpretTableGenerator(
new TableGenerator() {
@ -207,7 +222,8 @@ public class IdentifierGeneratorDefinition implements Serializable {
return builder.build();
}
private static IdentifierGeneratorDefinition buildSequenceGeneratorDefinition(String name, IdGeneratorStrategyInterpreter generationInterpreter) {
private static IdentifierGeneratorDefinition buildSequenceGeneratorDefinition(
String name, IdGeneratorStrategyInterpreter generationInterpreter) {
final Builder builder = new Builder();
generationInterpreter.interpretSequenceGenerator(
new SequenceGenerator() {

View File

@ -142,7 +142,7 @@ public class GeneratorBinder {
private static IdentifierGeneratorDefinition makeIdentifierGeneratorDefinition(
String name,
XProperty idXProperty,
XProperty idProperty,
Map<String, IdentifierGeneratorDefinition> localGenerators,
MetadataBuildingContext buildingContext) {
if ( localGenerators != null ) {
@ -160,7 +160,7 @@ public class GeneratorBinder {
LOG.debugf( "Could not resolve explicit IdentifierGeneratorDefinition - using implicit interpretation (%s)", name );
final GeneratedValue generatedValue = idXProperty.getAnnotation( GeneratedValue.class );
final GeneratedValue generatedValue = idProperty.getAnnotation( GeneratedValue.class );
if ( generatedValue == null ) {
// this should really never happen, but it's easy to protect against it...
return new IdentifierGeneratorDefinition( DEFAULT_ID_GEN_STRATEGY, DEFAULT_ID_GEN_STRATEGY );
@ -171,7 +171,7 @@ public class GeneratorBinder {
buildingContext
.getBootstrapContext()
.getReflectionManager()
.toClass( idXProperty.getType() ),
.toClass( idProperty.getType() ),
generatedValue.generator(),
buildingContext.getBuildingOptions().getIdGenerationTypeInterpreter(),
interpretGenerationType( generatedValue )

View File

@ -40,7 +40,6 @@ import java.util.TimeZone;
import java.util.UUID;
import java.util.regex.Pattern;
import org.hibernate.AssertionFailure;
import org.hibernate.Incubating;
import org.hibernate.Length;
import org.hibernate.LockMode;
@ -1740,35 +1739,12 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
// native identifier generation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* The "native" id generation strategy for this dialect.
* <p>
* This is the id generation strategy which should be used when {@code "native"} is
* specified in {@code hbm.xml}, or {@link GenerationType#AUTO} is specified by the
* {@link jakarta.persistence.GeneratedValue#strategy @GeneratedValue} annotation.
*
* @return The native generator strategy.
*/
@Incubating
public GenerationType getNativeIdentifierGenerationType() {
switch ( getNativeIdentifierGeneratorStrategy() ) {
case "identity":
return GenerationType.IDENTITY;
case "sequence":
return GenerationType.SEQUENCE;
case "uuid":
return GenerationType.UUID;
default:
throw new AssertionFailure( "unknown native generation type" );
}
}
/**
* The name identifying the "native" id generation strategy for this dialect.
* <p>
* This is the id generation strategy which should be used when {@code "native"} is
* specified in {@code hbm.xml}, or {@link GenerationType#AUTO} is specified by the
* {@link jakarta.persistence.GeneratedValue#strategy @GeneratedValue} annotation.
* This is the name of the id generation strategy which should be used when
* {@code "native"} is specified in {@code hbm.xml}.
*
* @return The name identifying the native generator strategy.
*/

View File

@ -352,12 +352,6 @@ public class DialectDelegateWrapper extends Dialect {
return wrapped.getLobMergeStrategy();
}
@Override
@Incubating
public GenerationType getNativeIdentifierGenerationType() {
return wrapped.getNativeIdentifierGenerationType();
}
@Override
public String getNativeIdentifierGeneratorStrategy() {
return wrapped.getNativeIdentifierGeneratorStrategy();

View File

@ -36,7 +36,6 @@ import org.hibernate.id.factory.spi.GenerationTypeStrategy;
import org.hibernate.id.factory.spi.GenerationTypeStrategyRegistration;
import org.hibernate.id.factory.spi.GeneratorDefinitionResolver;
import org.hibernate.id.factory.spi.StandardGenerator;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.jpa.spi.IdentifierGeneratorStrategyProvider;
import org.hibernate.resource.beans.container.spi.BeanContainer;
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
@ -50,6 +49,7 @@ import jakarta.persistence.GenerationType;
import static org.hibernate.cfg.AvailableSettings.IDENTIFIER_GENERATOR_STRATEGY_PROVIDER;
import static org.hibernate.id.factory.IdGenFactoryLogging.ID_GEN_FAC_LOGGER;
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
/**
* Basic implementation of {@link org.hibernate.id.factory.IdentifierGeneratorFactory},
@ -151,7 +151,7 @@ public class StandardIdentifierGeneratorFactory
final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class );
final Object providerSetting = configService.getSettings().get( IDENTIFIER_GENERATOR_STRATEGY_PROVIDER );
if ( providerSetting != null ) {
DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting2(
DEPRECATION_LOGGER.deprecatedSetting2(
IDENTIFIER_GENERATOR_STRATEGY_PROVIDER,
"supply a org.hibernate.id.factory.spi.GenerationTypeStrategyRegistration Java service"
);
@ -243,32 +243,32 @@ public class StandardIdentifierGeneratorFactory
@Override
public Class<? extends Generator> getIdentifierGeneratorClass(String strategy) {
if ( "hilo".equals( strategy ) ) {
throw new UnsupportedOperationException( "Support for 'hilo' generator has been removed" );
switch ( strategy ) {
case "hilo":
throw new UnsupportedOperationException( "Support for 'hilo' generator has been removed" );
case "native":
strategy = getDialect().getNativeIdentifierGeneratorStrategy();
//then fall through:
default:
Class<? extends Generator> generatorClass = legacyGeneratorClassNameMap.get( strategy );
return generatorClass != null ? generatorClass : generatorClassForName( strategy );
}
final String resolvedStrategy = "native".equals( strategy )
? getDialect().getNativeIdentifierGeneratorStrategy()
: strategy;
}
Class<? extends Generator> generatorClass = legacyGeneratorClassNameMap.get( resolvedStrategy );
if ( generatorClass != null ) {
return generatorClass;
private Class<? extends Generator> generatorClassForName(String strategy) {
try {
Class<? extends Generator> clazz =
serviceRegistry.getService( 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;
}
else {
try {
Class<? extends Generator> clazz =
serviceRegistry.getService( ClassLoaderService.class )
.classForName( resolvedStrategy );
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;
}
catch ( ClassLoadingException e ) {
throw new MappingException( String.format( "Could not interpret id generator strategy [%s]", strategy ) );
}
catch ( ClassLoadingException e ) {
throw new MappingException( String.format( "Could not interpret id generator strategy [%s]", strategy) );
}
}
}