From b8b8f011dcbe614618434db5e7a00f65d4cea813 Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Tue, 27 Aug 2024 11:13:02 +0200 Subject: [PATCH] HHH-18524 Fix binding of meta-annotated id generators for id-class --- .../boot/model/internal/EmbeddableBinder.java | 79 +++++++------------ .../boot/model/internal/GeneratorBinder.java | 3 +- .../boot/model/internal/PropertyBinder.java | 2 +- .../orm/test/tenantidpk/Account.java | 3 +- .../orm/test/tenantidpk/TenantizedId.java | 24 ++++++ 5 files changed, 59 insertions(+), 52 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/TenantizedId.java 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 45ee381fef..d20ca7634b 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 @@ -66,11 +66,8 @@ 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.DialectOverridesAnnotationHelper.getOverridableAnnotation; -import static org.hibernate.boot.model.internal.GeneratorBinder.buildGenerators; -import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator; -import static org.hibernate.boot.model.internal.GeneratorStrategies.generatorStrategy; +import static org.hibernate.boot.model.internal.GeneratorBinder.createIdGeneratorsFromGeneratorAnnotations; 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.PropertyHolderBuilder.buildPropertyHolder; @@ -464,7 +461,7 @@ public class EmbeddableBinder { ? Nullability.FORCED_NULL : ( isNullable ? Nullability.NO_CONSTRAINT : Nullability.FORCED_NOT_NULL ), propertyAnnotatedElement, - new HashMap<>(), + Map.of(), entityBinder, isIdentifierMapper, isComponentEmbedded, @@ -473,18 +470,27 @@ public class EmbeddableBinder { inheritanceStatePerClass ); - final MemberDetails property = propertyAnnotatedElement.getAttributeMember(); - if ( property.hasDirectAnnotationUsage( 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 MemberDetails member = propertyAnnotatedElement.getAttributeMember(); + 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(); + createIdGeneratorsFromGeneratorAnnotations( + subholder, + propertyAnnotatedElement, + value, + Map.of(), + context + ); } } + else if ( member.hasDirectAnnotationUsage( 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 ) { @@ -494,6 +500,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) { @@ -812,40 +827,6 @@ public class EmbeddableBinder { || property.hasDirectAnnotationUsage(ManyToMany.class); } - private static void processGeneratedId(MetadataBuildingContext context, Component component, MemberDetails property) { - final GeneratedValue generatedValue = property.getDirectAnnotationUsage( GeneratedValue.class ); - final String generatorType = - generatorStrategy( generatedValue.strategy(), generatedValue.generator(), property.getType() ); - final String generator = generatedValue.generator(); - - final SimpleValue value = (SimpleValue) component.getProperty( property.getName()).getValue(); - if ( isGlobalGeneratorNameGlobal( context ) ) { - buildGenerators( property, context ); - context.getMetadataCollector().addSecondPass( new IdGeneratorResolverSecondPass( - value, - property, - generatorType, - generator, - context - ) ); - -// handleTypeDescriptorRegistrations( property, context ); -// bindEmbeddableInstantiatorRegistrations( property, context ); -// bindCompositeUserTypeRegistrations( property, context ); -// handleConverterRegistrations( property, context ); - } - else { - makeIdGenerator( - value, - 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 8373fa4b2e..9c67af0b9a 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 @@ -65,6 +65,7 @@ import static org.hibernate.boot.model.internal.GeneratorParameters.interpretSeq import static org.hibernate.boot.model.internal.GeneratorParameters.interpretTableGenerator; import static org.hibernate.boot.model.internal.GeneratorStrategies.generatorClass; import static org.hibernate.boot.model.internal.GeneratorStrategies.generatorStrategy; +import static org.hibernate.internal.util.NullnessUtil.castNonNull; import static org.hibernate.internal.util.StringHelper.qualify; import static org.hibernate.resource.beans.internal.Helper.allowExtensionsInCdi; @@ -600,7 +601,7 @@ public class GeneratorBinder { MemberDetails idMember) { //manage composite related metadata //guess if its a component and find id data access (property, field etc) - final GeneratedValue generatedValue = idMember.getDirectAnnotationUsage( GeneratedValue.class ); + final GeneratedValue generatedValue = castNonNull( idMember.getDirectAnnotationUsage( GeneratedValue.class ) ); final String generatorType = generatorStrategy( generatedValue.strategy(), generatedValue.generator(), idMember.getType() ); final String generatorName = generatedValue.generator(); 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 68d62238b9..d1debc0484 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 @@ -1135,11 +1135,11 @@ public class PropertyBinder { ); } else if ( propertyBinder.isId() ) { - //components and regular basic types create SimpleValue objects 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 createIdGeneratorsFromGeneratorAnnotations( propertyHolder, inferredData, diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Account.java b/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Account.java index b44182fe68..a4cec927c8 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Account.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/Account.java @@ -3,12 +3,13 @@ package org.hibernate.orm.test.tenantidpk; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import jakarta.persistence.IdClass; import jakarta.persistence.ManyToOne; import org.hibernate.annotations.TenantId; import java.util.UUID; -@Entity +@Entity @IdClass(TenantizedId.class) public class Account { @Id @GeneratedValue Long id; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/TenantizedId.java b/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/TenantizedId.java new file mode 100644 index 0000000000..dc0a82890d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/tenantidpk/TenantizedId.java @@ -0,0 +1,24 @@ +/* + * 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.orm.test.tenantidpk; + +import java.util.UUID; + +import jakarta.persistence.Embeddable; + +@Embeddable +public class TenantizedId { + Long id; + UUID tenantId; + + public TenantizedId(Long id, UUID tenantId) { + this.id = id; + this.tenantId = tenantId; + } + + TenantizedId() {} +} \ No newline at end of file