HHH-18649 populate TypedQueryReference in static metamodel

also rename two enums since "metamodel" is a word
This commit is contained in:
Gavin King 2024-09-21 23:20:01 +02:00
parent 67e7b895cc
commit ec0f78d8c7
14 changed files with 152 additions and 82 deletions

View File

@ -203,4 +203,9 @@ public ParameterMemento toMemento(SessionFactoryImplementor sessionFactory) {
private static String normalize(String name) {
return StringHelper.isNotEmpty( name ) ? name : null;
}
@Override
public Map<String, Object> getHints() {
return hints;
}
}

View File

@ -32,8 +32,8 @@ public SequenceGeneratorJpaAnnotation(SourceModelBuildingContext modelContext) {
/**
* Used in creating named, defaulted annotation instances. Generally this
* is a situation where we have:<ol>
* <li>{@linkplain GeneratedValue#strategy()} set to {@linkplain jakarta.persistence.GenerationType#SEQUENCE}</li>
* <li>{@linkplain GeneratedValue#generator()} set to a non-empty String, but with no matching {@linkplain SequenceGenerator}</li>
* <li>{@linkplain jakarta.persistence.GeneratedValue#strategy()} set to {@linkplain jakarta.persistence.GenerationType#SEQUENCE}</li>
* <li>{@linkplain jakarta.persistence.GeneratedValue#generator()} set to a non-empty String, but with no matching {@linkplain SequenceGenerator}</li>
* </ol>
*/
public SequenceGeneratorJpaAnnotation(String name, SourceModelBuildingContext modelContext) {

View File

@ -47,8 +47,8 @@ public TableGeneratorJpaAnnotation(SourceModelBuildingContext modelContext) {
/**
* Used in creating named, defaulted annotation instances. Generally this
* is a situation where we have:<ol>
* <li>{@linkplain GeneratedValue#strategy()} set to {@linkplain jakarta.persistence.GenerationType#TABLE}</li>
* <li>{@linkplain GeneratedValue#generator()} set to a non-empty String, but with no matching {@linkplain TableGenerator}</li>
* <li>{@linkplain jakarta.persistence.GeneratedValue#strategy()} set to {@linkplain jakarta.persistence.GenerationType#TABLE}</li>
* <li>{@linkplain jakarta.persistence.GeneratedValue#generator()} set to a non-empty String, but with no matching {@linkplain TableGenerator}</li>
* </ol>
*/
public TableGeneratorJpaAnnotation(String name, SourceModelBuildingContext modelContext) {

View File

@ -4,11 +4,13 @@
*/
package org.hibernate.boot.query;
import jakarta.persistence.TypedQueryReference;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.named.NamedQueryMemento;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Common attributes shared across the mapping of named HQL, native
* and "callable" queries defined in annotations, orm.xml and hbm.xml
@ -16,7 +18,12 @@
* @author Steve Ebersole
* @author Gavin King
*/
public interface NamedQueryDefinition<E> {
public interface NamedQueryDefinition<E> extends TypedQueryReference<E> {
@Override
default String getName() {
return getRegistrationName();
}
/**
* The name under which the query is to be registered
*/

View File

@ -110,6 +110,7 @@ public String getComment() {
return comment;
}
@Override
public Map<String, Object> getHints() {
return hints;
}

View File

@ -46,33 +46,38 @@ public interface MappingSettings {
/**
* Setting that indicates whether to build the JPA types, either:<ul>
* <li>
* <b>enabled</b> - Do the build
* {@code enabled} &mdash; do the build
* </li>
* <li>
* <b>disabled</b> - Do not do the build
* {@code disabled} &mdash; do not do the build
* </li>
* <li>
* <b>ignoreUnsupported</b> - Do the build, but ignore any non-JPA
* features that would otherwise result in a failure.
* {@code ignoreUnsupported} &mdash; do the build, but ignore any
* non-JPA features that would otherwise result in a failure.
* </li>
* </ul>
*
* @settingDefault {@code ignoreUnsupported}
*/
String JPA_METAMODEL_POPULATION = "hibernate.jpa.metamodel.population";
/**
* Setting that controls whether we seek out JPA "static metamodel" classes
* Setting that controls whether we seek out JPA static metamodel classes
* and populate them, either:<ul>
* <li>
* <b>enabled</b> - Do the population
* {@code enabled} &mdash; do populate the static metamodel,
* </li>
* <li>
* <b>disabled</b> - Do not do the population
* {@code disabled} &mdash; do not populate the static metamodel, or
* </li>
* <li>
* <b>skipUnsupported</b> - Do the population, but ignore any non-JPA
* features that would otherwise result in the population failing.
* {@code skipUnsupported} &mdash; do populate the static metamodel,
* but ignore any non-JPA features that would otherwise result in
* the process failing.
* </li>
* </ul>
*
* @settingDefault {@code skipUnsupported}
*/
String STATIC_METAMODEL_POPULATION = "hibernate.jpa.static_metamodel.population";

View File

@ -356,7 +356,7 @@ public void sessionFactoryClosed(SessionFactory factory) {
private void integrate(MetadataImplementor bootMetamodel, BootstrapContext bootstrapContext, IntegratorObserver integratorObserver) {
for ( Integrator integrator : serviceRegistry.requireService( IntegratorService.class ).getIntegrators() ) {
integrator.integrate(bootMetamodel, bootstrapContext, this );
integrator.integrate( bootMetamodel, bootstrapContext, this );
integratorObserver.integrators.add( integrator );
}
}

View File

@ -4,6 +4,7 @@
*/
package org.hibernate.metamodel.internal;
import java.util.Locale;
import java.util.Map;
import org.hibernate.cfg.AvailableSettings;
@ -12,28 +13,25 @@
/**
* @author Steve Ebersole
*/
public enum JpaMetaModelPopulationSetting {
public enum JpaMetamodelPopulationSetting {
ENABLED,
DISABLED,
IGNORE_UNSUPPORTED;
public static JpaMetaModelPopulationSetting parse(String setting) {
if ( "enabled".equalsIgnoreCase( setting ) ) {
return ENABLED;
}
else if ( "disabled".equalsIgnoreCase( setting ) ) {
return DISABLED;
}
else {
return IGNORE_UNSUPPORTED;
}
public static JpaMetamodelPopulationSetting parse(String setting) {
return switch ( setting.toLowerCase(Locale.ROOT) ) {
case "enabled" -> ENABLED;
case "disabled" -> DISABLED;
default -> IGNORE_UNSUPPORTED;
};
}
public static JpaMetaModelPopulationSetting determineJpaMetaModelPopulationSetting(Map configurationValues) {
public static JpaMetamodelPopulationSetting determineJpaMetaModelPopulationSetting(Map configurationValues) {
String setting = ConfigurationHelper.getString(
AvailableSettings.JPA_METAMODEL_POPULATION,
configurationValues
configurationValues,
"ignoreUnsupported"
);
return JpaMetaModelPopulationSetting.parse( setting );
return JpaMetamodelPopulationSetting.parse( setting );
}
}

View File

@ -4,6 +4,7 @@
*/
package org.hibernate.metamodel.internal;
import java.util.Locale;
import java.util.Map;
import org.hibernate.cfg.AvailableSettings;
@ -15,43 +16,40 @@
*
* @author Andrea Boriero
*/
public enum JpaStaticMetaModelPopulationSetting {
public enum JpaStaticMetamodelPopulationSetting {
/**
* ENABLED indicates that Hibernate will look for the JPA static metamodel description
* Indicates that Hibernate will look for the JPA static metamodel description
* of the application domain model and populate it.
*/
ENABLED,
/**
* DISABLED indicates that Hibernate will not look for the JPA static metamodel description
* Indicates that Hibernate will not look for the JPA static metamodel description
* of the application domain model.
*/
DISABLED,
/**
* SKIP_UNSUPPORTED works as ENABLED but ignores any non-JPA features that would otherwise
* Works as {@link #ENABLED} but ignores any non-JPA features that would otherwise
* result in the population failing.
*/
SKIP_UNSUPPORTED;
public static JpaStaticMetaModelPopulationSetting parse(String setting) {
if ( "enabled".equalsIgnoreCase( setting ) ) {
return ENABLED;
}
else if ( "disabled".equalsIgnoreCase( setting ) ) {
return DISABLED;
}
else {
return SKIP_UNSUPPORTED;
}
public static JpaStaticMetamodelPopulationSetting parse(String setting) {
return switch ( setting.toLowerCase(Locale.ROOT) ) {
case "enabled" -> ENABLED;
case "disabled" -> DISABLED;
default -> SKIP_UNSUPPORTED;
};
}
public static JpaStaticMetaModelPopulationSetting determineJpaStaticMetaModelPopulationSetting(Map configurationValues) {
public static JpaStaticMetamodelPopulationSetting determineJpaStaticMetaModelPopulationSetting(Map configurationValues) {
return parse( determineSetting( configurationValues ) );
}
private static String determineSetting(Map configurationValues) {
return ConfigurationHelper.getString(
AvailableSettings.STATIC_METAMODEL_POPULATION,
configurationValues
configurationValues,
"skipUnsupported"
);
}
}

View File

@ -6,7 +6,6 @@
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -17,6 +16,7 @@
import org.hibernate.AssertionFailure;
import org.hibernate.Internal;
import org.hibernate.MappingException;
import org.hibernate.boot.query.NamedQueryDefinition;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.MetadataImplementor;
@ -58,6 +58,9 @@
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.Type;
import static java.lang.Character.charCount;
import static java.util.Collections.unmodifiableMap;
/**
* Defines a context for storing information during the building of the {@link MappingMetamodelImpl}.
@ -81,8 +84,8 @@ public class MetadataContext {
private final Set<MappedSuperclass> knownMappedSuperclasses;
private final TypeConfiguration typeConfiguration;
private final JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting;
private final JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting;
private final JpaStaticMetamodelPopulationSetting jpaStaticMetaModelPopulationSetting;
private final JpaMetamodelPopulationSetting jpaMetaModelPopulationSetting;
private final AttributeFactory attributeFactory = new AttributeFactory( this );
private final Map<Class<?>, EntityDomainType<?>> entityTypes = new HashMap<>();
@ -110,8 +113,8 @@ public MetadataContext(
JpaMetamodelImplementor jpaMetamodel,
MappingMetamodel mappingMetamodel,
MetadataImplementor bootMetamodel,
JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting,
JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting,
JpaStaticMetamodelPopulationSetting jpaStaticMetaModelPopulationSetting,
JpaMetamodelPopulationSetting jpaMetaModelPopulationSetting,
RuntimeModelCreationContext runtimeModelCreationContext) {
this.jpaMetamodel = jpaMetamodel;
this.classLoaderService = jpaMetamodel.getServiceRegistry().getService( ClassLoaderService.class );
@ -149,7 +152,7 @@ MappingMetamodel getMetamodel() {
* @return The {@linkplain Class java type} to {@link EntityTypeImpl} map.
*/
public Map<Class<?>, EntityDomainType<?>> getEntityTypeMap() {
return Collections.unmodifiableMap( entityTypes );
return unmodifiableMap( entityTypes );
}
public Set<EmbeddableDomainType<?>> getEmbeddableTypeSet() {
@ -255,7 +258,7 @@ public <E> IdentifiableDomainType<E> locateIdentifiableType(String entityName) {
}
public Map<String, IdentifiableDomainType<?>> getIdentifiableTypesByName() {
return Collections.unmodifiableMap( identifiableTypesByName );
return unmodifiableMap( identifiableTypesByName );
}
private <X> PersistentAttribute<X, ?> buildAttribute(
@ -292,7 +295,7 @@ public void wrapUp() {
}
final boolean staticMetamodelScanEnabled =
this.jpaStaticMetaModelPopulationSetting != JpaStaticMetaModelPopulationSetting.DISABLED;
this.jpaStaticMetaModelPopulationSetting != JpaStaticMetamodelPopulationSetting.DISABLED;
final Set<String> processedMetamodelClasses = new HashSet<>();
//we need to process types from superclasses to subclasses
@ -459,7 +462,7 @@ private void addAttribute(ManagedDomainType<?> type, PersistentAttribute<Object,
inFlightAccess.addAttribute( subAttribute );
}
}
if ( jpaMetaModelPopulationSetting != JpaMetaModelPopulationSetting.ENABLED ) {
if ( jpaMetaModelPopulationSetting != JpaMetamodelPopulationSetting.ENABLED ) {
return;
}
}
@ -698,30 +701,80 @@ private <X> void populateStaticMetamodel(ManagedDomainType<X> managedType, Set<S
}
final String metamodelClassName = managedTypeClass.getName() + '_';
if ( processedMetamodelClassName.add( metamodelClassName ) ) {
try {
final Class<?> metamodelClass = classLoaderService.classForName( metamodelClassName );
// we found the class; so populate it...
registerAttributes( metamodelClass, managedType );
try {
injectField( metamodelClass, "class_", managedType, false );
}
catch ( NoSuchFieldException e ) {
// ignore
}
final Class<?> metamodelClass = metamodelClass( metamodelClassName );
if ( metamodelClass != null ) {
populateMetamodelClass( managedType, metamodelClass );
}
catch ( ClassLoadingException ignore ) {
// nothing to do...
}
// todo : this does not account for @MappedSuperclass, mainly because this is not being tracked in our
// internal metamodel as populated from the annotations properly
ManagedDomainType<? super X> superType = managedType.getSuperType();
// todo : this does not account for @MappedSuperclass, mainly
// because this is not being tracked in our internal
// metamodel as populated from the annotations properly
final ManagedDomainType<? super X> superType = managedType.getSuperType();
if ( superType != null ) {
populateStaticMetamodel( superType, processedMetamodelClassName );
}
}
}
private <X> void populateMetamodelClass(ManagedDomainType<X> managedType, Class<?> metamodelClass) {
registerAttributes( metamodelClass, managedType );
injectManagedType( managedType, metamodelClass );
runtimeModelCreationContext.getBootModel()
.visitNamedHqlQueryDefinitions( definition
-> injectTypedQueryReference( definition, metamodelClass) );
runtimeModelCreationContext.getBootModel()
.visitNamedNativeQueryDefinitions( definition
-> injectTypedQueryReference( definition, metamodelClass) );
//TODO: named entity graphs
}
private static <X> void injectManagedType(ManagedDomainType<X> managedType, Class<?> metamodelClass) {
try {
injectField(metamodelClass, "class_", managedType, false );
}
catch ( NoSuchFieldException e ) {
// ignore
}
}
private Class<?> metamodelClass(String metamodelClassName) {
try {
return classLoaderService.classForName( metamodelClassName );
}
catch ( ClassLoadingException ignore ) {
return null;
}
}
private static void injectTypedQueryReference(NamedQueryDefinition<?> definition, Class<?> metamodelClass) {
try {
injectField(
metamodelClass,
'_' + javaIdentifier( definition.getRegistrationName() ) + '_',
definition,
false
);
}
catch ( NoSuchFieldException e ) {
// ignore
}
}
public static String javaIdentifier(String name) {
final StringBuilder result = new StringBuilder();
int position = 0;
while ( position < name.length() ) {
final int codePoint = name.codePointAt( position );
if ( Character.isJavaIdentifierPart(codePoint) ) {
result.appendCodePoint( codePoint );
}
else {
result.append('_');
}
position += charCount( codePoint );
}
return result.toString();
}
private <X> void registerAttributes(Class<?> metamodelClass, ManagedDomainType<X> managedType) {
// push the attributes on to the metamodel class...
for ( Attribute<X, ?> attribute : managedType.getDeclaredAttributes() ) {

View File

@ -5,6 +5,7 @@
package org.hibernate.metamodel.model.domain;
import java.io.ObjectStreamException;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
@ -630,6 +631,7 @@ public <K, V> MapAttribute<J, K, V> getDeclaredMap(String name, Class<K> keyType
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Serialization
@Serial
protected Object writeReplace() throws ObjectStreamException {
return new SerialForm( metamodel, getJavaType() );
}
@ -643,6 +645,7 @@ public SerialForm(JpaMetamodel jpaMetamodel, Class<?> typeClass) {
this.typeClass = typeClass;
}
@Serial
private Object readResolve() {
return jpaMetamodel.managedType( typeClass );
}

View File

@ -37,8 +37,8 @@
import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting;
import org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting;
import org.hibernate.metamodel.internal.JpaMetamodelPopulationSetting;
import org.hibernate.metamodel.internal.JpaStaticMetamodelPopulationSetting;
import org.hibernate.metamodel.internal.MetadataContext;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
@ -92,7 +92,7 @@ private static class ImportInfo<T> {
private final Map<String, ManagedDomainType<?>> managedTypeByName = new TreeMap<>();
private final Map<Class<?>, ManagedDomainType<?>> managedTypeByClass = new HashMap<>();
private JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting;
private JpaMetamodelPopulationSetting jpaMetaModelPopulationSetting;
private final Map<String, Set<String>> allowedEnumLiteralsToEnumTypeNames = new HashMap<>();
private final Map<String, EnumJavaType<?>> enumJavaTypes = new HashMap<>();
@ -594,8 +594,8 @@ public void processJpa(
MetadataImplementor bootMetamodel,
MappingMetamodel mappingMetamodel,
Map<Class<?>, String> entityProxyInterfaceMap,
JpaStaticMetaModelPopulationSetting jpaStaticMetaModelPopulationSetting,
JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting,
JpaStaticMetamodelPopulationSetting jpaStaticMetaModelPopulationSetting,
JpaMetamodelPopulationSetting jpaMetaModelPopulationSetting,
Collection<NamedEntityGraphDefinition> namedEntityGraphDefinitions,
RuntimeModelCreationContext runtimeModelCreationContext) {
bootMetamodel.getImports()

View File

@ -80,8 +80,8 @@
import jakarta.persistence.metamodel.ManagedType;
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY;
import static org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting.determineJpaMetaModelPopulationSetting;
import static org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting.determineJpaStaticMetaModelPopulationSetting;
import static org.hibernate.metamodel.internal.JpaMetamodelPopulationSetting.determineJpaMetaModelPopulationSetting;
import static org.hibernate.metamodel.internal.JpaStaticMetamodelPopulationSetting.determineJpaStaticMetaModelPopulationSetting;
/**
* Implementation of the JPA-defined contract {@link jakarta.persistence.metamodel.Metamodel}.

View File

@ -51,8 +51,8 @@
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.AttributeClassification;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting;
import org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting;
import org.hibernate.metamodel.internal.JpaMetamodelPopulationSetting;
import org.hibernate.metamodel.internal.JpaStaticMetamodelPopulationSetting;
import org.hibernate.metamodel.internal.MetadataContext;
import org.hibernate.metamodel.internal.RuntimeMetamodelsImpl;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
@ -217,8 +217,8 @@ public Class<?> classForName(String className) {
metamodel.getJpaMetamodel(),
metamodel,
bootModel,
JpaStaticMetaModelPopulationSetting.DISABLED,
JpaMetaModelPopulationSetting.DISABLED,
JpaStaticMetamodelPopulationSetting.DISABLED,
JpaMetamodelPopulationSetting.DISABLED,
this
);