HHH-18162 index creation in HibernateProcessor

This stores an index of entities and enum values in the
entity.index directory. This approach has some downsides
but works around some limitations of the processor API.

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-05-23 15:53:15 +02:00
parent ed2fdce0a6
commit ebd8619f73
11 changed files with 245 additions and 48 deletions

View File

@ -13,6 +13,7 @@ import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.ManagedType; import jakarta.persistence.metamodel.ManagedType;
import jakarta.persistence.metamodel.Metamodel; import jakarta.persistence.metamodel.Metamodel;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.Incubating; import org.hibernate.Incubating;
import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.jpa.spi.JpaCompliance; import org.hibernate.jpa.spi.JpaCompliance;
@ -89,7 +90,8 @@ public interface JpaMetamodel extends Metamodel {
String qualifyImportableName(String queryName); String qualifyImportableName(String queryName);
Set<String> getAllowedEnumLiteralTexts(String enumValue); @Nullable
Set<String> getEnumTypesForValue(String enumValue);
EnumJavaType<?> getEnumType(String prefix); EnumJavaType<?> getEnumType(String prefix);

View File

@ -21,6 +21,7 @@ import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.boot.model.NamedEntityGraphDefinition; import org.hibernate.boot.model.NamedEntityGraphDefinition;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
@ -281,8 +282,8 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
.collect( Collectors.toSet() ); .collect( Collectors.toSet() );
} }
@Override @Override @Nullable
public Set<String> getAllowedEnumLiteralTexts(String enumValue) { public Set<String> getEnumTypesForValue(String enumValue) {
return allowedEnumLiteralTexts.get(enumValue); return allowedEnumLiteralTexts.get(enumValue);
} }

View File

@ -530,8 +530,8 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
} }
@Override @Override
public Set<String> getAllowedEnumLiteralTexts(String enumValue) { public Set<String> getEnumTypesForValue(String enumValue) {
return jpaMetamodel.getAllowedEnumLiteralTexts(enumValue); return jpaMetamodel.getEnumTypesForValue(enumValue);
} }
@Override @Override

View File

@ -2603,7 +2603,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
ctx = ctx.getChild( 0 ); ctx = ctx.getChild( 0 );
if ( ctx instanceof HqlParser.SimplePathContext ) { if ( ctx instanceof HqlParser.SimplePathContext ) {
return creationContext.getJpaMetamodel().getAllowedEnumLiteralTexts( ctx.getText() ); return creationContext.getJpaMetamodel().getEnumTypesForValue( ctx.getText() );
} }
} }
} }

View File

@ -106,6 +106,9 @@ public final class Context {
private String[] includes = {"*"}; private String[] includes = {"*"};
private String[] excludes = {}; private String[] excludes = {};
private final Map<String, String> entityNameMappings = new HashMap<>();
private final Map<String, Set<String>> enumTypesByValue = new HashMap<>();
public Context(ProcessingEnvironment processingEnvironment) { public Context(ProcessingEnvironment processingEnvironment) {
this.processingEnvironment = processingEnvironment; this.processingEnvironment = processingEnvironment;
@ -483,4 +486,24 @@ public final class Context {
|| elements.stream().noneMatch(member -> member instanceof ExecutableElement || elements.stream().noneMatch(member -> member instanceof ExecutableElement
&& getElementUtils().overrides((ExecutableElement) member, (ExecutableElement) inherited, type)); && getElementUtils().overrides((ExecutableElement) member, (ExecutableElement) inherited, type));
} }
public Map<String, String> getEntityNameMappings() {
return entityNameMappings;
}
public void addEntityNameMapping(String entityName, String qualifiedName) {
entityNameMappings.put( entityName, qualifiedName );
}
public @Nullable String qualifiedNameForEntityName(String entityName) {
return entityNameMappings.get(entityName);
}
public Map<String,Set<String>> getEnumTypesByValue() {
return enumTypesByValue;
}
public void addEnumValue(String type, String value) {
enumTypesByValue.computeIfAbsent( value, s -> new HashSet<>() ).add( type );
}
} }

View File

@ -22,13 +22,19 @@ import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement; import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic; import javax.tools.Diagnostic;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -42,12 +48,36 @@ import static org.hibernate.processor.HibernateProcessor.ADD_GENERATED_ANNOTATIO
import static org.hibernate.processor.HibernateProcessor.ADD_GENERATION_DATE; import static org.hibernate.processor.HibernateProcessor.ADD_GENERATION_DATE;
import static org.hibernate.processor.HibernateProcessor.ADD_SUPPRESS_WARNINGS_ANNOTATION; import static org.hibernate.processor.HibernateProcessor.ADD_SUPPRESS_WARNINGS_ANNOTATION;
import static org.hibernate.processor.HibernateProcessor.DEBUG_OPTION; 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.FULLY_ANNOTATION_CONFIGURED_OPTION;
import static org.hibernate.processor.HibernateProcessor.INCLUDE;
import static org.hibernate.processor.HibernateProcessor.LAZY_XML_PARSING; import static org.hibernate.processor.HibernateProcessor.LAZY_XML_PARSING;
import static org.hibernate.processor.HibernateProcessor.ORM_XML_OPTION; import static org.hibernate.processor.HibernateProcessor.ORM_XML_OPTION;
import static org.hibernate.processor.HibernateProcessor.PERSISTENCE_XML_OPTION; import static org.hibernate.processor.HibernateProcessor.PERSISTENCE_XML_OPTION;
import static org.hibernate.processor.HibernateProcessor.SUPPRESS_JAKARTA_DATA_METAMODEL; import static org.hibernate.processor.HibernateProcessor.SUPPRESS_JAKARTA_DATA_METAMODEL;
import static org.hibernate.processor.util.Constants.*; import static org.hibernate.processor.util.Constants.EMBEDDABLE;
import static org.hibernate.processor.util.Constants.ENTITY;
import static org.hibernate.processor.util.Constants.FIND;
import static org.hibernate.processor.util.Constants.HIB_FETCH_PROFILE;
import static org.hibernate.processor.util.Constants.HIB_FETCH_PROFILES;
import static org.hibernate.processor.util.Constants.HIB_FILTER_DEF;
import static org.hibernate.processor.util.Constants.HIB_FILTER_DEFS;
import static org.hibernate.processor.util.Constants.HIB_NAMED_NATIVE_QUERIES;
import static org.hibernate.processor.util.Constants.HIB_NAMED_NATIVE_QUERY;
import static org.hibernate.processor.util.Constants.HIB_NAMED_QUERIES;
import static org.hibernate.processor.util.Constants.HIB_NAMED_QUERY;
import static org.hibernate.processor.util.Constants.HQL;
import static org.hibernate.processor.util.Constants.JD_REPOSITORY;
import static org.hibernate.processor.util.Constants.MAPPED_SUPERCLASS;
import static org.hibernate.processor.util.Constants.NAMED_ENTITY_GRAPH;
import static org.hibernate.processor.util.Constants.NAMED_ENTITY_GRAPHS;
import static org.hibernate.processor.util.Constants.NAMED_NATIVE_QUERIES;
import static org.hibernate.processor.util.Constants.NAMED_NATIVE_QUERY;
import static org.hibernate.processor.util.Constants.NAMED_QUERIES;
import static org.hibernate.processor.util.Constants.NAMED_QUERY;
import static org.hibernate.processor.util.Constants.SQL;
import static org.hibernate.processor.util.Constants.SQL_RESULT_SET_MAPPING;
import static org.hibernate.processor.util.Constants.SQL_RESULT_SET_MAPPINGS;
import static org.hibernate.processor.util.TypeUtils.containsAnnotation; import static org.hibernate.processor.util.TypeUtils.containsAnnotation;
import static org.hibernate.processor.util.TypeUtils.getAnnotationMirror; import static org.hibernate.processor.util.TypeUtils.getAnnotationMirror;
import static org.hibernate.processor.util.TypeUtils.getAnnotationValue; import static org.hibernate.processor.util.TypeUtils.getAnnotationValue;
@ -85,7 +115,8 @@ import static org.hibernate.processor.util.TypeUtils.isClassOrRecordType;
ADD_GENERATION_DATE, ADD_GENERATION_DATE,
ADD_GENERATED_ANNOTATION, ADD_GENERATED_ANNOTATION,
ADD_SUPPRESS_WARNINGS_ANNOTATION, ADD_SUPPRESS_WARNINGS_ANNOTATION,
SUPPRESS_JAKARTA_DATA_METAMODEL SUPPRESS_JAKARTA_DATA_METAMODEL,
INCLUDE, EXCLUDE
}) })
public class HibernateProcessor extends AbstractProcessor { public class HibernateProcessor extends AbstractProcessor {
@ -157,6 +188,8 @@ public class HibernateProcessor extends AbstractProcessor {
private static final boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = false; private static final boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = false;
public static final String ENTITY_INDEX = "entity.index";
private Context context; private Context context;
@Override @Override
@ -168,7 +201,7 @@ public class HibernateProcessor extends AbstractProcessor {
"Hibernate compile-time tooling " + Version.getVersionString() "Hibernate compile-time tooling " + Version.getVersionString()
); );
boolean fullyAnnotationConfigured = handleSettings( processingEnvironment ); final boolean fullyAnnotationConfigured = handleSettings( processingEnvironment );
if ( !fullyAnnotationConfigured ) { if ( !fullyAnnotationConfigured ) {
new JpaDescriptorParser( context ).parseXml(); new JpaDescriptorParser( context ).parseXml();
if ( context.isFullyXmlConfigured() ) { if ( context.isFullyXmlConfigured() ) {
@ -275,6 +308,7 @@ public class HibernateProcessor extends AbstractProcessor {
if ( !elementsToRedo.isEmpty() ) { if ( !elementsToRedo.isEmpty() ) {
context.logMessage( Diagnostic.Kind.ERROR, "Failed to generate code for " + elementsToRedo ); context.logMessage( Diagnostic.Kind.ERROR, "Failed to generate code for " + elementsToRedo );
} }
writeIndex();
} }
else if ( context.isFullyXmlConfigured() ) { else if ( context.isFullyXmlConfigured() ) {
context.logMessage( context.logMessage(
@ -518,6 +552,9 @@ public class HibernateProcessor extends AbstractProcessor {
if ( isClassOrRecordType( element ) ) { if ( isClassOrRecordType( element ) ) {
if ( hasAnnotation( element, ENTITY, MAPPED_SUPERCLASS, EMBEDDABLE ) ) { if ( hasAnnotation( element, ENTITY, MAPPED_SUPERCLASS, EMBEDDABLE ) ) {
final TypeElement typeElement = (TypeElement) element; final TypeElement typeElement = (TypeElement) element;
indexEntityName( typeElement );
indexEnumFields( typeElement );
final String qualifiedName = typeElement.getQualifiedName().toString(); final String qualifiedName = typeElement.getQualifiedName().toString();
final Metamodel alreadyExistingMetaEntity = final Metamodel alreadyExistingMetaEntity =
tryGettingExistingEntityFromContext( typeElement, qualifiedName ); tryGettingExistingEntityFromContext( typeElement, qualifiedName );
@ -565,6 +602,54 @@ public class HibernateProcessor extends AbstractProcessor {
} }
} }
private void indexEntityName(TypeElement typeElement) {
final AnnotationMirror mirror = getAnnotationMirror( typeElement, ENTITY );
if ( mirror != null ) {
context.addEntityNameMapping( entityName( typeElement, mirror ),
typeElement.getQualifiedName().toString() );
}
}
private static String entityName(TypeElement entityType, AnnotationMirror mirror) {
final String className = entityType.getSimpleName().toString();
final AnnotationValue name = getAnnotationValue(mirror, "name" );
if (name != null) {
final String explicitName = name.getValue().toString();
if ( !explicitName.isEmpty() ) {
return explicitName;
}
}
return className;
}
private void indexEnumFields(TypeElement typeElement) {
for ( Element member : context.getAllMembers(typeElement) ) {
switch ( member.getKind() ) {
case FIELD:
indexEnumValues( member.asType() );
break;
case METHOD:
indexEnumValues( ((ExecutableElement) member).getReturnType() );
break;
}
}
}
private void indexEnumValues(TypeMirror type) {
if ( type.getKind() == TypeKind.DECLARED ) {
final DeclaredType declaredType = (DeclaredType) type;
final TypeElement fieldType = (TypeElement) declaredType.asElement();
if ( fieldType.getKind() == ElementKind.ENUM ) {
for (Element enumMember : fieldType.getEnclosedElements() ) {
if ( enumMember.getKind() == ElementKind.ENUM_CONSTANT) {
context.addEnumValue( fieldType.getQualifiedName().toString(),
enumMember.getSimpleName().toString() );
}
}
}
}
}
private void handleRootElementAuxiliaryAnnotationMirrors(final Element element) { private void handleRootElementAuxiliaryAnnotationMirrors(final Element element) {
if ( element instanceof TypeElement ) { if ( element instanceof TypeElement ) {
final AnnotationMetaEntity metaEntity = final AnnotationMetaEntity metaEntity =
@ -615,4 +700,33 @@ public class HibernateProcessor extends AbstractProcessor {
} }
} }
private void writeIndex() {
final ProcessingEnvironment processingEnvironment = context.getProcessingEnvironment();
context.getEntityNameMappings().forEach((entityName, className) -> {
try (Writer writer = processingEnvironment.getFiler()
.createResource(StandardLocation.SOURCE_OUTPUT, ENTITY_INDEX, entityName)
.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)
.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

@ -84,7 +84,8 @@ public abstract class AnnotationMeta implements Metamodel {
final AnnotationValue nameValue = getAnnotationValue( mirror, "name" ); final AnnotationValue nameValue = getAnnotationValue( mirror, "name" );
if ( nameValue != null ) { if ( nameValue != null ) {
final String name = nameValue.getValue().toString(); final String name = nameValue.getValue().toString();
final boolean reportErrors = getContext().checkNamedQuery( name ); final Context context = getContext();
final boolean reportErrors = context.checkNamedQuery( name );
final AnnotationValue value = getAnnotationValue( mirror, "query" ); final AnnotationValue value = getAnnotationValue( mirror, "query" );
if ( value != null ) { if ( value != null ) {
final Object query = value.getValue(); final Object query = value.getValue();
@ -98,9 +99,10 @@ public abstract class AnnotationMeta implements Metamodel {
// If we are in the scope of @CheckHQL, semantic errors in the // If we are in the scope of @CheckHQL, semantic errors in the
// query result in compilation errors. Otherwise, they only // query result in compilation errors. Otherwise, they only
// result in warnings, so we don't break working code. // result in warnings, so we don't break working code.
new WarningErrorHandler( getContext(), getElement(), mirror, value, hql, new WarningErrorHandler( context, getElement(), mirror, value, hql,
reportErrors, checkHql ), reportErrors, checkHql ),
ProcessorSessionFactory.create( getContext().getProcessingEnvironment() ) ProcessorSessionFactory.create( context.getProcessingEnvironment(),
context.getEntityNameMappings(), context.getEnumTypesByValue() )
); );
if ( statement instanceof SqmSelectStatement if ( statement instanceof SqmSelectStatement
&& isQueryMethodName( name ) ) { && isQueryMethodName( name ) ) {
@ -112,7 +114,7 @@ public abstract class AnnotationMeta implements Metamodel {
isRepository(), isRepository(),
getSessionType(), getSessionType(),
getSessionVariableName(), getSessionVariableName(),
getContext().addNonnullAnnotation() context.addNonnullAnnotation()
) )
); );
} }

View File

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

View File

@ -7,6 +7,7 @@
package org.hibernate.processor.annotation; package org.hibernate.processor.annotation;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.processor.Context;
import org.hibernate.processor.model.MetaAttribute; import org.hibernate.processor.model.MetaAttribute;
import org.hibernate.processor.model.Metamodel; import org.hibernate.processor.model.Metamodel;
import org.hibernate.processor.util.Constants; import org.hibernate.processor.util.Constants;
@ -18,6 +19,7 @@ import org.hibernate.type.descriptor.java.JavaType;
import javax.lang.model.element.ModuleElement; import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import java.util.List; import java.util.List;
import java.util.TreeSet; import java.util.TreeSet;
@ -194,13 +196,19 @@ class NamedQueryMethod implements MetaAttribute {
} }
private @Nullable TypeElement entityType(String entityName) { private @Nullable TypeElement entityType(String entityName) {
final Context context = annotationMeta.getContext();
final Elements elementUtils = context.getElementUtils();
final String qualifiedName = context.qualifiedNameForEntityName(entityName);
if ( qualifiedName != null ) {
return elementUtils.getTypeElement(qualifiedName);
}
TypeElement symbol = TypeElement symbol =
findEntityByUnqualifiedName( entityName, findEntityByUnqualifiedName( entityName,
annotationMeta.getContext().getElementUtils().getModuleElement("") ); elementUtils.getModuleElement("") );
if ( symbol != null ) { if ( symbol != null ) {
return symbol; return symbol;
} }
for ( ModuleElement module : annotationMeta.getContext().getElementUtils().getAllModuleElements() ) { for ( ModuleElement module : elementUtils.getAllModuleElements() ) {
symbol = findEntityByUnqualifiedName( entityName, module ); symbol = findEntityByUnqualifiedName( entityName, module );
if ( symbol != null ) { if ( symbol != null ) {
return symbol; return symbol;

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.processor.validation; package org.hibernate.processor.validation;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.CustomEntityDirtinessStrategy; import org.hibernate.CustomEntityDirtinessStrategy;
import org.hibernate.EntityNameResolver; import org.hibernate.EntityNameResolver;
import org.hibernate.MappingException; import org.hibernate.MappingException;
@ -58,7 +59,6 @@ import org.hibernate.metamodel.internal.MetadataContext;
import org.hibernate.metamodel.internal.RuntimeMetamodelsImpl; import org.hibernate.metamodel.internal.RuntimeMetamodelsImpl;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute;
@ -729,6 +729,11 @@ public abstract class MockSessionFactory
public EntityPersister findEntityDescriptor(String entityName) { public EntityPersister findEntityDescriptor(String entityName) {
return createEntityPersister(entityName); return createEntityPersister(entityName);
} }
@Override
public Set<String> getEnumTypesForValue(String enumValue) {
return MockSessionFactory.this.getEnumTypesForValue(enumValue);
}
} }
@Override @Override
@ -868,9 +873,9 @@ public abstract class MockSessionFactory
return null; return null;
} }
@Override @Override @Nullable
public Set<String> getAllowedEnumLiteralTexts(String enumValue) { public Set<String> getEnumTypesForValue(String enumValue) {
return MockSessionFactory.this.getAllowedEnumLiteralTexts().get(enumValue); return MockSessionFactory.this.getEnumTypesForValue(enumValue);
} }
@Override @Override
@ -879,8 +884,9 @@ public abstract class MockSessionFactory
} }
} }
Map<String, Set<String>> getAllowedEnumLiteralTexts() { @Nullable
return emptyMap(); Set<String> getEnumTypesForValue(String value) {
return emptySet();
} }
class MockMappedDomainType<X> extends MappedSuperclassTypeImpl<X>{ class MockMappedDomainType<X> extends MappedSuperclassTypeImpl<X>{

View File

@ -7,6 +7,7 @@
package org.hibernate.processor.validation; package org.hibernate.processor.validation;
import jakarta.persistence.AccessType; import jakarta.persistence.AccessType;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.PropertyNotFoundException; import org.hibernate.PropertyNotFoundException;
import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.Mapping;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
@ -21,6 +22,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.VarcharJdbcType; import org.hibernate.type.descriptor.jdbc.VarcharJdbcType;
import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.internal.BasicTypeImpl;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.AnnotationValue;
@ -40,10 +42,13 @@ import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable; import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.Elements; import javax.lang.model.util.Elements;
import javax.lang.model.util.Types; import javax.lang.model.util.Types;
import javax.tools.StandardLocation;
import java.beans.Introspector; import java.beans.Introspector;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -65,8 +70,11 @@ import static org.hibernate.processor.util.Constants.JAVA_OBJECT;
@SuppressWarnings("nullness") @SuppressWarnings("nullness")
public abstract class ProcessorSessionFactory extends MockSessionFactory { public abstract class ProcessorSessionFactory extends MockSessionFactory {
public static MockSessionFactory create(ProcessingEnvironment environment) { public static MockSessionFactory create(
return instance.make(environment); ProcessingEnvironment environment,
Map<String,String> entityNameMappings,
Map<String, Set<String>> enumTypesByValue) {
return instance.make(environment, entityNameMappings, enumTypesByValue);
} }
static final Mocker<ProcessorSessionFactory> instance = Mocker.variadic(ProcessorSessionFactory.class); static final Mocker<ProcessorSessionFactory> instance = Mocker.variadic(ProcessorSessionFactory.class);
@ -80,10 +88,19 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
private final Elements elementUtil; private final Elements elementUtil;
private final Types typeUtil; private final Types typeUtil;
private final Filer filer;
private final Map<String, String> entityNameMappings;
private final Map<String, Set<String>> enumTypesByValue;
public ProcessorSessionFactory(ProcessingEnvironment processingEnv) { public ProcessorSessionFactory(
elementUtil = processingEnv.getElementUtils(); ProcessingEnvironment processingEnvironment,
typeUtil = processingEnv.getTypeUtils(); Map<String,String> entityNameMappings,
Map<String, Set<String>> enumTypesByValue) {
elementUtil = processingEnvironment.getElementUtils();
typeUtil = processingEnvironment.getTypeUtils();
filer = processingEnvironment.getFiler();
this.entityNameMappings = entityNameMappings;
this.enumTypesByValue = enumTypesByValue;
} }
@Override @Override
@ -196,29 +213,28 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
: IntegerJdbcType.INSTANCE; : IntegerJdbcType.INSTANCE;
} }
final Map<String, Set<String>> result = new HashMap<>(); public static final String ENTITY_INDEX = "entity.index";
@Override @Override @Nullable
Map<String, Set<String>> getAllowedEnumLiteralTexts() { Set<String> getEnumTypesForValue(String value) {
//TODO: elementUtil.getAllModuleElements(); Set<String> result = enumTypesByValue.get(value);
if ( result.isEmpty() ) { if ( result != null ) {
for (Element mod : elementUtil.getModuleElement("").getEnclosedElements()) {
for (Element element : mod.getEnclosedElements()) {
if (element.getKind() == ElementKind.ENUM) {
TypeElement typeElement = (TypeElement) element;
for (Element member : element.getEnclosedElements()) {
if (member.getKind() == ElementKind.ENUM_CONSTANT) {
String name = member.getSimpleName().toString();
result.computeIfAbsent( name, s -> new HashSet<>() )
.add( typeElement.getQualifiedName().toString() );
}
}
}
}
}
}
return result; return result;
} }
try (Reader reader = filer.getResource(StandardLocation.SOURCE_OUTPUT, ENTITY_INDEX, value)
.openReader(true); BufferedReader buffered = new BufferedReader(reader) ) {
return Set.of(buffered.readLine().split(" "));
}
catch (IOException e) {
}
try (Reader reader = filer.getResource(StandardLocation.CLASS_PATH, ENTITY_INDEX, '.' + value)
.openReader(true); BufferedReader buffered = new BufferedReader(reader) ) {
return Set.of(buffered.readLine().split(" "));
}
catch (IOException e) {
}
return null;
}
private static Type elementCollectionElementType(TypeElement elementType, private static Type elementCollectionElementType(TypeElement elementType,
String role, String path, String role, String path,
@ -430,6 +446,30 @@ public abstract class ProcessorSessionFactory extends MockSessionFactory {
if ( cached != null ) { if ( cached != null ) {
return cached; return cached;
} }
String qualifiedName = entityNameMappings.get(entityName);
if ( qualifiedName != null ) {
TypeElement result = elementUtil.getTypeElement(qualifiedName);
entityCache.put(entityName, result);
return result;
}
StandardLocation location = StandardLocation.SOURCE_OUTPUT;
try (Reader reader = filer.getResource(location, ENTITY_INDEX, entityName)
.openReader(true); BufferedReader buffered = new BufferedReader(reader) ) {
TypeElement result = elementUtil.getTypeElement(buffered.readLine());
entityCache.put(entityName, result);
return result;
}
catch (IOException e) {
}
try (Reader reader = filer.getResource(StandardLocation.CLASS_PATH, ENTITY_INDEX, entityName)
.openReader(true); BufferedReader buffered = new BufferedReader(reader) ) {
TypeElement result = elementUtil.getTypeElement(buffered.readLine());
entityCache.put(entityName, result);
return result;
}
catch (IOException e) {
}
TypeElement symbol = TypeElement symbol =
findEntityByUnqualifiedName(entityName, findEntityByUnqualifiedName(entityName,
elementUtil.getModuleElement("")); elementUtil.getModuleElement(""));