Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
HHH-18693 Fixing to work with Jakarta Data annotations; properly nami…
Browse files Browse the repository at this point in the history
…ng metadata classes
cigaly committed Nov 23, 2024
1 parent 00e2c9a commit 11a8adc
Showing 11 changed files with 84 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -4,15 +4,16 @@
*/
package org.hibernate.processor;

import jakarta.annotation.Nullable;
import org.hibernate.processor.annotation.AnnotationMetaEntity;
import org.hibernate.processor.annotation.InnerClassMetaAttribute;
import org.hibernate.processor.model.MetaAttribute;
import org.hibernate.processor.model.Metamodel;
import org.hibernate.processor.util.StringUtil;

import javax.annotation.processing.FilerException;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
@@ -27,7 +28,6 @@
import java.util.Set;
import java.util.stream.Collectors;


/**
* Helper class to write the actual metamodel class using the {@link javax.annotation.processing.Filer} API.
*
@@ -40,7 +40,6 @@ private ClassWriter() {
}

public static void writeFile(Metamodel entity, Context context) {
if (entity.hasParent()) throw new IllegalStateException();
try {
String metaModelPackage = entity.getPackageName();
// need to generate the body first, since this will also update
@@ -105,7 +104,7 @@ private static StringBuffer generateBody(Metamodel entity, Context context) {
}
entity.inheritedAnnotations().forEach(pw::println);

printClassDeclaration( entity, pw, context );
printClassDeclaration( entity, pw );

pw.println();

@@ -115,6 +114,7 @@ private static StringBuffer generateBody(Metamodel entity, Context context) {
generateBody( innerClass.getMetaEntity(), context )
.toString().lines()
.forEach(line -> pw.println('\t' + line));
context.markGenerated( innerClass.getMetaEntity() );
}
}

@@ -149,12 +149,13 @@ private static StringBuffer generateBody(Metamodel entity, Context context) {
}
}

private static void printClassDeclaration(Metamodel entity, PrintWriter pw, Context context) {
private static void printClassDeclaration(Metamodel entity, PrintWriter pw) {
if ( entity.hasParent() ) {
final Set<Modifier> modifiers = entity.getElement().getModifiers();
if (modifiers.contains( Modifier.PUBLIC )){
if ( modifiers.contains( Modifier.PUBLIC ) ) {
pw.print( "public " );
}else if (modifiers.contains( Modifier.PROTECTED )) {
}
else if ( modifiers.contains( Modifier.PROTECTED ) ) {
pw.print( "protected " );
}
pw.print( "static " );
@@ -168,70 +169,49 @@ private static void printClassDeclaration(Metamodel entity, PrintWriter pw, Cont
pw.print( entity.isJakartaDataStyle() ? "interface " : "class " );
pw.print( getGeneratedClassName(entity) );

String superClassName = entity.getSupertypeName();
if ( superClassName != null ) {
Metamodel superClassEntity = context.getMetaEntity( superClassName );
if (superClassEntity == null) {
superClassEntity = context.getMetaEmbeddable( superClassName );
}
final String superclassName = getGeneratedSuperclassName(
superClassName, superClassEntity, entity.isJakartaDataStyle() );
if (entity.getSimpleName().equals( "OffsetDateTimeTest" )) {
System.err.printf( "Extends (?) %s - superClassName is not null%n", superClassName );
}
pw.print( " extends " + entity.importType(superclassName) );
final Element superTypeElement = entity.getSuperTypeElement();
if ( superTypeElement != null ) {
pw.print( " extends " +
entity.importType(getGeneratedSuperclassName( superTypeElement, entity.isJakartaDataStyle() )) );
}
if ( entity.isImplementation() ) {
pw.print( entity.getElement().getKind() == ElementKind.CLASS ? " extends " : " implements " );
pw.print( entity.getSimpleName() );
if (entity.getSimpleName().equals( "OffsetDateTimeTest" )) {
System.err.printf( "Extends (?) %s -- implementation (?!?)%n", entity.getSimpleName() );
}
}

pw.println( " {" );
}

private static String getFullyQualifiedClassName(Metamodel entity) {
final String metaModelPackage = entity.getPackageName();
String fullyQualifiedClassName = "";
if ( !metaModelPackage.isEmpty() ) {
fullyQualifiedClassName = fullyQualifiedClassName + metaModelPackage + ".";
}
final String packageNamePrefix = !metaModelPackage.isEmpty() ? metaModelPackage + "." : "";
final String className;
if ( entity.getElement().getKind() == ElementKind.PACKAGE ) {
className = getGeneratedClassName( entity );
}
else {
className = Arrays.stream(
entity.getQualifiedName().substring( fullyQualifiedClassName.length() ).split( "\\." ) )
.map( AnnotationMetaEntity::removeDollar )
entity.getQualifiedName().substring( packageNamePrefix.length() ).split( "\\." ) )
.map( StringUtil::removeDollar )
.map( part -> entity.isJakartaDataStyle() ? '_' + part : part + '_' )
.collect( Collectors.joining( "." ) );
}
return fullyQualifiedClassName + className;
return packageNamePrefix + className;
}

private static String getGeneratedClassName(Metamodel entity) {
final String className = entity.getSimpleName();
return entity.isJakartaDataStyle() ? '_' + className : className + '_'; // TODO : check inner class!!!
return entity.isJakartaDataStyle() ? '_' + className : className + '_';
}

private static String getGeneratedSuperclassName(String superClassName, @Nullable Metamodel superClassEntity, boolean jakartaDataStyle) {
if ( jakartaDataStyle ) {
int lastDot = superClassName.lastIndexOf('.');
if ( lastDot<0 ) {
return '_' + superClassName;
}
else {
return superClassName.substring(0,lastDot+1)
+ '_' + superClassName.substring(lastDot+1);
}
}
else {
return superClassEntity == null ? superClassName + '_'
: getFullyQualifiedClassName( superClassEntity );
}
private static String getGeneratedSuperclassName(Element superClassElement, boolean jakartaDataStyle) {
final TypeElement typeElement = (TypeElement) superClassElement;
final String simpleName = typeElement.getSimpleName().toString();
final Element enclosingElement = typeElement.getEnclosingElement();
return (enclosingElement instanceof TypeElement
? getGeneratedSuperclassName( enclosingElement, jakartaDataStyle )
: ((PackageElement) enclosingElement).getQualifiedName().toString())
+ "." + (jakartaDataStyle ? '_' + simpleName : simpleName + '_');
}

private static String writeGeneratedAnnotation(Metamodel entity, Context context) {
Original file line number Diff line number Diff line change
@@ -416,14 +416,26 @@ else if ( element instanceof TypeElement typeElement ) {
parentMeta = parentMetaEntity;
}
}
if (element.getSimpleName().toString().equals( "OffsetDateTimeTest" )) {
System.err.println("Create OffsetDateTimeTest as non-entity class#1");
}
final NonManagedMetamodel metaEntity =
NonManagedMetamodel .create(
typeElement, context,
parentMeta );
false, parentMeta );
context.addMetaEntity( metaEntity.getQualifiedName(), metaEntity );
if ( context.generateJakartaDataStaticMetamodel()) {
AnnotationMetaEntity parentDataMeta = null;
if ( parent instanceof TypeElement parentElement ) {
final String key = parentElement.getQualifiedName().toString();
if ( context.getDataMetaEntity( key ) instanceof AnnotationMetaEntity parentMetaEntity ) {
parentDataMeta = parentMetaEntity;
}
}
final NonManagedMetamodel dataMetaEntity =
NonManagedMetamodel .create(
typeElement, context,
true, parentDataMeta );
context.addDataMetaEntity( dataMetaEntity.getQualifiedName(), dataMetaEntity );
}

}
}
}
@@ -471,17 +483,8 @@ private void createMetaModelClasses() {
}
}

for ( Metamodel entity : context.getMetaEntities() ) {
if ( !context.isAlreadyGenerated(entity) && !entity.hasParent()) {
context.logMessage( Diagnostic.Kind.OTHER,
"Writing Jakarta Persistence metamodel for entity '" + entity + "'" );
ClassWriter.writeFile( entity, context );
context.markGenerated(entity);
}
}

for ( Metamodel entity : context.getDataMetaEntities() ) {
if ( !context.isAlreadyGenerated(entity) ) {
if ( !context.isAlreadyGenerated(entity) && !entity.hasParent()) {
context.logMessage( Diagnostic.Kind.OTHER,
"Writing Jakarta Data metamodel for entity '" + entity + "'" );
ClassWriter.writeFile( entity, context );
@@ -504,7 +507,7 @@ private void processEmbeddables(Collection<Metamodel> models) {
final int toProcessCountBeforeLoop = models.size();
for ( Metamodel metamodel : models ) {
// see METAGEN-36
if ( context.isAlreadyGenerated(metamodel) || metamodel.hasParent()) {
if ( context.isAlreadyGenerated(metamodel) ) {
processed.add( metamodel );
}
else if ( !modelGenerationNeedsToBeDeferred(models, metamodel ) ) {
@@ -628,9 +631,6 @@ private void handleRootElementAnnotationMirrors(final Element element, @Nullable
}
final boolean requiresLazyMemberInitialization
= hasAnnotation( element, EMBEDDABLE, MAPPED_SUPERCLASS );
if (element.getSimpleName().toString().equals( "OffsetDateTimeTest" )) {
System.err.println("Create OffsetDateTimeTest in handleRootElementAnnotationMirrors#2");
}
final AnnotationMetaEntity metaEntity =
AnnotationMetaEntity.create( typeElement, context,
requiresLazyMemberInitialization,
@@ -648,13 +648,17 @@ && hasAnnotation( element, ENTITY, MAPPED_SUPERCLASS )
// let a handwritten metamodel "override" the generated one
// (this is used in the Jakarta Data TCK)
&& !hasHandwrittenMetamodel(element) ) {
if (element.getSimpleName().toString().equals( "OffsetDateTimeTest" )) {
System.err.println("Create OffsetDateTimeTest in handleRootElementAnnotationMirrors#3");
AnnotationMetaEntity parentDataEntity = null;
if ( parent instanceof TypeElement parentTypeElement ) {
if ( context.getDataMetaEntity( parentTypeElement.getQualifiedName().toString() )
instanceof AnnotationMetaEntity pme ) {
parentDataEntity = pme;
}
}
final AnnotationMetaEntity dataMetaEntity =
AnnotationMetaEntity.create( typeElement, context,
requiresLazyMemberInitialization,
true, true, parentMetaEntity );
true, true, parentDataEntity );
// final Metamodel alreadyExistingDataMetaEntity =
// tryGettingExistingDataEntityFromContext( mirror, '_' + qualifiedName );
// if ( alreadyExistingDataMetaEntity != null ) {
Original file line number Diff line number Diff line change
@@ -80,11 +80,12 @@
import static org.hibernate.processor.annotation.QueryMethod.isPageParam;
import static org.hibernate.processor.util.Constants.*;
import static org.hibernate.processor.util.NullnessUtil.castNonNull;
import static org.hibernate.processor.util.StringUtil.removeDollar;
import static org.hibernate.processor.util.TypeUtils.containsAnnotation;
import static org.hibernate.processor.util.TypeUtils.determineAccessTypeForHierarchy;
import static org.hibernate.processor.util.TypeUtils.determineAnnotationSpecifiedAccessType;
import static org.hibernate.processor.util.TypeUtils.extendsClass;
import static org.hibernate.processor.util.TypeUtils.findMappedSuperClass;
import static org.hibernate.processor.util.TypeUtils.findMappedSuperElement;
import static org.hibernate.processor.util.TypeUtils.getAnnotationMirror;
import static org.hibernate.processor.util.TypeUtils.getAnnotationValue;
import static org.hibernate.processor.util.TypeUtils.hasAnnotation;
@@ -232,18 +233,6 @@ private String getConstructorName() {
return getSimpleName() + '_';
}

/**
* If this is an "intermediate" class providing {@code @Query}
* annotations for the query by magical method name crap, then
* by convention it will be named with a trailing $ sign. Strip
* that off, so we get the standard constructor.
*/
public static String removeDollar(String simpleName) {
return simpleName.endsWith("$")
? simpleName.substring(0, simpleName.length()-1)
: simpleName;
}

@Override
public final String getQualifiedName() {
if ( qualifiedName == null ) {
@@ -253,8 +242,8 @@ public final String getQualifiedName() {
}

@Override
public @Nullable String getSupertypeName() {
return repository ? null : findMappedSuperClass( this, context );
public @Nullable Element getSuperTypeElement() {
return repository ? null : findMappedSuperElement( this, context );
}

@Override
@@ -278,7 +267,7 @@ public List<MetaAttribute> getMembers() {
}

public void addInnerClass(AnnotationMetaEntity metaEntity) {
putMember( "INNER_"+ metaEntity.getQualifiedName(), new InnerClassMetaAttribute( metaEntity ) );
putMember( "INNER_" + metaEntity.getQualifiedName(), new InnerClassMetaAttribute( metaEntity ) );
}

@Override
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
import org.hibernate.processor.model.MetaAttribute;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.PackageElement;
import javax.tools.Diagnostic;
import java.util.ArrayList;
@@ -69,7 +70,7 @@ public final String getQualifiedName() {
}

@Override
public @Nullable String getSupertypeName() {
public @Nullable Element getSuperTypeElement() {
return null;
}

Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@ public String getAttributeDeclarationString() {
final StringBuilder declaration = new StringBuilder();
declaration
.append('\n');
if ( annotationMetaEntity.getSupertypeName() == null ) {
if ( annotationMetaEntity.getSuperTypeElement() == null ) {
declaration
.append("@")
.append(annotationMetaEntity.importType("jakarta.persistence.PersistenceUnit"));
Original file line number Diff line number Diff line change
@@ -11,15 +11,16 @@

public class NonManagedMetamodel extends AnnotationMetaEntity {

public NonManagedMetamodel(TypeElement element, Context context, @Nullable AnnotationMeta parent) {
super( element, context, false, false, parent );
public NonManagedMetamodel(TypeElement element, Context context, boolean jakartaDataStaticMetamodel, @Nullable AnnotationMeta parent) {
super( element, context, false, jakartaDataStaticMetamodel, parent );
}

public static NonManagedMetamodel create(
TypeElement element, Context context,
boolean jakartaDataStaticMetamodel,
@Nullable AnnotationMetaEntity parent) {
final NonManagedMetamodel metamodel =
new NonManagedMetamodel( element, context, parent );
new NonManagedMetamodel( element, context, jakartaDataStaticMetamodel, parent );
if ( parent != null ) {
metamodel.setParentElement( parent.getElement() );
parent.addInnerClass( metamodel );
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ public String getAttributeDeclarationString() {
final StringBuilder declaration = new StringBuilder();
declaration
.append('\n');
if ( annotationMetaEntity.getSupertypeName() == null ) {
if ( annotationMetaEntity.getSuperTypeElement() == null ) {
declaration
.append("protected ");
if ( !dataRepository ) {
@@ -96,7 +96,7 @@ public String getAttributeDeclarationString() {
.append(" ")
.append(sessionVariableName)
.append(") {\n");
if ( annotationMetaEntity.getSupertypeName() != null ) {
if ( annotationMetaEntity.getSuperTypeElement() != null ) {
declaration
.append("\tsuper(")
.append(sessionVariableName)
@@ -112,7 +112,7 @@ public String getAttributeDeclarationString() {
}
declaration
.append("}");
if ( annotationMetaEntity.getSupertypeName() == null ) {
if ( annotationMetaEntity.getSuperTypeElement() == null ) {
declaration
.append("\n\n");
if (addOverrideAnnotation) {
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ public interface Metamodel extends ImportContext {

String getQualifiedName();

@Nullable String getSupertypeName();
@Nullable Element getSuperTypeElement();

String getPackageName();

Original file line number Diff line number Diff line change
@@ -119,4 +119,16 @@ private static boolean startsWithSeveralUpperCaseLetters(String string) {
&& isUpperCase( string.charAt( 0 ) )
&& isUpperCase( string.charAt( 1 ) );
}

/**
* If this is an "intermediate" class providing {@code @Query}
* annotations for the query by magical method name crap, then
* by convention it will be named with a trailing $ sign. Strip
* that off, so we get the standard constructor.
*/
public static String removeDollar(String simpleName) {
return simpleName.endsWith("$")
? simpleName.substring(0, simpleName.length()-1)
: simpleName;
}
}
Original file line number Diff line number Diff line change
@@ -598,7 +598,7 @@ else if ( name.startsWith( "is" ) ) {
}
}

public static @Nullable String findMappedSuperClass(Metamodel entity, Context context) {
public static @Nullable Element findMappedSuperElement(Metamodel entity, Context context) {
final Element element = entity.getElement();
if ( element instanceof TypeElement typeElement ) {
TypeMirror superClass = typeElement.getSuperclass();
@@ -607,7 +607,7 @@ else if ( name.startsWith( "is" ) ) {
final DeclaredType declaredType = (DeclaredType) superClass;
final TypeElement superClassElement = (TypeElement) declaredType.asElement();
if ( extendsSuperMetaModel( superClassElement, entity.isMetaComplete(), context ) ) {
return superClassElement.getQualifiedName().toString();
return superClassElement;
}
superClass = superClassElement.getSuperclass();
}
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@
import static org.hibernate.processor.util.StringUtil.isFullyQualified;
import static org.hibernate.processor.util.StringUtil.packageNameFromFullyQualifiedName;
import static org.hibernate.processor.util.TypeUtils.extractClosestRealTypeAsString;
import static org.hibernate.processor.util.TypeUtils.findMappedSuperClass;
import static org.hibernate.processor.util.TypeUtils.findMappedSuperElement;
import static org.hibernate.processor.util.TypeUtils.getElementKindForAccessType;

/**
@@ -165,8 +165,8 @@ public String getPackageName() {
}

@Override
public @Nullable String getSupertypeName() {
return findMappedSuperClass( this, context );
public @Nullable Element getSuperTypeElement() {
return findMappedSuperElement( this, context );
}

public List<MetaAttribute> getMembers() {

0 comments on commit 11a8adc

Please sign in to comment.