Skip to content

Commit 445f95f

Browse files
cigalygavinking
authored andcommitted
HHH-18829 Main:
- Hibernate Processor - create ID class in meta data class if entity class with more than one ID component is not annotated with @IdClass; property order must be preserved - Hibernate Core - if entity class has more than one ID component, but is not annotated with @IdClass entity binder should try to use ID class from metamodel if generated
1 parent b9351cf commit 445f95f

File tree

5 files changed

+137
-4
lines changed

5 files changed

+137
-4
lines changed

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -481,10 +481,22 @@ private boolean mapAsIdClass(
481481
final ClassDetails classWithIdClass = inheritanceState.getClassWithIdClass( false );
482482
if ( classWithIdClass != null ) {
483483
final IdClass idClassAnn = classWithIdClass.getDirectAnnotationUsage( IdClass.class );
484-
final Class<?> idClassValue = idClassAnn.value();
485-
final ClassDetails compositeClass =
486-
getMetadataCollector().getSourceModelBuildingContext().getClassDetailsRegistry()
487-
.resolveClassDetails( idClassValue.getName() );
484+
final ClassDetails compositeClass;
485+
if ( idClassAnn == null ) {
486+
try {
487+
compositeClass = getMetadataCollector().getSourceModelBuildingContext()
488+
.getClassDetailsRegistry()
489+
.resolveClassDetails( inheritanceState.getClassDetails().getClassName() + "_$Id" );
490+
}
491+
catch (RuntimeException e) {
492+
return false;
493+
}
494+
}
495+
else {
496+
final Class<?> idClassValue = idClassAnn.value();
497+
compositeClass = getMetadataCollector().getSourceModelBuildingContext()
498+
.getClassDetailsRegistry().resolveClassDetails( idClassValue.getName() );
499+
}
488500
final TypeDetails compositeType = new ClassTypeDetailsImpl( compositeClass, TypeDetails.Kind.CLASS );
489501
final TypeDetails classWithIdType = new ClassTypeDetailsImpl( classWithIdClass, TypeDetails.Kind.CLASS );
490502

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.ArrayList;
88
import java.util.List;
99
import java.util.Map;
10+
import java.util.stream.Stream;
1011

1112
import org.hibernate.AnnotationException;
1213
import org.hibernate.boot.spi.AccessType;
@@ -183,6 +184,13 @@ else if ( classDetails.hasDirectAnnotationUsage( IdClass.class ) ) {
183184
return classDetails;
184185
}
185186
else {
187+
final long count = Stream.concat(
188+
classDetails.getFields().stream(),
189+
classDetails.getMethods().stream()
190+
).filter( t -> t.hasDirectAnnotationUsage( Id.class ) ).count();
191+
if ( count > 1 ) {
192+
return classDetails;
193+
}
186194
final InheritanceState state = getSuperclassInheritanceState( classDetails, inheritanceStatePerClass );
187195
if ( state != null ) {
188196
return state.getClassWithIdClass( true );

tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaEntity.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@
108108
*/
109109
public class AnnotationMetaEntity extends AnnotationMeta {
110110

111+
private static final String ID_CLASS_MEMBER_NAME = "<ID_CLASS>";
112+
111113
private final ImportContext importContext;
112114
private final TypeElement element;
113115
private final Map<String, MetaAttribute> members;
@@ -438,6 +440,8 @@ && containsAnnotation( method, HQL, SQL, FIND ) ) {
438440

439441
addPersistentMembers( fieldsOfClass, AccessType.FIELD );
440442
addPersistentMembers( gettersAndSettersOfClass, AccessType.PROPERTY );
443+
444+
addIdClassIfNeeded( fieldsOfClass, gettersAndSettersOfClass );
441445
}
442446

443447
addAuxiliaryMembers();
@@ -451,6 +455,33 @@ && containsAnnotation( method, HQL, SQL, FIND ) ) {
451455
initialized = true;
452456
}
453457

458+
private void addIdClassIfNeeded(List<? extends Element> fields, List<? extends Element> methods) {
459+
if ( hasAnnotation( element, ID_CLASS ) ) {
460+
return;
461+
}
462+
final List<MetaAttribute> components = new ArrayList<>();
463+
for ( Element field : fields ) {
464+
if ( hasAnnotation( field, ID ) && isPersistent( field, AccessType.FIELD ) ) {
465+
final String propertyName = propertyName( this, field );
466+
if ( members.containsKey( propertyName ) ) {
467+
components.add( members.get( propertyName ) );
468+
}
469+
}
470+
}
471+
for ( Element method : methods ) {
472+
if ( hasAnnotation( method, ID ) && isPersistent( method, AccessType.PROPERTY ) ) {
473+
final String propertyName = propertyName( this, method );
474+
if ( members.containsKey( propertyName ) ) {
475+
components.add( members.get( propertyName ) );
476+
}
477+
}
478+
}
479+
if ( components.size() < 2 ) {
480+
return;
481+
}
482+
putMember( ID_CLASS_MEMBER_NAME, new IdClassMetaAttribute( this, components ) );
483+
}
484+
454485
private boolean checkEntities(List<ExecutableElement> lifecycleMethods) {
455486
boolean foundPersistenceEntity = false;
456487
VariableElement nonPersistenceParameter = null;

tooling/metamodel-generator/src/main/java/org/hibernate/processor/annotation/AnnotationMetaSingleAttribute.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44
*/
55
package org.hibernate.processor.annotation;
66

7+
import javax.lang.model.element.AnnotationMirror;
78
import javax.lang.model.element.Element;
89

910
import org.hibernate.processor.model.MetaSingleAttribute;
1011
import org.hibernate.processor.util.Constants;
1112

13+
import java.util.ArrayList;
14+
import java.util.List;
15+
1216
/**
1317
* @author Max Andersen
1418
* @author Hardy Ferentschik
@@ -24,4 +28,9 @@ public AnnotationMetaSingleAttribute(AnnotationMetaEntity parent, Element elemen
2428
public final String getMetaType() {
2529
return Constants.SINGULAR_ATTRIBUTE;
2630
}
31+
32+
@Override
33+
public List<AnnotationMirror> inheritedAnnotations() {
34+
return new ArrayList<>(element.getAnnotationMirrors());
35+
}
2736
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.processor.annotation;
6+
7+
import org.hibernate.processor.model.MetaAttribute;
8+
import org.hibernate.processor.model.Metamodel;
9+
10+
import java.util.List;
11+
12+
public class IdClassMetaAttribute implements MetaAttribute {
13+
14+
private final Metamodel parent;
15+
16+
private final List<MetaAttribute> components;
17+
18+
public IdClassMetaAttribute(Metamodel parent, List<MetaAttribute> components) {
19+
this.parent = parent;
20+
this.components = components;
21+
}
22+
23+
@Override
24+
public boolean hasTypedAttribute() {
25+
return true;
26+
}
27+
28+
@Override
29+
public boolean hasStringAttribute() {
30+
return false;
31+
}
32+
33+
@Override
34+
public String getAttributeDeclarationString() {
35+
final StringBuilder decl = new StringBuilder()
36+
.append("\n/**\n * Static ID class for {@link ")
37+
.append( parent.getQualifiedName() )
38+
.append( "}\n **/\n" )
39+
.append( "public record Id" );
40+
String delimiter = "(";
41+
for ( MetaAttribute component : components ) {
42+
decl.append( delimiter ).append( parent.importType( component.getTypeDeclaration() ) )
43+
.append( ' ' ).append( component.getPropertyName() );
44+
delimiter = ", ";
45+
}
46+
return decl.append( ") {}" ).toString();
47+
}
48+
49+
@Override
50+
public String getAttributeNameDeclarationString() {
51+
return "";
52+
}
53+
54+
@Override
55+
public String getMetaType() {
56+
return "";
57+
}
58+
59+
@Override
60+
public String getPropertyName() {
61+
return "";
62+
}
63+
64+
@Override
65+
public String getTypeDeclaration() {
66+
return "";
67+
}
68+
69+
@Override
70+
public Metamodel getHostingEntity() {
71+
return parent;
72+
}
73+
}

0 commit comments

Comments
 (0)