Skip to content

Commit c85efaa

Browse files
committed
HHH-18524 Fix binding of meta-annotated id generators for id-class
1 parent 049b76c commit c85efaa

File tree

6 files changed

+54
-70
lines changed

6 files changed

+54
-70
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/internal/EmbeddableBinder.java

Lines changed: 29 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import org.hibernate.boot.spi.MetadataBuildingContext;
2929
import org.hibernate.boot.spi.PropertyData;
3030
import org.hibernate.internal.CoreMessageLogger;
31-
import org.hibernate.mapping.AggregateColumn;
3231
import org.hibernate.mapping.BasicValue;
3332
import org.hibernate.mapping.Component;
3433
import org.hibernate.mapping.Property;
@@ -66,19 +65,15 @@
6665
import static org.hibernate.boot.model.internal.BinderHelper.getPropertyOverriddenByMapperOrMapsId;
6766
import static org.hibernate.boot.model.internal.BinderHelper.getRelativePath;
6867
import static org.hibernate.boot.model.internal.BinderHelper.hasToOneAnnotation;
69-
import static org.hibernate.boot.model.internal.BinderHelper.isGlobalGeneratorNameGlobal;
70-
import static org.hibernate.boot.model.internal.GeneratorBinder.buildGenerators;
71-
import static org.hibernate.boot.model.internal.GeneratorBinder.generatorType;
72-
import static org.hibernate.boot.model.internal.GeneratorBinder.makeIdGenerator;
7368
import static org.hibernate.boot.model.internal.HCANNHelper.findContainingAnnotations;
7469
import static org.hibernate.boot.model.internal.PropertyBinder.addElementsOfClass;
7570
import static org.hibernate.boot.model.internal.PropertyBinder.processElementAnnotations;
71+
import static org.hibernate.boot.model.internal.PropertyBinder.processId;
7672
import static org.hibernate.boot.model.internal.PropertyHolderBuilder.buildPropertyHolder;
7773
import static org.hibernate.internal.CoreLogging.messageLogger;
7874
import static org.hibernate.internal.util.StringHelper.isEmpty;
7975
import static org.hibernate.internal.util.StringHelper.qualify;
8076
import static org.hibernate.internal.util.StringHelper.unqualify;
81-
import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY;
8277

8378
/**
8479
* A binder responsible for interpreting {@link Embeddable} classes and producing
@@ -452,18 +447,27 @@ static Component fillEmbeddable(
452447
inheritanceStatePerClass
453448
);
454449

455-
final XProperty property = propertyAnnotatedElement.getProperty();
456-
if ( property.isAnnotationPresent( GeneratedValue.class ) ) {
457-
if ( isIdClass || subholder.isOrWithinEmbeddedId() ) {
458-
processGeneratedId( context, component, property );
459-
}
460-
else {
461-
throw new AnnotationException(
462-
"Property '" + property.getName() + "' of '"
463-
+ getPath( propertyHolder, inferredData )
464-
+ "' is annotated '@GeneratedValue' but is not part of an identifier" );
450+
final XProperty member = propertyAnnotatedElement.getProperty();
451+
if ( isIdClass || subholder.isOrWithinEmbeddedId() ) {
452+
final Property property = findProperty( component, member.getName() );
453+
if ( property != null ) {
454+
// Identifier properties are always simple values
455+
final SimpleValue value = (SimpleValue) property.getValue();
456+
processId(
457+
subholder,
458+
propertyAnnotatedElement,
459+
value,
460+
Map.of(),
461+
context
462+
);
465463
}
466464
}
465+
else if ( member.isAnnotationPresent( GeneratedValue.class ) ) {
466+
throw new AnnotationException(
467+
"Property '" + member.getName() + "' of '"
468+
+ getPath( propertyHolder, inferredData )
469+
+ "' is annotated '@GeneratedValue' but is not part of an identifier" );
470+
}
467471
}
468472

469473
if ( compositeUserType != null ) {
@@ -473,6 +477,15 @@ static Component fillEmbeddable(
473477
return component;
474478
}
475479

480+
private static Property findProperty(Component component, String name) {
481+
for ( Property property : component.getProperties() ) {
482+
if ( property.getName().equals( name ) ) {
483+
return property;
484+
}
485+
}
486+
return null;
487+
}
488+
476489
private static CompositeUserType<?> compositeUserType(
477490
Class<? extends CompositeUserType<?>> compositeUserTypeClass,
478491
MetadataBuildingContext context) {
@@ -782,40 +795,6 @@ private static boolean hasTriggeringAnnotation(XAnnotatedElement property) {
782795
|| property.isAnnotationPresent(ManyToMany.class);
783796
}
784797

785-
private static void processGeneratedId(MetadataBuildingContext context, Component component, XProperty property) {
786-
final GeneratedValue generatedValue = property.getAnnotation( GeneratedValue.class );
787-
final String generatorType = generatedValue != null
788-
? generatorType( generatedValue, property.getType(), context )
789-
: DEFAULT_ID_GEN_STRATEGY;
790-
final String generator = generatedValue != null ? generatedValue.generator() : "";
791-
792-
if ( isGlobalGeneratorNameGlobal( context ) ) {
793-
buildGenerators( property, context );
794-
context.getMetadataCollector().addSecondPass( new IdGeneratorResolverSecondPass(
795-
(SimpleValue) component.getProperty( property.getName() ).getValue(),
796-
property,
797-
generatorType,
798-
generator,
799-
context
800-
) );
801-
802-
// handleTypeDescriptorRegistrations( property, context );
803-
// bindEmbeddableInstantiatorRegistrations( property, context );
804-
// bindCompositeUserTypeRegistrations( property, context );
805-
// handleConverterRegistrations( property, context );
806-
}
807-
else {
808-
makeIdGenerator(
809-
(SimpleValue) component.getProperty( property.getName() ).getValue(),
810-
property,
811-
generatorType,
812-
generator,
813-
context,
814-
new HashMap<>( buildGenerators( property, context ) )
815-
);
816-
}
817-
}
818-
819798
private static void processIdClassElements(
820799
PropertyHolder propertyHolder,
821800
PropertyData baseInferredData,

hibernate-core/src/main/java/org/hibernate/boot/model/internal/GeneratorBinder.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import static org.hibernate.boot.model.internal.BinderHelper.isCompositeId;
6060
import static org.hibernate.boot.model.internal.BinderHelper.isGlobalGeneratorNameGlobal;
6161
import static org.hibernate.id.factory.internal.IdentifierGeneratorUtil.collectParameters;
62+
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
6263
import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY;
6364

6465
public class GeneratorBinder {
@@ -113,16 +114,10 @@ public static void makeIdGenerator(
113114
|| identifierGeneratorStrategy.equals( "seqhilo" );
114115
if ( generatorType == null || !avoidOverriding ) {
115116
id.setIdentifierGeneratorStrategy( identifierGeneratorStrategy );
116-
if ( DEFAULT_ID_GEN_STRATEGY.equals( identifierGeneratorStrategy ) ) {
117-
id.setNullValue( "undefined" );
118-
}
119117
}
120118
//checkIfMatchingGenerator(definition, generatorType, generatorName);
121119
parameters.putAll( definition.getParameters() );
122120
}
123-
if ( DEFAULT_ID_GEN_STRATEGY.equals( generatorType ) ) {
124-
id.setNullValue( "undefined" );
125-
}
126121
id.setIdentifierGeneratorParameters( parameters );
127122
}
128123

@@ -564,9 +559,9 @@ static void createIdGenerator(
564559
XProperty idProperty) {
565560
//manage composite related metadata
566561
//guess if its a component and find id data access (property, field etc)
567-
final GeneratedValue generatedValue = idProperty.getAnnotation( GeneratedValue.class );
562+
final GeneratedValue generatedValue = castNonNull( idProperty.getAnnotation( GeneratedValue.class ) );
568563
final String generatorType = generatorType( context, entityClass, isCompositeId( entityClass, idProperty ), generatedValue );
569-
final String generatorName = generatedValue == null ? "" : generatedValue.generator();
564+
final String generatorName = generatedValue.generator();
570565
if ( isGlobalGeneratorNameGlobal( context ) ) {
571566
buildGenerators( idProperty, context );
572567
context.getMetadataCollector().addSecondPass( new IdGeneratorResolverSecondPass(

hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyBinder.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import jakarta.persistence.Column;
1616
import jakarta.persistence.ElementCollection;
1717
import jakarta.persistence.EmbeddedId;
18+
import jakarta.persistence.GeneratedValue;
1819
import jakarta.persistence.Id;
1920
import jakarta.persistence.JoinColumn;
2021
import jakarta.persistence.JoinColumns;
@@ -1156,13 +1157,16 @@ && isEmbedded( property, property.getElementClass() ) ) {
11561157
);
11571158
}
11581159
else if ( propertyBinder.isId() ) {
1160+
if ( isIdentifierMapper ) {
1161+
throw new AnnotationException( "Property '"+ getPath( propertyHolder, inferredData )
1162+
+ "' belongs to an '@IdClass' and may not be annotated '@Id' or '@EmbeddedId'" );
1163+
}
11591164
//components and regular basic types create SimpleValue objects
11601165
processId(
11611166
propertyHolder,
11621167
inferredData,
11631168
(SimpleValue) propertyBinder.getValue(),
11641169
classGenerators,
1165-
isIdentifierMapper,
11661170
context
11671171
);
11681172
}
@@ -1415,17 +1419,12 @@ private static Class<? extends CompositeUserType<?>> resolveCompositeUserType(
14151419
return null;
14161420
}
14171421

1418-
private static void processId(
1422+
static void processId(
14191423
PropertyHolder propertyHolder,
14201424
PropertyData inferredData,
14211425
SimpleValue idValue,
14221426
Map<String, IdentifierGeneratorDefinition> classGenerators,
1423-
boolean isIdentifierMapper,
14241427
MetadataBuildingContext context) {
1425-
if ( isIdentifierMapper ) {
1426-
throw new AnnotationException( "Property '"+ getPath( propertyHolder, inferredData )
1427-
+ "' belongs to an '@IdClass' and may not be annotated '@Id' or '@EmbeddedId'" );
1428-
}
14291428
final XProperty idProperty = inferredData.getProperty();
14301429
final List<Annotation> idGeneratorAnnotations = findContainingAnnotations( idProperty, IdGeneratorType.class );
14311430
final List<Annotation> generatorAnnotations = findContainingAnnotations( idProperty, ValueGenerationType.class );
@@ -1449,7 +1448,7 @@ else if ( !generatorAnnotations.isEmpty() ) {
14491448
+ "' is annotated '" + generatorAnnotations.get(0).annotationType()
14501449
+ "' which is not an '@IdGeneratorType'" );
14511450
}
1452-
else {
1451+
else if ( idProperty.isAnnotationPresent( GeneratedValue.class ) ) {
14531452
final XClass entityClass = inferredData.getClassOrElement();
14541453
createIdGenerator( idValue, classGenerators, context, entityClass, idProperty );
14551454
if ( LOG.isTraceEnabled() ) {

hibernate-core/src/main/java/org/hibernate/id/Assigned.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,9 @@ public void configure(Type type, Properties parameters, ServiceRegistry serviceR
4343
throw new MappingException("no entity name");
4444
}
4545
}
46+
47+
@Override
48+
public boolean allowAssignedIdentifiers() {
49+
return true;
50+
}
4651
}

hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
import org.hibernate.jpa.internal.ExceptionMapperLegacyJpaImpl;
7777
import org.hibernate.jpa.internal.PersistenceUnitUtilImpl;
7878
import org.hibernate.mapping.Collection;
79+
import org.hibernate.mapping.KeyValue;
7980
import org.hibernate.mapping.PersistentClass;
8081
import org.hibernate.mapping.RootClass;
8182
import org.hibernate.mapping.SimpleValue;
@@ -462,7 +463,8 @@ private static Map<String, Generator> createGenerators(
462463
bootMetamodel.getEntityBindings().stream()
463464
.filter( model -> !model.isInherited() )
464465
.forEach( model -> {
465-
final Generator generator = model.getIdentifier().createGenerator(
466+
final KeyValue id = model.getIdentifier();
467+
final Generator generator = id.createGenerator(
466468
bootstrapContext.getIdentifierGeneratorFactory(),
467469
jdbcServices.getJdbcEnvironment().getDialect(),
468470
(RootClass) model
@@ -471,8 +473,11 @@ private static Map<String, Generator> createGenerators(
471473
final Configurable identifierGenerator = (Configurable) generator;
472474
identifierGenerator.initialize( sqlStringGenerationContext );
473475
}
474-
if ( generator.allowAssignedIdentifiers() ) {
475-
( (SimpleValue) model.getIdentifier() ).setNullValue( "undefined" );
476+
if ( generator.allowAssignedIdentifiers() && id instanceof SimpleValue ) {
477+
final SimpleValue simpleValue = (SimpleValue) id;
478+
if ( simpleValue.getNullValue() == null ) {
479+
simpleValue.setNullValue( "undefined" );
480+
}
476481
}
477482
generators.put( model.getEntityName(), generator );
478483
} );

hibernate-core/src/main/java/org/hibernate/mapping/Component.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,8 @@ else if ( rootClass.getIdentifierProperty() != null ) {
719719
if ( property.getValue().isSimpleValue() ) {
720720
final SimpleValue value = (SimpleValue) property.getValue();
721721

722-
if ( !DEFAULT_ID_GEN_STRATEGY.equals( value.getIdentifierGeneratorStrategy() ) ) {
722+
if ( !DEFAULT_ID_GEN_STRATEGY.equals( value.getIdentifierGeneratorStrategy() )
723+
|| value.getCustomIdGeneratorCreator() != null ) {
723724
// skip any 'assigned' generators, they would have been handled by
724725
// the StandardGenerationContextLocator
725726
generator.addGeneratedValuePlan( new ValueGenerationPlan(

0 commit comments

Comments
 (0)