HHH-16028 allow FunctionContributor to be registered programmatically

since we can do this with its friend TypeContributor
This commit is contained in:
Gavin 2023-01-11 23:41:17 +01:00 committed by Gavin King
parent 2e84d51838
commit a3b2e9b4ae
13 changed files with 125 additions and 26 deletions

View File

@ -10,6 +10,7 @@ import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
import org.hibernate.boot.archive.scan.spi.ScanOptions;
import org.hibernate.boot.archive.scan.spi.Scanner;
import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory;
import org.hibernate.boot.model.FunctionContributor;
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
import org.hibernate.boot.model.TypeContributor;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
@ -369,6 +370,16 @@ public interface MetadataBuilder {
@Deprecated(since = "6", forRemoval = true)
MetadataBuilder applySourceProcessOrdering(MetadataSourceType... sourceTypes);
/**
* Apply an explicit {@link FunctionContributor}
* (implicit application via {@link java.util.ServiceLoader} will still happen too)
*
* @param functionContributor The contributor to apply
*
* @return {@code this}, for method chaining
*/
MetadataBuilder applyFunctions(FunctionContributor functionContributor);
/**
* Contribute a {@link SqmFunctionDescriptor} to HQL.
*

View File

@ -38,6 +38,7 @@ import org.hibernate.jpa.spi.MutableJpaCompliance;
import org.hibernate.metamodel.internal.ManagedTypeRepresentationResolverStandard;
import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;
@ -55,6 +56,7 @@ public class BootstrapContextImpl implements BootstrapContext {
private final MetadataBuildingOptions metadataBuildingOptions;
private final TypeConfiguration typeConfiguration;
private final SqmFunctionRegistry sqmFunctionRegistry;
private final MutableJpaCompliance jpaCompliance;
private final ClassLoaderAccessImpl classLoaderAccess;
@ -108,6 +110,7 @@ public class BootstrapContextImpl implements BootstrapContext {
this.typeConfiguration = new TypeConfiguration();
this.beanInstanceProducer = new TypeBeanInstanceProducer( configService );
this.sqmFunctionRegistry = new SqmFunctionRegistry();
}
@Override
@ -125,6 +128,11 @@ public class BootstrapContextImpl implements BootstrapContext {
return typeConfiguration;
}
@Override
public SqmFunctionRegistry getFunctionRegistry() {
return sqmFunctionRegistry;
}
@Override
public BeanInstanceProducer getCustomTypeProducer() {
return beanInstanceProducer;

View File

@ -104,6 +104,7 @@ import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.spi.TypeConfiguration;
@ -216,6 +217,11 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
return bootstrapContext.getTypeConfiguration();
}
@Override
public SqmFunctionRegistry getFunctionRegistry() {
return bootstrapContext.getFunctionRegistry();
}
@Override
public Database getDatabase() {
// important to delay this instantiation until as late as possible.

View File

@ -27,6 +27,8 @@ import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory;
import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService;
import org.hibernate.boot.cfgxml.spi.LoadedConfig;
import org.hibernate.boot.cfgxml.spi.MappingReference;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.FunctionContributor;
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.boot.model.TypeContributor;
@ -72,6 +74,7 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceException;
import org.hibernate.type.BasicType;
@ -345,6 +348,27 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
return this;
}
@Override
public MetadataBuilder applyFunctions(FunctionContributor functionContributor) {
functionContributor.contributeFunctions( new FunctionContributions() {
@Override
public SqmFunctionRegistry getFunctionRegistry() {
return bootstrapContext.getFunctionRegistry();
}
@Override
public TypeConfiguration getTypeConfiguration() {
return bootstrapContext.getTypeConfiguration();
}
@Override
public ServiceRegistry getServiceRegistry() {
return bootstrapContext.getServiceRegistry();
}
} );
return this;
}
@Override
public MetadataBuilder applySqlFunction(String functionName, SqmFunctionDescriptor function) {
this.bootstrapContext.addSqlFunction( functionName, function );

View File

@ -65,6 +65,7 @@ import org.hibernate.query.internal.NamedObjectRepositoryImpl;
import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.sql.spi.NamedNativeQueryMemento;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.spi.NamedSqmQueryMemento;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.tool.schema.Action;
@ -155,6 +156,11 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
return bootstrapContext.getTypeConfiguration();
}
@Override
public SqmFunctionRegistry getFunctionRegistry() {
return bootstrapContext.getFunctionRegistry();
}
@Override
public SessionFactoryBuilder getSessionFactoryBuilder() {
final SessionFactoryBuilderService factoryBuilderService = metadataBuildingOptions.getServiceRegistry().getService( SessionFactoryBuilderService.class );

View File

@ -15,18 +15,19 @@
package org.hibernate.boot.model;
/**
* On object that contributes custom types and type descriptors, eventually
* to a {@link org.hibernate.query.sqm.function.SqmFunctionRegistry}, via an
* On object that contributes custom HQL functions, eventually to a
* {@link org.hibernate.query.sqm.function.SqmFunctionRegistry}, via an
* instance of {@link FunctionContributions}.
* <p>
* The most common way to integrate a {@code FunctionContributor} is by making
* it discoverable via the Java {@link java.util.ServiceLoader} facility.
*
* @apiNote Unfortunately there's currently no programmatic way to register
* an instance with {@code Configuration} or {@code MetadataBuilder}.
* Nor can it be registered via a corresponding setting defined in
* {@link org.hibernate.jpa.boot.spi.JpaSettings}. These are things
* which <em>are</em> possible for its best friend {@link TypeContributor}.
* <ul>
* <li>
* The most common way to integrate a {@code FunctionContributor} is by
* making it discoverable via the Java {@link java.util.ServiceLoader}
* facility.
* <li>
* Alternatively, a {@code FunctionContributor} may be programmatically supplied to
* {@link org.hibernate.cfg.Configuration#registerFunctionContributor(FunctionContributor)}
* or even {@link org.hibernate.boot.MetadataBuilder#applyFunctions(FunctionContributor)}.
* </ul>
*
* @see org.hibernate.query.sqm.function.SqmFunctionRegistry
*

View File

@ -32,6 +32,7 @@ import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Table;
import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.type.Type;
import org.hibernate.type.spi.TypeConfiguration;
@ -213,6 +214,11 @@ public abstract class AbstractDelegatingMetadata implements MetadataImplementor
return delegate.getTypeConfiguration();
}
@Override
public SqmFunctionRegistry getFunctionRegistry() {
return delegate.getFunctionRegistry();
}
@Override
public void orderColumns(boolean forceOrdering) {
delegate.orderColumns( false );

View File

@ -16,6 +16,7 @@ import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
import org.hibernate.boot.archive.scan.spi.ScanOptions;
import org.hibernate.boot.archive.scan.spi.Scanner;
import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory;
import org.hibernate.boot.model.FunctionContributor;
import org.hibernate.boot.model.IdGeneratorStrategyInterpreter;
import org.hibernate.boot.model.TypeContributor;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
@ -196,6 +197,12 @@ public abstract class AbstractDelegatingMetadataBuilderImplementor<T extends Met
return getThis();
}
@Override
public MetadataBuilder applyFunctions(FunctionContributor functionContributor) {
delegate.applyFunctions( functionContributor );
return this;
}
@Override
public MetadataBuilder applySqlFunction(String functionName, SqmFunctionDescriptor function) {
delegate.applySqlFunction( functionName, function );

View File

@ -25,6 +25,7 @@ import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.jpa.spi.MutableJpaCompliance;
import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;
@ -57,6 +58,13 @@ public interface BootstrapContext {
*/
TypeConfiguration getTypeConfiguration();
/**
* The {@link SqmFunctionRegistry} belonging to this {@code BootstrapContext}.
*
* @see SqmFunctionRegistry
*/
SqmFunctionRegistry getFunctionRegistry();
/**
* The {@link BeanInstanceProducer} to use when creating custom type references.
*

View File

@ -16,6 +16,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -38,6 +39,11 @@ public interface MetadataImplementor extends Metadata {
*/
TypeConfiguration getTypeConfiguration();
/**
* Access to the {@link SqmFunctionRegistry} belonging to the {@link BootstrapContext}
*/
SqmFunctionRegistry getFunctionRegistry();
NamedObjectRepository buildNamedQueryRepository(SessionFactoryImplementor sessionFactory);
@Incubating

View File

@ -10,7 +10,6 @@ import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -31,6 +30,7 @@ import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.internal.ClassmateContext;
import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.model.FunctionContributor;
import org.hibernate.boot.model.NamedEntityGraphDefinition;
import org.hibernate.boot.model.TypeContributor;
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
@ -66,6 +66,8 @@ import org.hibernate.usertype.UserType;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.SharedCacheMode;
import static java.util.Collections.emptyList;
/**
* A convenience API making it easier to bootstrap an instance of Hibernate.
* <p>
@ -125,8 +127,6 @@ import jakarta.persistence.SharedCacheMode;
public class Configuration {
private static final CoreMessageLogger log = CoreLogging.messageLogger( Configuration.class );
public static final String ARTEFACT_PROCESSING_ORDER = AvailableSettings.ARTIFACT_PROCESSING_ORDER;
private final BootstrapServiceRegistry bootstrapServiceRegistry;
private final MetadataSources metadataSources;
private final ClassmateContext classmateContext;
@ -137,6 +137,7 @@ public class Configuration {
private final List<BasicType<?>> basicTypes = new ArrayList<>();
private List<UserTypeRegistration> userTypeRegistrations;
private final List<TypeContributor> typeContributorRegistrations = new ArrayList<>();
private final List<FunctionContributor> functionContributorRegistrations = new ArrayList<>();
private Map<String, NamedHqlQueryDefinition> namedQueries;
private Map<String, NamedNativeQueryDefinition> namedSqlQueries;
private Map<String, NamedProcedureCallDefinition> namedProcedureCallMap;
@ -160,6 +161,9 @@ public class Configuration {
private Properties properties;
private SharedCacheMode sharedCacheMode;
@Deprecated(since = "6", forRemoval = true)
public static final String ARTEFACT_PROCESSING_ORDER = AvailableSettings.ARTIFACT_PROCESSING_ORDER;
/**
* Create a new instance, using a default {@link BootstrapServiceRegistry}
* and a newly instantiated {@link MetadataSources}.
@ -406,6 +410,14 @@ public class Configuration {
return this;
}
/**
* Add a {@link FunctionContributor} to this configuration.
*/
public Configuration registerFunctionContributor(FunctionContributor functionContributor) {
functionContributorRegistrations.add( functionContributor );
return this;
}
/**
* Register a {@linkplain BasicType type} into the type registry,
* potentially replacing a previously registered type.
@ -816,20 +828,20 @@ public class Configuration {
metadataBuilder.applySharedCacheMode( sharedCacheMode );
}
if ( !typeContributorRegistrations.isEmpty() ) {
for ( TypeContributor typeContributor : typeContributorRegistrations ) {
metadataBuilder.applyTypes( typeContributor );
}
for ( TypeContributor typeContributor : typeContributorRegistrations ) {
metadataBuilder.applyTypes( typeContributor );
}
for ( FunctionContributor functionContributor : functionContributorRegistrations ) {
metadataBuilder.applyFunctions( functionContributor );
}
if ( userTypeRegistrations != null ) {
userTypeRegistrations.forEach( registration -> registration.registerType( metadataBuilder ) );
}
if ( !basicTypes.isEmpty() ) {
for ( BasicType<?> basicType : basicTypes ) {
metadataBuilder.applyBasicType( basicType );
}
for ( BasicType<?> basicType : basicTypes ) {
metadataBuilder.applyBasicType( basicType );
}
if ( customFunctionDescriptors != null ) {
@ -1029,9 +1041,7 @@ public class Configuration {
}
public java.util.Collection<NamedEntityGraphDefinition> getNamedEntityGraphs() {
return namedEntityGraphMap == null
? Collections.emptyList()
: namedEntityGraphMap.values();
return namedEntityGraphMap == null ? emptyList() : namedEntityGraphMap.values();
}

View File

@ -84,7 +84,7 @@ public class QueryEngine {
MetadataImplementor metadata,
QueryEngineOptions queryEngineOptions,
Dialect dialect) {
final SqmFunctionRegistry sqmFunctionRegistry = new SqmFunctionRegistry();
final SqmFunctionRegistry sqmFunctionRegistry = metadata.getFunctionRegistry();
queryEngineOptions.getCustomSqlFunctionMap().forEach( sqmFunctionRegistry::register );

View File

@ -27,6 +27,7 @@ import org.hibernate.jpa.spi.MutableJpaCompliance;
import org.hibernate.metamodel.internal.ManagedTypeRepresentationResolverStandard;
import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;
@ -62,6 +63,11 @@ public class BootstrapContextImpl implements BootstrapContext {
return delegate.getTypeConfiguration();
}
@Override
public SqmFunctionRegistry getFunctionRegistry() {
return delegate.getFunctionRegistry();
}
@Override
public BeanInstanceProducer getCustomTypeProducer() {
return delegate.getCustomTypeProducer();