HHH-17772 Jakarta Data static metamodel

This commit is contained in:
Gavin King 2024-02-24 17:15:33 +01:00
parent a23792ca1b
commit 67a5590316
11 changed files with 221 additions and 151 deletions

View File

@ -6,6 +6,14 @@
*/ */
package org.hibernate.jpamodelgen; package org.hibernate.jpamodelgen;
import org.hibernate.jpamodelgen.model.MetaAttribute;
import org.hibernate.jpamodelgen.model.Metamodel;
import javax.annotation.processing.FilerException;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -13,23 +21,6 @@ import java.io.StringWriter;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import javax.annotation.processing.FilerException;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import org.hibernate.jpamodelgen.model.MetaAttribute;
import org.hibernate.jpamodelgen.model.Metamodel;
import org.hibernate.jpamodelgen.util.Constants;
import org.checkerframework.checker.nullness.qual.Nullable;
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
/** /**
* Helper class to write the actual metamodel class using the {@link javax.annotation.processing.Filer} API. * Helper class to write the actual metamodel class using the {@link javax.annotation.processing.Filer} API.
@ -50,7 +41,7 @@ public final class ClassWriter {
String body = generateBody( entity, context ).toString(); String body = generateBody( entity, context ).toString();
FileObject fo = context.getProcessingEnvironment().getFiler().createSourceFile( FileObject fo = context.getProcessingEnvironment().getFiler().createSourceFile(
getFullyQualifiedClassName( entity, metaModelPackage, context ), getFullyQualifiedClassName( entity, metaModelPackage ),
entity.getElement() entity.getElement()
); );
OutputStream os = fo.openOutputStream(); OutputStream os = fo.openOutputStream();
@ -95,7 +86,7 @@ public final class ClassWriter {
pw.println( writeScopeAnnotation( entity ) ); pw.println( writeScopeAnnotation( entity ) );
} }
if ( entity.getElement() instanceof TypeElement && !entity.isInjectable() ) { if ( entity.getElement() instanceof TypeElement && !entity.isInjectable() ) {
pw.println( writeStaticMetaModelAnnotation( entity, context ) ); pw.println( writeStaticMetaModelAnnotation( entity ) );
} }
if ( context.addGeneratedAnnotation() ) { if ( context.addGeneratedAnnotation() ) {
pw.println( writeGeneratedAnnotation( entity, context ) ); pw.println( writeGeneratedAnnotation( entity, context ) );
@ -104,7 +95,7 @@ public final class ClassWriter {
pw.println( writeSuppressWarnings() ); pw.println( writeSuppressWarnings() );
} }
printClassDeclaration( entity, pw, context ); printClassDeclaration( entity, pw );
pw.println(); pw.println();
@ -128,13 +119,13 @@ public final class ClassWriter {
} }
} }
private static void printClassDeclaration(Metamodel entity, PrintWriter pw, Context context) { private static void printClassDeclaration(Metamodel entity, PrintWriter pw) {
pw.print( entity.isImplementation() ? "public class " : "public abstract class " ); pw.print( entity.isImplementation() ? "public class " : "public abstract class " );
pw.print( generatedClassName( context, entity.getSimpleName() ) ); pw.print( getGeneratedClassName(entity) );
String superClassName = findMappedSuperClass( entity, context ); String superClassName = entity.getSupertypeName();
if ( superClassName != null ) { if ( superClassName != null ) {
pw.print( " extends " + generatedClassName( context, superClassName ) ); pw.print( " extends " + getGeneratedSuperclassName(entity, superClassName) );
} }
if ( entity.isImplementation() ) { if ( entity.isImplementation() ) {
pw.print( entity.getElement().getKind() == ElementKind.CLASS ? " extends " : " implements " ); pw.print( entity.getElement().getKind() == ElementKind.CLASS ? " extends " : " implements " );
@ -144,68 +135,36 @@ public final class ClassWriter {
pw.println( " {" ); pw.println( " {" );
} }
private static String generatedClassName(Context context, String superClassName) { private static String getFullyQualifiedClassName(Metamodel entity, String metaModelPackage) {
return context.useJakartaDataStyle() ? '_' + superClassName : superClassName + '_';
}
private static @Nullable String findMappedSuperClass(Metamodel entity, Context context) {
Element element = entity.getElement();
if ( element instanceof TypeElement ) {
TypeMirror superClass = ((TypeElement) element).getSuperclass();
//superclass of Object is of NoType which returns some other kind
while ( superClass.getKind() == TypeKind.DECLARED ) {
final Element superClassElement = ( (DeclaredType) superClass ).asElement();
String superClassName = ( (TypeElement) superClassElement ).getQualifiedName().toString();
if ( extendsSuperMetaModel( superClassElement, entity.isMetaComplete(), context ) ) {
return superClassName;
}
superClass = ( (TypeElement) superClassElement ).getSuperclass();
}
}
return null;
}
/**
* Checks whether this metamodel class needs to extend another metamodel class.
* This method checks whether the processor has generated a metamodel class for the super class, but it also
* allows for the possibility that the metamodel class was generated in a previous compilation. (It could be
* part of a separate jar. See also METAGEN-35.)
*
* @param superClassElement the super class element
* @param entityMetaComplete flag indicating if the entity for which the metamodel should be generated is
* metamodel complete. If so we cannot use reflection to decide whether we have to add the extends clause
* @param context the execution context
*
* @return {@code true} in case there is super class metamodel to extend from {@code false} otherwise.
*/
private static boolean extendsSuperMetaModel(Element superClassElement, boolean entityMetaComplete, Context context) {
// if we processed the superclass in the same run we definitely need to extend
String superClassName = ( (TypeElement) superClassElement ).getQualifiedName().toString();
if ( context.containsMetaEntity( superClassName )
|| context.containsMetaEmbeddable( superClassName ) ) {
return true;
}
// to allow for the case that the metamodel class for the super entity is for example contained in another
// jar file we use reflection. However, we need to consider the fact that there is xml configuration
// and annotations should be ignored
if ( !entityMetaComplete
&& containsAnnotation( superClassElement, Constants.ENTITY, Constants.MAPPED_SUPERCLASS ) ) {
return true;
}
return false;
}
private static String getFullyQualifiedClassName(Metamodel entity, String metaModelPackage, Context context) {
String fullyQualifiedClassName = ""; String fullyQualifiedClassName = "";
if ( !metaModelPackage.isEmpty() ) { if ( !metaModelPackage.isEmpty() ) {
fullyQualifiedClassName = fullyQualifiedClassName + metaModelPackage + "."; fullyQualifiedClassName = fullyQualifiedClassName + metaModelPackage + ".";
} }
fullyQualifiedClassName = fullyQualifiedClassName + generatedClassName( context, entity.getSimpleName() ); fullyQualifiedClassName = fullyQualifiedClassName + getGeneratedClassName( entity );
return fullyQualifiedClassName; return fullyQualifiedClassName;
} }
private static String getGeneratedClassName(Metamodel entity) {
final String className = entity.getSimpleName();
return entity.isJakartaDataStyle() ? '_' + className : className + '_';
}
private static String getGeneratedSuperclassName(Metamodel entity, String superClassName) {
if ( entity.isJakartaDataStyle() ) {
int lastDot = superClassName.lastIndexOf('.');
if ( lastDot<0 ) {
return '_' + superClassName;
}
else {
return superClassName.substring(0,lastDot+1)
+ '_' + superClassName.substring(lastDot+1);
}
}
else {
return superClassName + '_';
}
}
private static String writeGeneratedAnnotation(Metamodel entity, Context context) { private static String writeGeneratedAnnotation(Metamodel entity, Context context) {
StringBuilder generatedAnnotation = new StringBuilder(); StringBuilder generatedAnnotation = new StringBuilder();
generatedAnnotation generatedAnnotation
@ -239,8 +198,8 @@ public final class ClassWriter {
return "@" + entity.importType( entity.scope() ); return "@" + entity.importType( entity.scope() );
} }
private static String writeStaticMetaModelAnnotation(Metamodel entity, Context context) { private static String writeStaticMetaModelAnnotation(Metamodel entity) {
final String annotation = context.useJakartaDataStyle() final String annotation = entity.isJakartaDataStyle()
? "jakarta.data.metamodel.StaticMetamodel" ? "jakarta.data.metamodel.StaticMetamodel"
: "jakarta.persistence.metamodel.StaticMetamodel"; : "jakarta.persistence.metamodel.StaticMetamodel";
return "@" + entity.importType( annotation ) + "(" + entity.getSimpleName() + ".class)"; return "@" + entity.importType( annotation ) + "(" + entity.getSimpleName() + ".class)";

View File

@ -76,7 +76,6 @@ public final class Context {
private boolean addTransactionScopedAnnotation; private boolean addTransactionScopedAnnotation;
private AccessType persistenceUnitDefaultAccessType; private AccessType persistenceUnitDefaultAccessType;
private boolean generateJakartaDataStaticMetamodel; private boolean generateJakartaDataStaticMetamodel;
private boolean jakartaDataStyle;
// keep track of all classes for which model have been generated // keep track of all classes for which model have been generated
private final Collection<String> generatedModelClasses = new HashSet<>(); private final Collection<String> generatedModelClasses = new HashSet<>();
@ -122,14 +121,6 @@ public final class Context {
return processingEnvironment; return processingEnvironment;
} }
public boolean useJakartaDataStyle() {
return jakartaDataStyle;
}
public void setJakartaDataStyle(boolean jakartaDataStyle) {
this.jakartaDataStyle = jakartaDataStyle;
}
public boolean generateJakartaDataStaticMetamodel() { public boolean generateJakartaDataStaticMetamodel() {
return generateJakartaDataStaticMetamodel; return generateJakartaDataStaticMetamodel;
} }
@ -210,61 +201,61 @@ public final class Context {
return ormXmlFiles; return ormXmlFiles;
} }
public boolean containsMetaEntity(String fqcn) { public boolean containsMetaEntity(String qualifiedName) {
return metaEntities.containsKey( fqcn ); return metaEntities.containsKey( qualifiedName );
} }
public @Nullable Metamodel getMetaEntity(String fqcn) { public @Nullable Metamodel getMetaEntity(String qualifiedName) {
return metaEntities.get( fqcn ); return metaEntities.get( qualifiedName );
} }
public Collection<Metamodel> getMetaEntities() { public Collection<Metamodel> getMetaEntities() {
return metaEntities.values(); return metaEntities.values();
} }
public void addMetaEntity(String fqcn, Metamodel metaEntity) { public void addMetaEntity(String qualifiedName, Metamodel metaEntity) {
metaEntities.put( fqcn, metaEntity ); metaEntities.put( qualifiedName, metaEntity );
} }
public boolean containsMetaEmbeddable(String fqcn) { public boolean containsMetaEmbeddable(String qualifiedName) {
return metaEmbeddables.containsKey( fqcn ); return metaEmbeddables.containsKey( qualifiedName );
} }
public @Nullable Metamodel getMetaEmbeddable(String fqcn) { public @Nullable Metamodel getMetaEmbeddable(String qualifiedName) {
return metaEmbeddables.get( fqcn ); return metaEmbeddables.get( qualifiedName );
} }
public void addMetaEmbeddable(String fqcn, Metamodel metaEntity) { public void addMetaEmbeddable(String qualifiedName, Metamodel metaEntity) {
metaEmbeddables.put( fqcn, metaEntity ); metaEmbeddables.put( qualifiedName, metaEntity );
} }
public Collection<Metamodel> getMetaEmbeddables() { public Collection<Metamodel> getMetaEmbeddables() {
return metaEmbeddables.values(); return metaEmbeddables.values();
} }
public @Nullable Metamodel getMetaAuxiliary(String fqcn) { public @Nullable Metamodel getMetaAuxiliary(String qualifiedName) {
return metaAuxiliaries.get( fqcn ); return metaAuxiliaries.get( qualifiedName );
} }
public Collection<Metamodel> getMetaAuxiliaries() { public Collection<Metamodel> getMetaAuxiliaries() {
return metaAuxiliaries.values(); return metaAuxiliaries.values();
} }
public void addMetaAuxiliary(String fqcn, Metamodel metamodel) { public void addMetaAuxiliary(String qualifiedName, Metamodel metamodel) {
metaAuxiliaries.put( fqcn, metamodel); metaAuxiliaries.put( qualifiedName, metamodel);
} }
public void addAccessTypeInformation(String fqcn, AccessTypeInformation info) { public void addAccessTypeInformation(String qualifiedName, AccessTypeInformation info) {
accessTypeInformation.put( fqcn, info ); accessTypeInformation.put( qualifiedName, info );
} }
public @Nullable AccessTypeInformation getAccessTypeInfo(String fqcn) { public @Nullable AccessTypeInformation getAccessTypeInfo(String qualifiedName) {
return accessTypeInformation.get( fqcn ); return accessTypeInformation.get( qualifiedName );
} }
public TypeElement getTypeElementForFullyQualifiedName(String fqcn) { public TypeElement getTypeElementForFullyQualifiedName(String qualifiedName) {
Elements elementUtils = processingEnvironment.getElementUtils(); Elements elementUtils = processingEnvironment.getElementUtils();
return elementUtils.getTypeElement( fqcn ); return elementUtils.getTypeElement( qualifiedName );
} }
void markGenerated(String name) { void markGenerated(String name) {

View File

@ -67,14 +67,10 @@ import static org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.*;
LAZY_XML_PARSING, LAZY_XML_PARSING,
ADD_GENERATION_DATE, ADD_GENERATION_DATE,
ADD_GENERATED_ANNOTATION, ADD_GENERATED_ANNOTATION,
ADD_SUPPRESS_WARNINGS_ANNOTATION, ADD_SUPPRESS_WARNINGS_ANNOTATION
JAKARTA_DATA_OPTION
}) })
public class JPAMetaModelEntityProcessor extends AbstractProcessor { public class JPAMetaModelEntityProcessor extends AbstractProcessor {
/**
* Produce Jakarta Data style static metamodel
*/
public static final String JAKARTA_DATA_OPTION = "jakartaDataStyle";
/** /**
* Debug logging from the processor * Debug logging from the processor
*/ */
@ -174,8 +170,6 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
context.setAddSuppressWarningsAnnotation( parseBoolean( options.get( ADD_SUPPRESS_WARNINGS_ANNOTATION ) ) ); context.setAddSuppressWarningsAnnotation( parseBoolean( options.get( ADD_SUPPRESS_WARNINGS_ANNOTATION ) ) );
context.setJakartaDataStyle( parseBoolean( options.get( JAKARTA_DATA_OPTION ) ) );
return parseBoolean( options.get( FULLY_ANNOTATION_CONFIGURED_OPTION ) ); return parseBoolean( options.get( FULLY_ANNOTATION_CONFIGURED_OPTION ) );
} }
@ -287,18 +281,22 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
private void createMetaModelClasses() { private void createMetaModelClasses() {
for ( Metamodel aux : context.getMetaAuxiliaries() ) { for ( Metamodel aux : context.getMetaAuxiliaries() ) {
if ( !context.isAlreadyGenerated( aux.getQualifiedName() ) ) { final String key = aux.getQualifiedName();
if ( !context.isAlreadyGenerated(key) ) {
context.logMessage( Diagnostic.Kind.OTHER, "Writing metamodel for auxiliary '" + aux + "'" ); context.logMessage( Diagnostic.Kind.OTHER, "Writing metamodel for auxiliary '" + aux + "'" );
ClassWriter.writeFile( aux, context ); ClassWriter.writeFile( aux, context );
context.markGenerated( aux.getQualifiedName() ); context.markGenerated(key);
} }
} }
for ( Metamodel entity : context.getMetaEntities() ) { for ( Metamodel entity : context.getMetaEntities() ) {
if ( !context.isAlreadyGenerated( entity.getQualifiedName() ) ) { final String key = entity.isJakartaDataStyle()
? '_' + entity.getQualifiedName()
: entity.getQualifiedName();
if ( !context.isAlreadyGenerated(key) ) {
context.logMessage( Diagnostic.Kind.OTHER, "Writing metamodel for entity '" + entity + "'" ); context.logMessage( Diagnostic.Kind.OTHER, "Writing metamodel for entity '" + entity + "'" );
ClassWriter.writeFile( entity, context ); ClassWriter.writeFile( entity, context );
context.markGenerated( entity.getQualifiedName() ); context.markGenerated(key);
} }
} }
@ -310,7 +308,10 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
int toProcessCountBeforeLoop = toProcessEntities.size(); int toProcessCountBeforeLoop = toProcessEntities.size();
for ( Metamodel entity : toProcessEntities ) { for ( Metamodel entity : toProcessEntities ) {
// see METAGEN-36 // see METAGEN-36
if ( context.isAlreadyGenerated( entity.getQualifiedName() ) ) { final String key = entity.isJakartaDataStyle()
? '_' + entity.getQualifiedName()
: entity.getQualifiedName();
if ( context.isAlreadyGenerated(key) ) {
processedEntities.add( entity ); processedEntities.add( entity );
} }
else if ( !modelGenerationNeedsToBeDeferred( toProcessEntities, entity ) ) { else if ( !modelGenerationNeedsToBeDeferred( toProcessEntities, entity ) ) {
@ -319,7 +320,7 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
"Writing meta model for embeddable/mapped superclass " + entity "Writing meta model for embeddable/mapped superclass " + entity
); );
ClassWriter.writeFile( entity, context ); ClassWriter.writeFile( entity, context );
context.markGenerated( entity.getQualifiedName() ); context.markGenerated(key);
processedEntities.add( entity ); processedEntities.add( entity );
} }
} }
@ -400,7 +401,8 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
for ( AnnotationMirror mirror : element.getAnnotationMirrors() ) { for ( AnnotationMirror mirror : element.getAnnotationMirrors() ) {
final TypeElement typeElement = (TypeElement) element; final TypeElement typeElement = (TypeElement) element;
final String qualifiedName = typeElement.getQualifiedName().toString(); final String qualifiedName = typeElement.getQualifiedName().toString();
final Metamodel alreadyExistingMetaEntity = tryGettingExistingEntityFromContext( mirror, qualifiedName ); final Metamodel alreadyExistingMetaEntity =
tryGettingExistingEntityFromContext( mirror, qualifiedName );
if ( alreadyExistingMetaEntity != null && alreadyExistingMetaEntity.isMetaComplete() ) { if ( alreadyExistingMetaEntity != null && alreadyExistingMetaEntity.isMetaComplete() ) {
context.logMessage( context.logMessage(
Diagnostic.Kind.OTHER, Diagnostic.Kind.OTHER,
@ -408,15 +410,29 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
+ "' since XML configuration is metadata complete."); + "' since XML configuration is metadata complete.");
} }
else { else {
boolean requiresLazyMemberInitialization final boolean requiresLazyMemberInitialization
= containsAnnotation( element, EMBEDDABLE ) = hasAnnotation( element, EMBEDDABLE, MAPPED_SUPERCLASS );
|| containsAnnotation( element, MAPPED_SUPERCLASS );
final AnnotationMetaEntity metaEntity = final AnnotationMetaEntity metaEntity =
AnnotationMetaEntity.create( typeElement, context, requiresLazyMemberInitialization, true ); AnnotationMetaEntity.create( typeElement, context,
requiresLazyMemberInitialization, true );
if ( alreadyExistingMetaEntity != null ) { if ( alreadyExistingMetaEntity != null ) {
metaEntity.mergeInMembers( alreadyExistingMetaEntity ); metaEntity.mergeInMembers( alreadyExistingMetaEntity );
} }
addMetaEntityToContext( mirror, metaEntity ); addMetaEntityToContext( mirror, metaEntity );
if ( context.generateJakartaDataStaticMetamodel()
// Don't generate a Jakarta Data metamodel
// if this entity was partially mapped in XML
&& alreadyExistingMetaEntity == null ) {
final AnnotationMetaEntity dataMetaEntity =
AnnotationMetaEntity.create( typeElement, context,
requiresLazyMemberInitialization, true, true );
// final Metamodel alreadyExistingDataMetaEntity =
// tryGettingExistingEntityFromContext( mirror, '_' + qualifiedName );
// if ( alreadyExistingDataMetaEntity != null ) {
// dataMetaEntity.mergeInMembers( alreadyExistingDataMetaEntity );
// }
addMetaEntityToContext( mirror, dataMetaEntity );
}
} }
} }
} }
@ -448,14 +464,17 @@ public class JPAMetaModelEntityProcessor extends AbstractProcessor {
} }
private void addMetaEntityToContext(AnnotationMirror mirror, AnnotationMetaEntity metaEntity) { private void addMetaEntityToContext(AnnotationMirror mirror, AnnotationMetaEntity metaEntity) {
final String key = metaEntity.isJakartaDataStyle()
? '_' + metaEntity.getQualifiedName()
: metaEntity.getQualifiedName();
if ( isAnnotationMirrorOfType( mirror, ENTITY ) ) { if ( isAnnotationMirrorOfType( mirror, ENTITY ) ) {
context.addMetaEntity( metaEntity.getQualifiedName(), metaEntity ); context.addMetaEntity( key, metaEntity );
} }
else if ( isAnnotationMirrorOfType( mirror, MAPPED_SUPERCLASS ) ) { else if ( isAnnotationMirrorOfType( mirror, MAPPED_SUPERCLASS ) ) {
context.addMetaEntity( metaEntity.getQualifiedName(), metaEntity ); context.addMetaEntity( key, metaEntity );
} }
else if ( isAnnotationMirrorOfType( mirror, EMBEDDABLE ) ) { else if ( isAnnotationMirrorOfType( mirror, EMBEDDABLE ) ) {
context.addMetaEmbeddable( metaEntity.getQualifiedName(), metaEntity ); context.addMetaEmbeddable( key, metaEntity );
} }
} }

View File

@ -59,7 +59,6 @@ public abstract class AnnotationMetaAttribute implements MetaAttribute {
.append( parent.importType( getTypeDeclaration() ) ) .append( parent.importType( getTypeDeclaration() ) )
.append( "> " ) .append( "> " )
.append( getPropertyName() ) .append( getPropertyName() )
.append( parent.getContext().useJakartaDataStyle() ? "_" : "" )
.append( ";" ) .append( ";" )
.toString(); .toString();
} }

View File

@ -86,6 +86,7 @@ import static org.hibernate.jpamodelgen.util.NullnessUtil.castNonNull;
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation; import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
import static org.hibernate.jpamodelgen.util.TypeUtils.determineAccessTypeForHierarchy; import static org.hibernate.jpamodelgen.util.TypeUtils.determineAccessTypeForHierarchy;
import static org.hibernate.jpamodelgen.util.TypeUtils.determineAnnotationSpecifiedAccessType; import static org.hibernate.jpamodelgen.util.TypeUtils.determineAnnotationSpecifiedAccessType;
import static org.hibernate.jpamodelgen.util.TypeUtils.findMappedSuperClass;
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationMirror; import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationMirror;
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationValue; import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationValue;
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationValueRef; import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationValueRef;
@ -113,6 +114,8 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private final Context context; private final Context context;
private final boolean managed; private final boolean managed;
private boolean dataRepository; private boolean dataRepository;
private String qualifiedName;
private final boolean jakartaDataStaticModel;
private AccessTypeInformation entityAccessTypeInfo; private AccessTypeInformation entityAccessTypeInfo;
@ -148,16 +151,25 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private final Map<String,String> memberTypes = new HashMap<>(); private final Map<String,String> memberTypes = new HashMap<>();
public AnnotationMetaEntity(TypeElement element, Context context, boolean managed) { public AnnotationMetaEntity(TypeElement element, Context context, boolean managed, boolean jakartaData) {
this.element = element; this.element = element;
this.context = context; this.context = context;
this.managed = managed; this.managed = managed;
this.members = new HashMap<>(); this.members = new HashMap<>();
this.importContext = new ImportContextImpl( getPackageName( context, element ) ); this.importContext = new ImportContextImpl( getPackageName( context, element ) );
jakartaDataStaticModel = jakartaData;
} }
public static AnnotationMetaEntity create(TypeElement element, Context context, boolean lazilyInitialised, boolean managed) { public static AnnotationMetaEntity create(
final AnnotationMetaEntity annotationMetaEntity = new AnnotationMetaEntity( element, context, managed ); TypeElement element, Context context,
boolean lazilyInitialised, boolean managed) {
return create( element,context, lazilyInitialised, managed, false );
}
public static AnnotationMetaEntity create(
TypeElement element, Context context,
boolean lazilyInitialised, boolean managed, boolean jakartaData) {
final AnnotationMetaEntity annotationMetaEntity = new AnnotationMetaEntity( element, context, managed, jakartaData );
if ( !lazilyInitialised ) { if ( !lazilyInitialised ) {
annotationMetaEntity.init(); annotationMetaEntity.init();
} }
@ -182,6 +194,11 @@ public class AnnotationMetaEntity extends AnnotationMeta {
return repository; return repository;
} }
@Override
public boolean isJakartaDataStyle() {
return jakartaDataStaticModel;
}
@Override @Override
public final String getSimpleName() { public final String getSimpleName() {
return element.getSimpleName().toString(); return element.getSimpleName().toString();
@ -189,7 +206,15 @@ public class AnnotationMetaEntity extends AnnotationMeta {
@Override @Override
public final String getQualifiedName() { public final String getQualifiedName() {
return element.getQualifiedName().toString(); if ( qualifiedName == null ) {
qualifiedName = element.getQualifiedName().toString();
}
return qualifiedName;
}
@Override
public @Nullable String getSupertypeName() {
return findMappedSuperClass( this, context );
} }
@Override @Override
@ -498,13 +523,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private void addPersistentMembers(List<? extends Element> membersOfClass, AccessType membersKind) { private void addPersistentMembers(List<? extends Element> membersOfClass, AccessType membersKind) {
for ( Element memberOfClass : membersOfClass ) { for ( Element memberOfClass : membersOfClass ) {
if ( isPersistent( memberOfClass, membersKind ) ) { if ( isPersistent( memberOfClass, membersKind ) ) {
final AnnotationMetaAttribute jpaMetaAttribute = if ( jakartaDataStaticModel ) {
memberOfClass.asType()
.accept( new MetaAttributeGenerationVisitor( this, context ), memberOfClass );
if ( jpaMetaAttribute != null ) {
members.put( jpaMetaAttribute.getPropertyName(), jpaMetaAttribute );
}
if ( context.generateJakartaDataStaticMetamodel() ) {
final DataAnnotationMetaAttribute dataMetaAttribute = final DataAnnotationMetaAttribute dataMetaAttribute =
memberOfClass.asType() memberOfClass.asType()
.accept( new DataMetaAttributeGenerationVisitor( this, context ), memberOfClass ); .accept( new DataMetaAttributeGenerationVisitor( this, context ), memberOfClass );
@ -512,6 +531,14 @@ public class AnnotationMetaEntity extends AnnotationMeta {
members.put( '_' + dataMetaAttribute.getPropertyName(), dataMetaAttribute ); members.put( '_' + dataMetaAttribute.getPropertyName(), dataMetaAttribute );
} }
} }
else {
final AnnotationMetaAttribute jpaMetaAttribute =
memberOfClass.asType()
.accept( new MetaAttributeGenerationVisitor( this, context ), memberOfClass );
if ( jpaMetaAttribute != null ) {
members.put( jpaMetaAttribute.getPropertyName(), jpaMetaAttribute );
}
}
} }
} }
} }

View File

@ -41,7 +41,6 @@ public class AnnotationMetaMap extends AnnotationMetaCollection {
.append( parent.importType( getTypeDeclaration() ) ) .append( parent.importType( getTypeDeclaration() ) )
.append("> ") .append("> ")
.append( getPropertyName() ) .append( getPropertyName() )
.append( parent.getContext().useJakartaDataStyle() ? "_" : "" )
.append(";") .append(";")
.toString(); .toString();
} }

View File

@ -67,6 +67,11 @@ public class AnnotationMetaPackage extends AnnotationMeta {
return element.getQualifiedName().toString(); return element.getQualifiedName().toString();
} }
@Override
public @Nullable String getSupertypeName() {
throw new UnsupportedOperationException();
}
@Override @Override
public final String getPackageName() { public final String getPackageName() {
return getPackageName( context, element ); return getPackageName( context, element );
@ -154,4 +159,9 @@ public class AnnotationMetaPackage extends AnnotationMeta {
public String scope() { public String scope() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public boolean isJakartaDataStyle() {
return false;
}
} }

View File

@ -60,7 +60,6 @@ public class DataAnnotationMetaAttribute implements MetaAttribute {
.append( "<" ) .append( "<" )
.append( className ) .append( className )
.append( "> " ) .append( "> " )
.append( parent.getContext().useJakartaDataStyle() ? "" : "_" )
.append( getPropertyName() ) .append( getPropertyName() )
.append(" = ") .append(" = ")
.append( getMetaImpl(className, memberName) ) .append( getMetaImpl(className, memberName) )

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.jpamodelgen.model; package org.hibernate.jpamodelgen.model;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.jpamodelgen.Context; import org.hibernate.jpamodelgen.Context;
import java.util.List; import java.util.List;
@ -19,6 +20,8 @@ public interface Metamodel extends ImportContext {
String getQualifiedName(); String getQualifiedName();
@Nullable String getSupertypeName();
String getPackageName(); String getPackageName();
List<MetaAttribute> getMembers(); List<MetaAttribute> getMembers();
@ -40,4 +43,6 @@ public interface Metamodel extends ImportContext {
boolean isInjectable(); boolean isInjectable();
String scope(); String scope();
boolean isJakartaDataStyle();
} }

View File

@ -10,6 +10,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.jpamodelgen.Context; import org.hibernate.jpamodelgen.Context;
import org.hibernate.jpamodelgen.MetaModelGenerationException; import org.hibernate.jpamodelgen.MetaModelGenerationException;
import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity; import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity;
import org.hibernate.jpamodelgen.model.Metamodel;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.AnnotationValue;
@ -610,6 +611,55 @@ public final class TypeUtils {
} }
} }
public static @Nullable String findMappedSuperClass(Metamodel entity, Context context) {
Element element = entity.getElement();
if ( element instanceof TypeElement ) {
TypeMirror superClass = ((TypeElement) element).getSuperclass();
//superclass of Object is of NoType which returns some other kind
while ( superClass.getKind() == TypeKind.DECLARED ) {
final Element superClassElement = ( (DeclaredType) superClass ).asElement();
String superClassName = ( (TypeElement) superClassElement ).getQualifiedName().toString();
if ( extendsSuperMetaModel( superClassElement, entity.isMetaComplete(), context ) ) {
return superClassName;
}
superClass = ( (TypeElement) superClassElement ).getSuperclass();
}
}
return null;
}
/**
* Checks whether this metamodel class needs to extend another metamodel class.
* This method checks whether the processor has generated a metamodel class for the super class, but it also
* allows for the possibility that the metamodel class was generated in a previous compilation. (It could be
* part of a separate jar. See also METAGEN-35.)
*
* @param superClassElement the super class element
* @param entityMetaComplete flag indicating if the entity for which the metamodel should be generated is
* metamodel complete. If so we cannot use reflection to decide whether we have to add the extends clause
* @param context the execution context
*
* @return {@code true} in case there is super class metamodel to extend from {@code false} otherwise.
*/
private static boolean extendsSuperMetaModel(Element superClassElement, boolean entityMetaComplete, Context context) {
// if we processed the superclass in the same run we definitely need to extend
String superClassName = ( (TypeElement) superClassElement ).getQualifiedName().toString();
if ( context.containsMetaEntity( superClassName )
|| context.containsMetaEmbeddable( superClassName ) ) {
return true;
}
// to allow for the case that the metamodel class for the super entity is for example contained in another
// jar file we use reflection. However, we need to consider the fact that there is xml configuration
// and annotations should be ignored
if ( !entityMetaComplete
&& containsAnnotation( superClassElement, Constants.ENTITY, Constants.MAPPED_SUPERCLASS ) ) {
return true;
}
return false;
}
static class EmbeddedAttributeVisitor extends SimpleTypeVisitor8<@Nullable String, Element> { static class EmbeddedAttributeVisitor extends SimpleTypeVisitor8<@Nullable String, Element> {
private final Context context; private final Context context;

View File

@ -47,6 +47,8 @@ import org.hibernate.jpamodelgen.xml.jaxb.OneToOne;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import static org.hibernate.jpamodelgen.util.StringUtil.determineFullyQualifiedClassName; import static org.hibernate.jpamodelgen.util.StringUtil.determineFullyQualifiedClassName;
import static org.hibernate.jpamodelgen.util.TypeUtils.extractClosestRealTypeAsString;
import static org.hibernate.jpamodelgen.util.TypeUtils.findMappedSuperClass;
import static org.hibernate.jpamodelgen.util.TypeUtils.getElementKindForAccessType; import static org.hibernate.jpamodelgen.util.TypeUtils.getElementKindForAccessType;
import static org.hibernate.jpamodelgen.xml.jaxb.AccessType.*; import static org.hibernate.jpamodelgen.xml.jaxb.AccessType.*;
@ -132,7 +134,7 @@ public class XmlMetaEntity implements Metamodel {
this.isMetaComplete = initIsMetaComplete( context, metaComplete ); this.isMetaComplete = initIsMetaComplete( context, metaComplete );
} }
private final void init() { private void init() {
context.logMessage( Diagnostic.Kind.OTHER, "Initializing type " + getQualifiedName() + "." ); context.logMessage( Diagnostic.Kind.OTHER, "Initializing type " + getQualifiedName() + "." );
this.accessTypeInfo = NullnessUtil.castNonNull( context.getAccessTypeInfo( getQualifiedName() ) ); this.accessTypeInfo = NullnessUtil.castNonNull( context.getAccessTypeInfo( getQualifiedName() ) );
@ -158,6 +160,11 @@ public class XmlMetaEntity implements Metamodel {
return packageName; return packageName;
} }
@Override
public @Nullable String getSupertypeName() {
return findMappedSuperClass( this, context );
}
public List<MetaAttribute> getMembers() { public List<MetaAttribute> getMembers() {
if ( !initialized ) { if ( !initialized ) {
init(); init();
@ -265,12 +272,12 @@ public class XmlMetaEntity implements Metamodel {
private void determineTargetType(DeclaredType type, String propertyName, String explicitTargetEntity, @Nullable String[] types) { private void determineTargetType(DeclaredType type, String propertyName, String explicitTargetEntity, @Nullable String[] types) {
List<? extends TypeMirror> typeArguments = type.getTypeArguments(); List<? extends TypeMirror> typeArguments = type.getTypeArguments();
if ( typeArguments.size() == 0 && explicitTargetEntity == null ) { if ( typeArguments.isEmpty() && explicitTargetEntity == null ) {
throw new MetaModelGenerationException( "Unable to determine target entity type for " + clazzName + "." + propertyName + "." ); throw new MetaModelGenerationException( "Unable to determine target entity type for " + clazzName + "." + propertyName + "." );
} }
if ( explicitTargetEntity == null ) { if ( explicitTargetEntity == null ) {
types[0] = TypeUtils.extractClosestRealTypeAsString( typeArguments.get( 0 ), context ); types[0] = extractClosestRealTypeAsString( typeArguments.get( 0 ), context );
} }
else { else {
types[0] = explicitTargetEntity; types[0] = explicitTargetEntity;
@ -632,4 +639,9 @@ public class XmlMetaEntity implements Metamodel {
public String scope() { public String scope() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public boolean isJakartaDataStyle() {
return false;
}
} }