diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java index 92243de333..77922aed7a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java @@ -28,7 +28,6 @@ import org.hibernate.boot.spi.AccessType; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.mapping.AggregateColumn; import org.hibernate.mapping.BasicValue; import org.hibernate.mapping.Component; import org.hibernate.mapping.Property; @@ -66,19 +65,15 @@ import static org.hibernate.boot.model.internal.BinderHelper.getPath; import static org.hibernate.boot.model.internal.BinderHelper.getPropertyOverriddenByMapperOrMapsId; import static org.hibernate.boot.model.internal.BinderHelper.getRelativePath; import static org.hibernate.boot.model.internal.BinderHelper.hasToOneAnnotation; -import static org.hibernate.boot.model.internal.BinderHelper.isGlobalGeneratorNameGlobal; -import static org.hibernate.boot.model.internal.GeneratorBinder.buildGenerators; -import static org.hibernate.boot.model.internal.GeneratorBinder.generatorType; -import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator; import static org.hibernate.boot.model.internal.HCANNHelper.findContainingAnnotations; import static org.hibernate.boot.model.internal.PropertyBinder.addElementsOfClass; import static org.hibernate.boot.model.internal.PropertyBinder.processElementAnnotations; +import static org.hibernate.boot.model.internal.PropertyBinder.processId; import static org.hibernate.boot.model.internal.PropertyHolderBuilder.buildPropertyHolder; import static org.hibernate.internal.CoreLogging.messageLogger; import static org.hibernate.internal.util.StringHelper.isEmpty; import static org.hibernate.internal.util.StringHelper.qualify; import static org.hibernate.internal.util.StringHelper.unqualify; -import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY; /** * A binder responsible for interpreting {@link Embeddable} classes and producing @@ -452,18 +447,27 @@ public class EmbeddableBinder { inheritanceStatePerClass ); - final XProperty property = propertyAnnotatedElement.getProperty(); - if ( property.isAnnotationPresent( GeneratedValue.class ) ) { - if ( isIdClass || subholder.isOrWithinEmbeddedId() ) { - processGeneratedId( context, component, property ); - } - else { - throw new AnnotationException( - "Property '" + property.getName() + "' of '" - + getPath( propertyHolder, inferredData ) - + "' is annotated '@GeneratedValue' but is not part of an identifier" ); + final XProperty member = propertyAnnotatedElement.getProperty(); + if ( isIdClass || subholder.isOrWithinEmbeddedId() ) { + final Property property = findProperty( component, member.getName() ); + if ( property != null ) { + // Identifier properties are always simple values + final SimpleValue value = (SimpleValue) property.getValue(); + processId( + subholder, + propertyAnnotatedElement, + value, + Map.of(), + context + ); } } + else if ( member.isAnnotationPresent( GeneratedValue.class ) ) { + throw new AnnotationException( + "Property '" + member.getName() + "' of '" + + getPath( propertyHolder, inferredData ) + + "' is annotated '@GeneratedValue' but is not part of an identifier" ); + } } if ( compositeUserType != null ) { @@ -473,6 +477,15 @@ public class EmbeddableBinder { return component; } + private static Property findProperty(Component component, String name) { + for ( Property property : component.getProperties() ) { + if ( property.getName().equals( name ) ) { + return property; + } + } + return null; + } + private static CompositeUserType compositeUserType( Class> compositeUserTypeClass, MetadataBuildingContext context) { @@ -782,40 +795,6 @@ public class EmbeddableBinder { || property.isAnnotationPresent(ManyToMany.class); } - private static void processGeneratedId(MetadataBuildingContext context, Component component, XProperty property) { - final GeneratedValue generatedValue = property.getAnnotation( GeneratedValue.class ); - final String generatorType = generatedValue != null - ? generatorType( generatedValue, property.getType(), context ) - : DEFAULT_ID_GEN_STRATEGY; - final String generator = generatedValue != null ? generatedValue.generator() : ""; - - if ( isGlobalGeneratorNameGlobal( context ) ) { - buildGenerators( property, context ); - context.getMetadataCollector().addSecondPass( new IdGeneratorResolverSecondPass( - (SimpleValue) component.getProperty( property.getName() ).getValue(), - property, - generatorType, - generator, - context - ) ); - -// handleTypeDescriptorRegistrations( property, context ); -// bindEmbeddableInstantiatorRegistrations( property, context ); -// bindCompositeUserTypeRegistrations( property, context ); -// handleConverterRegistrations( property, context ); - } - else { - makeIdGenerator( - (SimpleValue) component.getProperty( property.getName() ).getValue(), - property, - generatorType, - generator, - context, - new HashMap<>( buildGenerators( property, context ) ) - ); - } - } - private static void processIdClassElements( PropertyHolder propertyHolder, PropertyData baseInferredData, diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java index 8f6707d831..05782977b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java @@ -59,6 +59,7 @@ import jakarta.persistence.Version; 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.NullnessUtil.castNonNull; import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY; public class GeneratorBinder { @@ -113,16 +114,10 @@ public class GeneratorBinder { || identifierGeneratorStrategy.equals( "seqhilo" ); if ( generatorType == null || !avoidOverriding ) { id.setIdentifierGeneratorStrategy( identifierGeneratorStrategy ); - if ( DEFAULT_ID_GEN_STRATEGY.equals( identifierGeneratorStrategy ) ) { - id.setNullValue( "undefined" ); - } } //checkIfMatchingGenerator(definition, generatorType, generatorName); parameters.putAll( definition.getParameters() ); } - if ( DEFAULT_ID_GEN_STRATEGY.equals( generatorType ) ) { - id.setNullValue( "undefined" ); - } id.setIdentifierGeneratorParameters( parameters ); } @@ -564,9 +559,9 @@ public class GeneratorBinder { XProperty idProperty) { //manage composite related metadata //guess if its a component and find id data access (property, field etc) - final GeneratedValue generatedValue = idProperty.getAnnotation( GeneratedValue.class ); + final GeneratedValue generatedValue = castNonNull( idProperty.getAnnotation( GeneratedValue.class ) ); final String generatorType = generatorType( context, entityClass, isCompositeId( entityClass, idProperty ), generatedValue ); - final String generatorName = generatedValue == null ? "" : generatedValue.generator(); + final String generatorName = generatedValue.generator(); if ( isGlobalGeneratorNameGlobal( context ) ) { buildGenerators( idProperty, context ); context.getMetadataCollector().addSecondPass( new IdGeneratorResolverSecondPass( diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java index 5c98e401d0..df5319afaa 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java @@ -15,6 +15,7 @@ import jakarta.persistence.Basic; import jakarta.persistence.Column; import jakarta.persistence.ElementCollection; import jakarta.persistence.EmbeddedId; +import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumns; @@ -1156,13 +1157,16 @@ public class PropertyBinder { ); } else if ( propertyBinder.isId() ) { + if ( isIdentifierMapper ) { + throw new AnnotationException( "Property '"+ getPath( propertyHolder, inferredData ) + + "' belongs to an '@IdClass' and may not be annotated '@Id' or '@EmbeddedId'" ); + } //components and regular basic types create SimpleValue objects processId( propertyHolder, inferredData, (SimpleValue) propertyBinder.getValue(), classGenerators, - isIdentifierMapper, context ); } @@ -1415,17 +1419,12 @@ public class PropertyBinder { return null; } - private static void processId( + static void processId( PropertyHolder propertyHolder, PropertyData inferredData, SimpleValue idValue, Map classGenerators, - boolean isIdentifierMapper, MetadataBuildingContext context) { - if ( isIdentifierMapper ) { - throw new AnnotationException( "Property '"+ getPath( propertyHolder, inferredData ) - + "' belongs to an '@IdClass' and may not be annotated '@Id' or '@EmbeddedId'" ); - } final XProperty idProperty = inferredData.getProperty(); final List idGeneratorAnnotations = findContainingAnnotations( idProperty, IdGeneratorType.class ); final List generatorAnnotations = findContainingAnnotations( idProperty, ValueGenerationType.class ); @@ -1449,7 +1448,7 @@ public class PropertyBinder { + "' is annotated '" + generatorAnnotations.get(0).annotationType() + "' which is not an '@IdGeneratorType'" ); } - else { + else if ( idProperty.isAnnotationPresent( GeneratedValue.class ) ) { final XClass entityClass = inferredData.getClassOrElement(); createIdGenerator( idValue, classGenerators, context, entityClass, idProperty ); if ( LOG.isTraceEnabled() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/id/Assigned.java b/hibernate-core/src/main/java/org/hibernate/id/Assigned.java index ffce159958..22ebc92abc 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/Assigned.java +++ b/hibernate-core/src/main/java/org/hibernate/id/Assigned.java @@ -43,4 +43,9 @@ public class Assigned implements IdentifierGenerator, StandardGenerator { throw new MappingException("no entity name"); } } + + @Override + public boolean allowAssignedIdentifiers() { + return true; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 4420b3e672..9ca7b6b571 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -76,6 +76,7 @@ import org.hibernate.integrator.spi.IntegratorService; import org.hibernate.jpa.internal.ExceptionMapperLegacyJpaImpl; import org.hibernate.jpa.internal.PersistenceUnitUtilImpl; import org.hibernate.mapping.Collection; +import org.hibernate.mapping.KeyValue; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.RootClass; import org.hibernate.mapping.SimpleValue; @@ -462,7 +463,8 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im bootMetamodel.getEntityBindings().stream() .filter( model -> !model.isInherited() ) .forEach( model -> { - final Generator generator = model.getIdentifier().createGenerator( + final KeyValue id = model.getIdentifier(); + final Generator generator = id.createGenerator( bootstrapContext.getIdentifierGeneratorFactory(), jdbcServices.getJdbcEnvironment().getDialect(), (RootClass) model @@ -471,8 +473,11 @@ public class SessionFactoryImpl extends QueryParameterBindingTypeResolverImpl im final Configurable identifierGenerator = (Configurable) generator; identifierGenerator.initialize( sqlStringGenerationContext ); } - if ( generator.allowAssignedIdentifiers() ) { - ( (SimpleValue) model.getIdentifier() ).setNullValue( "undefined" ); + if ( generator.allowAssignedIdentifiers() && id instanceof SimpleValue ) { + final SimpleValue simpleValue = (SimpleValue) id; + if ( simpleValue.getNullValue() == null ) { + simpleValue.setNullValue( "undefined" ); + } } generators.put( model.getEntityName(), generator ); } ); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java index 431099e0ca..1cea3cd6b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java @@ -719,7 +719,8 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable if ( property.getValue().isSimpleValue() ) { final SimpleValue value = (SimpleValue) property.getValue(); - if ( !DEFAULT_ID_GEN_STRATEGY.equals( value.getIdentifierGeneratorStrategy() ) ) { + if ( !DEFAULT_ID_GEN_STRATEGY.equals( value.getIdentifierGeneratorStrategy() ) + || value.getCustomIdGeneratorCreator() != null ) { // skip any 'assigned' generators, they would have been handled by // the StandardGenerationContextLocator generator.addGeneratedValuePlan( new ValueGenerationPlan(