HHH-18863 allow index creation to be disabled in processor

also cache enum results read from index
This commit is contained in:
Gavin King 2024-12-05 11:23:40 +01:00
parent 3cf2bc88e0
commit 83110b4638
5 changed files with 113 additions and 69 deletions

View File

@ -107,6 +107,8 @@ public final class Context {
private String[] includes = {"*"};
private String[] excludes = {};
private boolean indexing = true;
private final Map<String, String> entityNameMappings = new HashMap<>();
private final Map<String, Set<String>> enumTypesByValue = new HashMap<>();
@ -551,4 +553,12 @@ public final class Context {
}
return null;
}
public void setIndexing(boolean index) {
this.indexing = index;
}
public boolean isIndexing() {
return indexing;
}
}

View File

@ -54,6 +54,7 @@ import static org.hibernate.processor.HibernateProcessor.DEBUG_OPTION;
import static org.hibernate.processor.HibernateProcessor.EXCLUDE;
import static org.hibernate.processor.HibernateProcessor.FULLY_ANNOTATION_CONFIGURED_OPTION;
import static org.hibernate.processor.HibernateProcessor.INCLUDE;
import static org.hibernate.processor.HibernateProcessor.INDEX;
import static org.hibernate.processor.HibernateProcessor.LAZY_XML_PARSING;
import static org.hibernate.processor.HibernateProcessor.ORM_XML_OPTION;
import static org.hibernate.processor.HibernateProcessor.PERSISTENCE_XML_OPTION;
@ -120,7 +121,8 @@ import static org.hibernate.processor.util.TypeUtils.isMemberType;
ADD_GENERATED_ANNOTATION,
ADD_SUPPRESS_WARNINGS_ANNOTATION,
SUPPRESS_JAKARTA_DATA_METAMODEL,
INCLUDE, EXCLUDE
INCLUDE, EXCLUDE,
INDEX
})
public class HibernateProcessor extends AbstractProcessor {
@ -190,6 +192,13 @@ public class HibernateProcessor extends AbstractProcessor {
*/
public static final String EXCLUDE = "exclude";
/**
* Option to suppress creation of a filesystem-based index of entity
* types and enums for use by the query validator. By default, and
* index is created.
*/
public static final String INDEX = "index";
private static final boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = false;
public static final String ENTITY_INDEX = "entity.index";
@ -282,6 +291,8 @@ public class HibernateProcessor extends AbstractProcessor {
context.setInclude( options.getOrDefault( INCLUDE, "*" ) );
context.setExclude( options.getOrDefault( EXCLUDE, "" ) );
context.setIndexing( parseBoolean( options.get( INDEX ) ) );
return parseBoolean( options.get( FULLY_ANNOTATION_CONFIGURED_OPTION ) );
}
@ -773,43 +784,45 @@ public class HibernateProcessor extends AbstractProcessor {
}
private void writeIndex() {
final ProcessingEnvironment processingEnvironment = context.getProcessingEnvironment();
final Elements elementUtils = processingEnvironment.getElementUtils();
context.getEntityNameMappings().forEach((entityName, className) -> {
try (Writer writer = processingEnvironment.getFiler()
.createResource(
StandardLocation.SOURCE_OUTPUT,
ENTITY_INDEX,
entityName,
elementUtils.getTypeElement( className )
)
.openWriter()) {
writer.append(className);
}
catch (IOException e) {
processingEnvironment.getMessager()
.printMessage(Diagnostic.Kind.WARNING,
"could not write entity index " + e.getMessage());
}
});
context.getEnumTypesByValue().forEach((valueName, enumTypeNames) -> {
try (Writer writer = processingEnvironment.getFiler()
.createResource(
StandardLocation.SOURCE_OUTPUT,
ENTITY_INDEX,
'.' + valueName,
elementUtils.getTypeElement( enumTypeNames.iterator().next() )
)
.openWriter()) {
for (String enumTypeName : enumTypeNames) {
writer.append(enumTypeName).append(" ");
if ( context.isIndexing() ) {
final ProcessingEnvironment processingEnvironment = context.getProcessingEnvironment();
final Elements elementUtils = processingEnvironment.getElementUtils();
context.getEntityNameMappings().forEach( (entityName, className) -> {
try (Writer writer = processingEnvironment.getFiler()
.createResource(
StandardLocation.SOURCE_OUTPUT,
ENTITY_INDEX,
entityName,
elementUtils.getTypeElement( className )
)
.openWriter()) {
writer.append( className );
}
}
catch (IOException e) {
processingEnvironment.getMessager()
.printMessage(Diagnostic.Kind.WARNING,
"could not write entity index " + e.getMessage());
}
});
catch (IOException e) {
processingEnvironment.getMessager()
.printMessage( Diagnostic.Kind.WARNING,
"could not write entity index " + e.getMessage() );
}
} );
context.getEnumTypesByValue().forEach( (valueName, enumTypeNames) -> {
try (Writer writer = processingEnvironment.getFiler()
.createResource(
StandardLocation.SOURCE_OUTPUT,
ENTITY_INDEX,
'.' + valueName,
elementUtils.getTypeElement( enumTypeNames.iterator().next() )
)
.openWriter()) {
for ( String enumTypeName : enumTypeNames ) {
writer.append( enumTypeName ).append( " " );
}
}
catch (IOException e) {
processingEnvironment.getMessager()
.printMessage( Diagnostic.Kind.WARNING,
"could not write entity index " + e.getMessage() );
}
} );
}
}
}

View File

@ -104,7 +104,8 @@ public abstract class AnnotationMeta implements Metamodel {
new WarningErrorHandler( context, getElement(), mirror, value, hql,
reportErrors, checkHql ),
ProcessorSessionFactory.create( context.getProcessingEnvironment(),
context.getEntityNameMappings(), context.getEnumTypesByValue() )
context.getEntityNameMappings(), context.getEnumTypesByValue(),
context.isIndexing() )
);
if ( !isJakartaDataStyle()
&& statement instanceof SqmSelectStatement<?> selectStatement ) {

View File

@ -2451,7 +2451,7 @@ public class AnnotationMetaEntity extends AnnotationMeta {
true,
new ErrorHandler( context, isLocal(method) ? method : element, mirror, value, hql ),
ProcessorSessionFactory.create( context.getProcessingEnvironment(),
context.getEntityNameMappings(), context.getEnumTypesByValue() )
context.getEntityNameMappings(), context.getEnumTypesByValue(), context.isIndexing() )
);
if ( statement != null ) {
if ( statement instanceof SqmSelectStatement ) {

View File

@ -72,8 +72,9 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
public static MockSessionFactory create(
ProcessingEnvironment environment,
Map<String,String> entityNameMappings,
Map<String, Set<String>> enumTypesByValue) {
return instance.make(environment, entityNameMappings, enumTypesByValue);
Map<String, Set<String>> enumTypesByValue,
boolean indexing) {
return instance.make(environment, indexing, entityNameMappings, enumTypesByValue);
}
static final Mocker<ProcessorSessionFactory> instance = Mocker.variadic(ProcessorSessionFactory.class);
@ -88,16 +89,19 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
private final Elements elementUtil;
private final Types typeUtil;
private final Filer filer;
private final boolean indexing;
private final Map<String, String> entityNameMappings;
private final Map<String, Set<String>> enumTypesByValue;
public ProcessorSessionFactory(
ProcessingEnvironment processingEnvironment,
boolean indexing,
Map<String,String> entityNameMappings,
Map<String, Set<String>> enumTypesByValue) {
elementUtil = processingEnvironment.getElementUtils();
typeUtil = processingEnvironment.getTypeUtils();
filer = processingEnvironment.getFiler();
this.indexing = indexing;
this.entityNameMappings = entityNameMappings;
this.enumTypesByValue = enumTypesByValue;
}
@ -220,15 +224,25 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
if ( result != null ) {
return result;
}
try (Reader reader = filer.getResource(StandardLocation.SOURCE_OUTPUT, ENTITY_INDEX, value)
.openReader(true); BufferedReader buffered = new BufferedReader(reader) ) {
return Set.of(split(" ", buffered.readLine()));
if ( indexing ) {
final Set<String> indexed = getIndexedEnumTypesByValue(value);
enumTypesByValue.put(value, indexed);
return indexed;
}
//TODO: else do a full scan like in findEntityByUnqualifiedName()
return null;
}
private @Nullable Set<String> getIndexedEnumTypesByValue(String value) {
try (Reader reader = filer.getResource( StandardLocation.SOURCE_OUTPUT, ENTITY_INDEX, value )
.openReader( true ); BufferedReader buffered = new BufferedReader( reader )) {
return Set.of( split( " ", buffered.readLine() ) );
}
catch (IOException ignore) {
}
try (Reader reader = filer.getResource(StandardLocation.CLASS_PATH, ENTITY_INDEX, '.' + value)
.openReader(true); BufferedReader buffered = new BufferedReader(reader) ) {
return Set.of(split(" ", buffered.readLine()));
try (Reader reader = filer.getResource( StandardLocation.CLASS_PATH, ENTITY_INDEX, '.' + value )
.openReader( true ); BufferedReader buffered = new BufferedReader( reader )) {
return Set.of( split( " ", buffered.readLine() ) );
}
catch (IOException ignore) {
}
@ -503,27 +517,13 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
if ( cached != null ) {
return cached;
}
final String qualifiedName = entityNameMappings.get(entityName);
if ( qualifiedName != null ) {
final TypeElement result = elementUtil.getTypeElement(qualifiedName);
entityCache.put(entityName, result);
return result;
}
try (Reader reader = filer.getResource( StandardLocation.SOURCE_OUTPUT, ENTITY_INDEX, entityName)
.openReader(true); BufferedReader buffered = new BufferedReader(reader) ) {
final TypeElement result = elementUtil.getTypeElement(buffered.readLine());
entityCache.put(entityName, result);
return result;
}
catch (IOException ignore) {
}
try (Reader reader = filer.getResource(StandardLocation.CLASS_PATH, ENTITY_INDEX, entityName)
.openReader(true); BufferedReader buffered = new BufferedReader(reader) ) {
final TypeElement result = elementUtil.getTypeElement(buffered.readLine());
entityCache.put(entityName, result);
return result;
}
catch (IOException ignore) {
if ( indexing ) {
final TypeElement indexedEntity = findIndexedEntityByQualifiedName( entityName );
if ( indexedEntity != null ) {
entityCache.put(entityName, indexedEntity);
return indexedEntity;
}
}
TypeElement symbol =
@ -543,6 +543,26 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
return null;
}
private @Nullable TypeElement findIndexedEntityByQualifiedName(String entityName) {
final String qualifiedName = entityNameMappings.get(entityName);
if ( qualifiedName != null ) {
return elementUtil.getTypeElement(qualifiedName);
}
try (Reader reader = filer.getResource( StandardLocation.SOURCE_OUTPUT, ENTITY_INDEX, entityName)
.openReader(true); BufferedReader buffered = new BufferedReader(reader) ) {
return elementUtil.getTypeElement(buffered.readLine());
}
catch (IOException ignore) {
}
try (Reader reader = filer.getResource(StandardLocation.CLASS_PATH, ENTITY_INDEX, entityName)
.openReader(true); BufferedReader buffered = new BufferedReader(reader) ) {
return elementUtil.getTypeElement(buffered.readLine());
}
catch (IOException ignore) {
}
return null;
}
public static TypeElement findEntityByUnqualifiedName(String entityName, ModuleElement module) {
for (Element element: module.getEnclosedElements()) {
if (element.getKind() == ElementKind.PACKAGE) {