HHH-17772 rework processor bookkeeping

This commit is contained in:
Gavin King 2024-02-24 20:22:24 +01:00
parent 67a5590316
commit 582d736062
3 changed files with 155 additions and 81 deletions

View File

@ -50,6 +50,17 @@ public final class Context {
*/
private final Map<String, Metamodel> metaEmbeddables = new HashMap<>();
/**
* Used for keeping track of parsed entities and mapped super classes (XML + annotations).
*/
private final Map<String, Metamodel> dataMetaEntities = new HashMap<>();
/**
* Used for keeping track of parsed embeddable entities. These entities have to be kept separate since
* they are lazily initialized.
*/
private final Map<String, Metamodel> dataMetaEmbeddables = new HashMap<>();
private final Map<String, Metamodel> metaAuxiliaries = new HashMap<>();
private final Map<String, AccessTypeInformation> accessTypeInformation = new HashMap<>();
@ -78,7 +89,7 @@ public final class Context {
private boolean generateJakartaDataStaticMetamodel;
// keep track of all classes for which model have been generated
private final Collection<String> generatedModelClasses = new HashSet<>();
private final Set<Metamodel> generatedModelClasses = new HashSet<>();
// keep track of which named queries have been checked
private final Set<String> checkedNamedQueries = new HashSet<>();
@ -233,6 +244,38 @@ public Collection<Metamodel> getMetaEmbeddables() {
return metaEmbeddables.values();
}
public boolean containsDataMetaEntity(String qualifiedName) {
return dataMetaEntities.containsKey( qualifiedName );
}
public @Nullable Metamodel getDataMetaEntity(String qualifiedName) {
return dataMetaEntities.get( qualifiedName );
}
public Collection<Metamodel> getDataMetaEntities() {
return dataMetaEntities.values();
}
public void addDataMetaEntity(String qualifiedName, Metamodel metaEntity) {
dataMetaEntities.put( qualifiedName, metaEntity );
}
public boolean containsDataMetaEmbeddable(String qualifiedName) {
return dataMetaEmbeddables.containsKey( qualifiedName );
}
public @Nullable Metamodel getDataMetaEmbeddable(String qualifiedName) {
return dataMetaEmbeddables.get( qualifiedName );
}
public void addDataMetaEmbeddable(String qualifiedName, Metamodel metaEntity) {
dataMetaEmbeddables.put( qualifiedName, metaEntity );
}
public Collection<Metamodel> getDataMetaEmbeddables() {
return dataMetaEmbeddables.values();
}
public @Nullable Metamodel getMetaAuxiliary(String qualifiedName) {
return metaAuxiliaries.get( qualifiedName );
}
@ -258,12 +301,12 @@ public TypeElement getTypeElementForFullyQualifiedName(String qualifiedName) {
return elementUtils.getTypeElement( qualifiedName );
}
void markGenerated(String name) {
generatedModelClasses.add( name );
void markGenerated(Metamodel metamodel) {
generatedModelClasses.add( metamodel );
}
boolean isAlreadyGenerated(String name) {
return generatedModelClasses.contains( name );
boolean isAlreadyGenerated(Metamodel metamodel) {
return generatedModelClasses.contains( metamodel );
}
public Set<CharSequence> getElementsToRedo() {

View File

@ -6,11 +6,12 @@
*/
package org.hibernate.jpamodelgen;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity;
import org.hibernate.jpamodelgen.annotation.AnnotationMetaPackage;
import org.hibernate.jpamodelgen.model.Metamodel;
import org.hibernate.jpamodelgen.xml.JpaDescriptorParser;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
@ -24,20 +25,29 @@
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity;
import org.hibernate.jpamodelgen.annotation.AnnotationMetaPackage;
import org.hibernate.jpamodelgen.model.Metamodel;
import org.hibernate.jpamodelgen.xml.JpaDescriptorParser;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static java.lang.Boolean.parseBoolean;
import static javax.lang.model.util.ElementFilter.fieldsIn;
import static javax.lang.model.util.ElementFilter.methodsIn;
import static org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.ADD_GENERATED_ANNOTATION;
import static org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.ADD_GENERATION_DATE;
import static org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.ADD_SUPPRESS_WARNINGS_ANNOTATION;
import static org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.DEBUG_OPTION;
import static org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.FULLY_ANNOTATION_CONFIGURED_OPTION;
import static org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.LAZY_XML_PARSING;
import static org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.ORM_XML_OPTION;
import static org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.PERSISTENCE_XML_OPTION;
import static org.hibernate.jpamodelgen.util.Constants.*;
import static org.hibernate.jpamodelgen.util.TypeUtils.*;
import static org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.*;
import static org.hibernate.jpamodelgen.util.TypeUtils.containsAnnotation;
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationMirror;
import static org.hibernate.jpamodelgen.util.TypeUtils.getAnnotationValue;
import static org.hibernate.jpamodelgen.util.TypeUtils.hasAnnotation;
import static org.hibernate.jpamodelgen.util.TypeUtils.isClassOrRecordType;
/**
* Main annotation processor.
@ -281,51 +291,62 @@ else if ( element instanceof TypeElement ) {
private void createMetaModelClasses() {
for ( Metamodel aux : context.getMetaAuxiliaries() ) {
final String key = aux.getQualifiedName();
if ( !context.isAlreadyGenerated(key) ) {
context.logMessage( Diagnostic.Kind.OTHER, "Writing metamodel for auxiliary '" + aux + "'" );
if ( !context.isAlreadyGenerated(aux) ) {
context.logMessage( Diagnostic.Kind.OTHER,
"Writing metamodel for auxiliary '" + aux + "'" );
ClassWriter.writeFile( aux, context );
context.markGenerated(key);
context.markGenerated(aux);
}
}
for ( Metamodel entity : context.getMetaEntities() ) {
final String key = entity.isJakartaDataStyle()
? '_' + entity.getQualifiedName()
: entity.getQualifiedName();
if ( !context.isAlreadyGenerated(key) ) {
context.logMessage( Diagnostic.Kind.OTHER, "Writing metamodel for entity '" + entity + "'" );
if ( !context.isAlreadyGenerated(entity) ) {
context.logMessage( Diagnostic.Kind.OTHER,
"Writing Jakarta Persistence metamodel for entity '" + entity + "'" );
ClassWriter.writeFile( entity, context );
context.markGenerated(key);
context.markGenerated(entity);
}
}
// we cannot process the delayed entities in any order. There might be dependencies between them.
// we need to process the top level entities first
final Collection<Metamodel> toProcessEntities = context.getMetaEmbeddables();
while ( !toProcessEntities.isEmpty() ) {
final Set<Metamodel> processedEntities = new HashSet<>();
int toProcessCountBeforeLoop = toProcessEntities.size();
for ( Metamodel entity : toProcessEntities ) {
for ( Metamodel entity : context.getDataMetaEntities() ) {
if ( !context.isAlreadyGenerated(entity) ) {
context.logMessage( Diagnostic.Kind.OTHER,
"Writing Jakarta Data metamodel for entity '" + entity + "'" );
ClassWriter.writeFile( entity, context );
context.markGenerated(entity);
}
}
processEmbeddables( context.getMetaEmbeddables() );
processEmbeddables( context.getDataMetaEmbeddables() );
}
/**
* We cannot process the delayed classes in any order.
* There might be dependencies between them.
* We need to process the toplevel classes first.
*/
private void processEmbeddables(Collection<Metamodel> models) {
while ( !models.isEmpty() ) {
final Set<Metamodel> processed = new HashSet<>();
final int toProcessCountBeforeLoop = models.size();
for ( Metamodel metamodel : models ) {
// see METAGEN-36
final String key = entity.isJakartaDataStyle()
? '_' + entity.getQualifiedName()
: entity.getQualifiedName();
if ( context.isAlreadyGenerated(key) ) {
processedEntities.add( entity );
if ( context.isAlreadyGenerated(metamodel) ) {
processed.add( metamodel );
}
else if ( !modelGenerationNeedsToBeDeferred( toProcessEntities, entity ) ) {
else if ( !modelGenerationNeedsToBeDeferred(models, metamodel ) ) {
context.logMessage(
Diagnostic.Kind.OTHER,
"Writing meta model for embeddable/mapped superclass " + entity
"Writing metamodel for embeddable " + metamodel
);
ClassWriter.writeFile( entity, context );
context.markGenerated(key);
processedEntities.add( entity );
ClassWriter.writeFile( metamodel, context );
context.markGenerated(metamodel);
processed.add( metamodel );
}
}
toProcessEntities.removeAll( processedEntities );
if ( toProcessEntities.size() >= toProcessCountBeforeLoop ) {
models.removeAll( processed );
if ( models.size() >= toProcessCountBeforeLoop ) {
context.logMessage(
Diagnostic.Kind.ERROR,
"Potential endless loop in generation of entities."
@ -398,11 +419,11 @@ private boolean hasAuxiliaryAnnotations(Element element) {
private void handleRootElementAnnotationMirrors(final Element element) {
if ( isClassOrRecordType( element ) ) {
for ( AnnotationMirror mirror : element.getAnnotationMirrors() ) {
if ( hasAnnotation( element, ENTITY, MAPPED_SUPERCLASS, EMBEDDABLE ) ) {
final TypeElement typeElement = (TypeElement) element;
final String qualifiedName = typeElement.getQualifiedName().toString();
final Metamodel alreadyExistingMetaEntity =
tryGettingExistingEntityFromContext( mirror, qualifiedName );
tryGettingExistingEntityFromContext( typeElement, qualifiedName );
if ( alreadyExistingMetaEntity != null && alreadyExistingMetaEntity.isMetaComplete() ) {
context.logMessage(
Diagnostic.Kind.OTHER,
@ -418,7 +439,7 @@ private void handleRootElementAnnotationMirrors(final Element element) {
if ( alreadyExistingMetaEntity != null ) {
metaEntity.mergeInMembers( alreadyExistingMetaEntity );
}
addMetaEntityToContext( mirror, metaEntity );
addMetamodelToContext( typeElement, metaEntity );
if ( context.generateJakartaDataStaticMetamodel()
// Don't generate a Jakarta Data metamodel
// if this entity was partially mapped in XML
@ -427,11 +448,11 @@ private void handleRootElementAnnotationMirrors(final Element element) {
AnnotationMetaEntity.create( typeElement, context,
requiresLazyMemberInitialization, true, true );
// final Metamodel alreadyExistingDataMetaEntity =
// tryGettingExistingEntityFromContext( mirror, '_' + qualifiedName );
// tryGettingExistingDataEntityFromContext( mirror, '_' + qualifiedName );
// if ( alreadyExistingDataMetaEntity != null ) {
// dataMetaEntity.mergeInMembers( alreadyExistingDataMetaEntity );
// }
addMetaEntityToContext( mirror, dataMetaEntity );
addDataMetamodelToContext( typeElement, dataMetaEntity );
}
}
}
@ -452,29 +473,39 @@ else if ( element instanceof PackageElement ) {
//TODO: handle PackageElement
}
private @Nullable Metamodel tryGettingExistingEntityFromContext(AnnotationMirror mirror, String qualifiedName) {
if ( isAnnotationMirrorOfType( mirror, ENTITY )
|| isAnnotationMirrorOfType( mirror, MAPPED_SUPERCLASS ) ) {
private @Nullable Metamodel tryGettingExistingEntityFromContext(TypeElement typeElement, String qualifiedName) {
if ( hasAnnotation( typeElement, ENTITY, MAPPED_SUPERCLASS ) ) {
return context.getMetaEntity( qualifiedName );
}
else if ( isAnnotationMirrorOfType( mirror, EMBEDDABLE ) ) {
else if ( hasAnnotation( typeElement, EMBEDDABLE ) ) {
return context.getMetaEmbeddable( qualifiedName );
}
return null;
}
private void addMetaEntityToContext(AnnotationMirror mirror, AnnotationMetaEntity metaEntity) {
final String key = metaEntity.isJakartaDataStyle()
? '_' + metaEntity.getQualifiedName()
: metaEntity.getQualifiedName();
if ( isAnnotationMirrorOfType( mirror, ENTITY ) ) {
context.addMetaEntity( key, metaEntity );
private void addMetamodelToContext(TypeElement typeElement, AnnotationMetaEntity entity) {
final String key = entity.getQualifiedName();
if ( hasAnnotation( typeElement, ENTITY ) ) {
context.addMetaEntity( key, entity );
}
else if ( isAnnotationMirrorOfType( mirror, MAPPED_SUPERCLASS ) ) {
context.addMetaEntity( key, metaEntity );
else if ( hasAnnotation( typeElement, MAPPED_SUPERCLASS ) ) {
context.addMetaEntity( key, entity );
}
else if ( isAnnotationMirrorOfType( mirror, EMBEDDABLE ) ) {
context.addMetaEmbeddable( key, metaEntity );
else if ( hasAnnotation( typeElement, EMBEDDABLE ) ) {
context.addMetaEmbeddable( key, entity );
}
}
private void addDataMetamodelToContext(TypeElement typeElement, AnnotationMetaEntity entity) {
final String key = entity.getQualifiedName();
if ( hasAnnotation( typeElement, ENTITY ) ) {
context.addDataMetaEntity( key, entity );
}
else if ( hasAnnotation( typeElement, MAPPED_SUPERCLASS ) ) {
context.addDataMetaEntity( key, entity );
}
else if ( hasAnnotation( typeElement, EMBEDDABLE ) ) {
context.addDataMetaEmbeddable( key, entity );
}
}

View File

@ -113,7 +113,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
private final Map<String, MetaAttribute> members;
private final Context context;
private final boolean managed;
private boolean dataRepository;
private boolean jakartaDataRepository;
private String qualifiedName;
private final boolean jakartaDataStaticModel;
@ -306,7 +306,7 @@ public boolean isInjectable() {
@Override
public String scope() {
if (dataRepository) {
if (jakartaDataRepository) {
return context.addTransactionScopedAnnotation()
? "javax.transaction.TransactionScoped"
: "jakarta.enterprise.context.RequestScoped";
@ -351,18 +351,18 @@ else if ( containsAnnotation( method, JD_INSERT, JD_UPDATE, JD_DELETE, JD_SAVE )
}
}
dataRepository = hasAnnotation( element, JD_REPOSITORY );
jakartaDataRepository = hasAnnotation( element, JD_REPOSITORY );
findSessionGetter( element );
if ( !repository && dataRepository) {
if ( !repository && jakartaDataRepository) {
repository = true;
sessionType = HIB_STATELESS_SESSION;
addDaoConstructor( null );
}
if ( dataRepository ) {
if ( jakartaDataRepository ) {
addDefaultConstructor();
}
if ( managed ) {
if ( managed && !jakartaDataStaticModel ) {
putMember( "class", new AnnotationMetaType(this) );
}
@ -452,7 +452,7 @@ private String addDaoConstructor(@Nullable ExecutableElement method) {
context.addInjectAnnotation(),
context.addNonnullAnnotation(),
method != null,
dataRepository
jakartaDataRepository
)
);
return sessionType;
@ -822,7 +822,7 @@ else if ( !context.getTypeUtils().isSameType( typeArgument, entity.asType() ) )
enabledFetchProfiles( method ),
orderByList( method, entity ),
context.addNonnullAnnotation(),
dataRepository
jakartaDataRepository
)
);
}
@ -976,7 +976,7 @@ && matchesNaturalKey( method, entity ) ) {
sessionType[1],
enabledFetchProfiles( method ),
context.addNonnullAnnotation(),
dataRepository
jakartaDataRepository
)
);
}
@ -996,7 +996,7 @@ && matchesNaturalKey( method, entity ) ) {
enabledFetchProfiles( method ),
orderByList( method, entity ),
context.addNonnullAnnotation(),
dataRepository
jakartaDataRepository
)
);
}
@ -1029,7 +1029,7 @@ private void createSingleParameterFinder(ExecutableElement method, TypeMirror re
sessionType[1],
profiles,
context.addNonnullAnnotation(),
dataRepository
jakartaDataRepository
)
);
break;
@ -1047,7 +1047,7 @@ private void createSingleParameterFinder(ExecutableElement method, TypeMirror re
sessionType[1],
profiles,
context.addNonnullAnnotation(),
dataRepository
jakartaDataRepository
)
);
break;
@ -1067,7 +1067,7 @@ private void createSingleParameterFinder(ExecutableElement method, TypeMirror re
profiles,
orderByList( method, entity ),
context.addNonnullAnnotation(),
dataRepository
jakartaDataRepository
)
);
break;
@ -1302,7 +1302,7 @@ private void addQueryMethod(
sessionType[0],
sessionType[1],
context.addNonnullAnnotation(),
dataRepository
jakartaDataRepository
);
putMember( attribute.getPropertyName() + paramTypes, attribute );