HHH-18524 Fix binding of meta-annotated id generators for id-class

This commit is contained in:
Marco Belladelli 2024-08-27 11:13:02 +02:00
parent 6d0c9599e6
commit b8b8f011dc
5 changed files with 59 additions and 52 deletions

View File

@ -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<? extends CompositeUserType<?>> 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,

View File

@ -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();

View File

@ -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,

View File

@ -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;

View File

@ -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() {}
}