Skip to content

Commit 0ecb734

Browse files
committed
HHH-18693 Changed Hibernate Processor implementation to generate inner classes under "parent" meta class
1 parent 3ccbdff commit 0ecb734

File tree

7 files changed

+274
-44
lines changed

7 files changed

+274
-44
lines changed

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

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
package org.hibernate.processor;
66

77
import jakarta.annotation.Nullable;
8+
import org.hibernate.processor.annotation.AnnotationMetaEntity;
9+
import org.hibernate.processor.annotation.InnerClassMetaAttribute;
810
import org.hibernate.processor.model.MetaAttribute;
911
import org.hibernate.processor.model.Metamodel;
1012

1113
import javax.annotation.processing.FilerException;
1214
import javax.lang.model.element.ElementKind;
15+
import javax.lang.model.element.Modifier;
1316
import javax.lang.model.element.TypeElement;
1417
import javax.tools.Diagnostic;
1518
import javax.tools.FileObject;
@@ -19,7 +22,11 @@
1922
import java.io.StringWriter;
2023
import java.time.OffsetDateTime;
2124
import java.time.format.DateTimeFormatter;
25+
import java.util.Arrays;
2226
import java.util.List;
27+
import java.util.Set;
28+
import java.util.stream.Collectors;
29+
2330

2431
/**
2532
* Helper class to write the actual metamodel class using the {@link javax.annotation.processing.Filer} API.
@@ -33,14 +40,15 @@ private ClassWriter() {
3340
}
3441

3542
public static void writeFile(Metamodel entity, Context context) {
43+
if (entity.hasParent()) throw new IllegalStateException();
3644
try {
3745
String metaModelPackage = entity.getPackageName();
3846
// need to generate the body first, since this will also update
3947
// the required imports which need to be written out first
4048
String body = generateBody( entity, context ).toString();
4149

4250
FileObject fo = context.getProcessingEnvironment().getFiler().createSourceFile(
43-
getFullyQualifiedClassName( entity, metaModelPackage ),
51+
getFullyQualifiedClassName( entity ),
4452
entity.getElement()
4553
);
4654
OutputStream os = fo.openOutputStream();
@@ -102,6 +110,14 @@ private static StringBuffer generateBody(Metamodel entity, Context context) {
102110
pw.println();
103111

104112
final List<MetaAttribute> members = entity.getMembers();
113+
for ( MetaAttribute metaMember : members ) {
114+
if ( metaMember instanceof InnerClassMetaAttribute innerClass ) {
115+
generateBody( innerClass.getMetaEntity(), context )
116+
.toString().lines()
117+
.forEach(line -> pw.println('\t' + line));
118+
}
119+
}
120+
105121
for ( MetaAttribute metaMember : members ) {
106122
if ( metaMember.hasStringAttribute() ) {
107123
metaMember.getAttributeNameDeclarationString().lines()
@@ -134,7 +150,18 @@ private static StringBuffer generateBody(Metamodel entity, Context context) {
134150
}
135151

136152
private static void printClassDeclaration(Metamodel entity, PrintWriter pw, Context context) {
137-
pw.print( "public " );
153+
if ( entity.hasParent() ) {
154+
final Set<Modifier> modifiers = entity.getElement().getModifiers();
155+
if (modifiers.contains( Modifier.PUBLIC )){
156+
pw.print( "public " );
157+
}else if (modifiers.contains( Modifier.PROTECTED )) {
158+
pw.print( "protected " );
159+
}
160+
pw.print( "static " );
161+
}
162+
else {
163+
pw.print( "public " );
164+
}
138165
if ( !entity.isImplementation() && !entity.isJakartaDataStyle() ) {
139166
pw.print( "abstract " );
140167
}
@@ -147,32 +174,51 @@ private static void printClassDeclaration(Metamodel entity, PrintWriter pw, Cont
147174
if (superClassEntity == null) {
148175
superClassEntity = context.getMetaEmbeddable( superClassName );
149176
}
150-
pw.print( " extends " + getGeneratedSuperclassName(entity, superClassName, superClassEntity ) );
177+
final String superclassName = getGeneratedSuperclassName(
178+
superClassName, superClassEntity, entity.isJakartaDataStyle() );
179+
if (entity.getSimpleName().equals( "OffsetDateTimeTest" )) {
180+
System.err.printf( "Extends (?) %s - superClassName is not null%n", superClassName );
181+
}
182+
pw.print( " extends " + entity.importType(superclassName) );
151183
}
152184
if ( entity.isImplementation() ) {
153185
pw.print( entity.getElement().getKind() == ElementKind.CLASS ? " extends " : " implements " );
154186
pw.print( entity.getSimpleName() );
187+
if (entity.getSimpleName().equals( "OffsetDateTimeTest" )) {
188+
System.err.printf( "Extends (?) %s -- implementation (?!?)%n", entity.getSimpleName() );
189+
}
155190
}
156191

157192
pw.println( " {" );
158193
}
159194

160-
private static String getFullyQualifiedClassName(Metamodel entity, String metaModelPackage) {
195+
private static String getFullyQualifiedClassName(Metamodel entity) {
196+
final String metaModelPackage = entity.getPackageName();
161197
String fullyQualifiedClassName = "";
162198
if ( !metaModelPackage.isEmpty() ) {
163199
fullyQualifiedClassName = fullyQualifiedClassName + metaModelPackage + ".";
164200
}
165-
fullyQualifiedClassName = fullyQualifiedClassName + getGeneratedClassName( entity );
166-
return fullyQualifiedClassName;
201+
final String className;
202+
if ( entity.getElement().getKind() == ElementKind.PACKAGE ) {
203+
className = getGeneratedClassName( entity );
204+
}
205+
else {
206+
className = Arrays.stream(
207+
entity.getQualifiedName().substring( fullyQualifiedClassName.length() ).split( "\\." ) )
208+
.map( AnnotationMetaEntity::removeDollar )
209+
.map( part -> entity.isJakartaDataStyle() ? '_' + part : part + '_' )
210+
.collect( Collectors.joining( "." ) );
211+
}
212+
return fullyQualifiedClassName + className;
167213
}
168214

169215
private static String getGeneratedClassName(Metamodel entity) {
170-
final String className = entity.getSimpleName().replace( '.', '_' );
171-
return entity.isJakartaDataStyle() ? '_' + className : className + '_';
216+
final String className = entity.getSimpleName();
217+
return entity.isJakartaDataStyle() ? '_' + className : className + '_'; // TODO : check inner class!!!
172218
}
173219

174-
private static String getGeneratedSuperclassName(Metamodel entity, String superClassName, @Nullable Metamodel superClassEntity) {
175-
if ( entity.isJakartaDataStyle() ) {
220+
private static String getGeneratedSuperclassName(String superClassName, @Nullable Metamodel superClassEntity, boolean jakartaDataStyle) {
221+
if ( jakartaDataStyle ) {
176222
int lastDot = superClassName.lastIndexOf('.');
177223
if ( lastDot<0 ) {
178224
return '_' + superClassName;
@@ -184,7 +230,7 @@ private static String getGeneratedSuperclassName(Metamodel entity, String superC
184230
}
185231
else {
186232
return superClassEntity == null ? superClassName + '_'
187-
: getFullyQualifiedClassName( superClassEntity, superClassEntity.getPackageName() );
233+
: getFullyQualifiedClassName( superClassEntity );
188234
}
189235
}
190236

@@ -233,6 +279,7 @@ private static String writeStaticMetaModelAnnotation(Metamodel entity) {
233279
final String annotation = entity.isJakartaDataStyle()
234280
? "jakarta.data.metamodel.StaticMetamodel"
235281
: "jakarta.persistence.metamodel.StaticMetamodel";
236-
return "@" + entity.importType( annotation ) + "(" + entity.getSimpleName() + ".class)";
282+
final String simpleName = entity.importType( entity.getQualifiedName() );
283+
return "@" + entity.importType( annotation ) + "(" + simpleName + ".class)";
237284
}
238285
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,15 @@ public Collection<Metamodel> getDataMetaEmbeddables() {
304304
return dataMetaEmbeddables.values();
305305
}
306306

307+
public @Nullable Metamodel getMetamodel(String qualifiedName) {
308+
if ( metaEntities.containsKey( qualifiedName ) ) {
309+
return metaEntities.get( qualifiedName );
310+
}
311+
else {
312+
return metaEmbeddables.get( qualifiedName );
313+
}
314+
}
315+
307316
public @Nullable Metamodel getMetaAuxiliary(String qualifiedName) {
308317
return metaAuxiliaries.get( qualifiedName );
309318
}

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

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.checkerframework.checker.nullness.qual.Nullable;
88
import org.hibernate.processor.annotation.AnnotationMetaEntity;
99
import org.hibernate.processor.annotation.AnnotationMetaPackage;
10+
import org.hibernate.processor.annotation.NonManagedMetamodel;
1011
import org.hibernate.processor.model.Metamodel;
1112
import org.hibernate.processor.util.Constants;
1213
import org.hibernate.processor.xml.JpaDescriptorParser;
@@ -359,11 +360,11 @@ private void processClasses(RoundEnvironment roundEnvironment) {
359360
}
360361

361362
for ( Element element : roundEnvironment.getRootElements() ) {
362-
processElement( element );
363+
processElement( element, null );
363364
}
364365
}
365366

366-
private void processElement(Element element) {
367+
private void processElement(Element element, @Nullable Element parent) {
367368
try {
368369
if ( !included( element )
369370
|| hasAnnotation( element, Constants.EXCLUDE )
@@ -373,7 +374,7 @@ private void processElement(Element element) {
373374
}
374375
else if ( isEntityOrEmbeddable( element ) && !element.getModifiers().contains( Modifier.PRIVATE )) {
375376
context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated entity class '" + element + "'" );
376-
handleRootElementAnnotationMirrors( element );
377+
handleRootElementAnnotationMirrors( element, parent );
377378
}
378379
else if ( hasAuxiliaryAnnotations( element ) ) {
379380
context.logMessage( Diagnostic.Kind.OTHER, "Processing annotated class '" + element + "'" );
@@ -405,12 +406,29 @@ else if ( element instanceof TypeElement typeElement ) {
405406
break;
406407
}
407408
}
409+
if ( enclosesEntityOrEmbeddable( element ) ) {
410+
AnnotationMetaEntity parentMeta = null;
411+
if ( parent instanceof TypeElement parentElement ) {
412+
final String key = parentElement.getQualifiedName().toString();
413+
if ( context.getMetamodel( key ) instanceof AnnotationMetaEntity parentMetaEntity ) {
414+
parentMeta = parentMetaEntity;
415+
}
416+
}
417+
if (element.getSimpleName().toString().equals( "OffsetDateTimeTest" )) {
418+
System.err.println("Create OffsetDateTimeTest as non-entity class#1");
419+
}
420+
final NonManagedMetamodel metaEntity =
421+
NonManagedMetamodel .create(
422+
typeElement, context,
423+
parentMeta );
424+
context.addMetaEntity( metaEntity.getQualifiedName(), metaEntity );
425+
}
408426
}
409427
}
410428
if ( isClassOrRecordType( element ) ) {
411429
for ( final Element child : element.getEnclosedElements() ) {
412430
if ( isClassOrRecordType( child ) ) {
413-
processElement( child );
431+
processElement( child, element );
414432
}
415433
}
416434
}
@@ -443,7 +461,16 @@ private void createMetaModelClasses() {
443461
}
444462

445463
for ( Metamodel entity : context.getMetaEntities() ) {
446-
if ( !context.isAlreadyGenerated(entity) ) {
464+
if ( !context.isAlreadyGenerated(entity) && !entity.hasParent()) {
465+
context.logMessage( Diagnostic.Kind.OTHER,
466+
"Writing Jakarta Persistence metamodel for entity '" + entity + "'" );
467+
ClassWriter.writeFile( entity, context );
468+
context.markGenerated(entity);
469+
}
470+
}
471+
472+
for ( Metamodel entity : context.getMetaEntities() ) {
473+
if ( !context.isAlreadyGenerated(entity) && !entity.hasParent()) {
447474
context.logMessage( Diagnostic.Kind.OTHER,
448475
"Writing Jakarta Persistence metamodel for entity '" + entity + "'" );
449476
ClassWriter.writeFile( entity, context );
@@ -475,7 +502,7 @@ private void processEmbeddables(Collection<Metamodel> models) {
475502
final int toProcessCountBeforeLoop = models.size();
476503
for ( Metamodel metamodel : models ) {
477504
// see METAGEN-36
478-
if ( context.isAlreadyGenerated(metamodel) ) {
505+
if ( context.isAlreadyGenerated(metamodel) || metamodel.hasParent()) {
479506
processed.add( metamodel );
480507
}
481508
else if ( !modelGenerationNeedsToBeDeferred(models, metamodel ) ) {
@@ -529,6 +556,18 @@ private boolean modelGenerationNeedsToBeDeferred(Collection<Metamodel> entities,
529556
return false;
530557
}
531558

559+
private static boolean enclosesEntityOrEmbeddable(Element element) {
560+
if ( !(element instanceof TypeElement typeElement) ) {
561+
return false;
562+
}
563+
for ( final Element enclosedElement : typeElement.getEnclosedElements() ) {
564+
if ( isEntityOrEmbeddable( enclosedElement ) || enclosesEntityOrEmbeddable( enclosedElement ) ) {
565+
return true;
566+
}
567+
}
568+
return false;
569+
}
570+
532571
private static boolean isEntityOrEmbeddable(Element element) {
533572
return hasAnnotation(
534573
element,
@@ -560,7 +599,7 @@ private boolean hasAuxiliaryAnnotations(Element element) {
560599
);
561600
}
562601

563-
private void handleRootElementAnnotationMirrors(final Element element) {
602+
private void handleRootElementAnnotationMirrors(final Element element, @Nullable Element parent) {
564603
if ( isClassOrRecordType( element ) ) {
565604
if ( isEntityOrEmbeddable( element ) ) {
566605
final TypeElement typeElement = (TypeElement) element;
@@ -577,12 +616,23 @@ private void handleRootElementAnnotationMirrors(final Element element) {
577616
+ "' since XML configuration is metadata complete.");
578617
}
579618
else {
619+
AnnotationMetaEntity parentMetaEntity = null;
620+
if ( parent instanceof TypeElement parentTypeElement ) {
621+
if ( context.getMetamodel(
622+
parentTypeElement.getQualifiedName().toString() )
623+
instanceof AnnotationMetaEntity pme ) {
624+
parentMetaEntity = pme;
625+
}
626+
}
580627
final boolean requiresLazyMemberInitialization
581628
= hasAnnotation( element, EMBEDDABLE, MAPPED_SUPERCLASS );
629+
if (element.getSimpleName().toString().equals( "OffsetDateTimeTest" )) {
630+
System.err.println("Create OffsetDateTimeTest in handleRootElementAnnotationMirrors#2");
631+
}
582632
final AnnotationMetaEntity metaEntity =
583633
AnnotationMetaEntity.create( typeElement, context,
584634
requiresLazyMemberInitialization,
585-
true, false );
635+
true, false, parentMetaEntity );
586636
if ( alreadyExistingMetaEntity != null ) {
587637
metaEntity.mergeInMembers( alreadyExistingMetaEntity );
588638
}
@@ -596,10 +646,13 @@ && hasAnnotation( element, ENTITY, MAPPED_SUPERCLASS )
596646
// let a handwritten metamodel "override" the generated one
597647
// (this is used in the Jakarta Data TCK)
598648
&& !hasHandwrittenMetamodel(element) ) {
649+
if (element.getSimpleName().toString().equals( "OffsetDateTimeTest" )) {
650+
System.err.println("Create OffsetDateTimeTest in handleRootElementAnnotationMirrors#3");
651+
}
599652
final AnnotationMetaEntity dataMetaEntity =
600653
AnnotationMetaEntity.create( typeElement, context,
601654
requiresLazyMemberInitialization,
602-
true, true );
655+
true, true, parentMetaEntity );
603656
// final Metamodel alreadyExistingDataMetaEntity =
604657
// tryGettingExistingDataEntityFromContext( mirror, '_' + qualifiedName );
605658
// if ( alreadyExistingDataMetaEntity != null ) {

0 commit comments

Comments
 (0)