fix problem where Hibernate refused to instantiate non-public UserType

also:

- clean up some code with respect to generic typing
- improve some exception reporting
This commit is contained in:
Gavin King 2023-07-26 13:44:15 +02:00
parent 0725022d79
commit 9add83ec92
12 changed files with 321 additions and 304 deletions

View File

@ -15,7 +15,7 @@ public class InstantiationException extends HibernateException {
private final Class<?> clazz;
/**
* Constructs a {@code InstantiationException}.
* Constructs an {@code InstantiationException}.
*
* @param message A message explaining the exception condition
* @param clazz The Class we are attempting to instantiate

View File

@ -6,15 +6,16 @@
*/
package org.hibernate.boot.model;
import org.hibernate.InstantiationException;
import org.hibernate.Internal;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
import org.hibernate.type.spi.TypeBootstrapContext;
import java.lang.reflect.Constructor;
import java.util.Map;
import org.hibernate.Internal;
import org.hibernate.MappingException;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.resource.beans.spi.BeanInstanceProducer;
import org.hibernate.type.spi.TypeBootstrapContext;
import static org.hibernate.internal.util.ReflectHelper.getConstructor;
/**
* {@link BeanInstanceProducer} implementation for building beans related to custom types.
@ -31,20 +32,29 @@ public class TypeBeanInstanceProducer implements BeanInstanceProducer, TypeBoots
@Override
public <B> B produceBeanInstance(Class<B> beanType) {
try {
final Constructor<B> bootstrapContextAwareTypeConstructor = ReflectHelper.getConstructor(
beanType,
TypeBootstrapContext.class
);
if ( bootstrapContextAwareTypeConstructor != null ) {
return bootstrapContextAwareTypeConstructor.newInstance( this );
final Constructor<B> bootstrapContextAwareConstructor =
getConstructor( beanType, TypeBootstrapContext.class );
if ( bootstrapContextAwareConstructor != null ) {
try {
return bootstrapContextAwareConstructor.newInstance( this );
}
else {
return beanType.newInstance();
catch ( Exception e ) {
throw new InstantiationException( "Could not instantiate type", beanType, e );
}
}
catch ( Exception e ) {
throw new MappingException( "Could not instantiate Type: " + beanType.getName(), e );
else {
final Constructor<B> constructor = getConstructor( beanType );
if ( constructor != null ) {
try {
return constructor.newInstance();
}
catch ( Exception e ) {
throw new InstantiationException( "Could not instantiate type", beanType, e );
}
}
else {
throw new InstantiationException( "No appropriate constructor for type", beanType );
}
}
}

View File

@ -15,7 +15,6 @@ import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import org.hibernate.boot.model.process.internal.InferredBasicValueResolver;
import org.hibernate.boot.model.process.internal.UserTypeResolution;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.spi.BootstrapContext;
@ -42,6 +41,7 @@ import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.type.spi.TypeConfigurationAware;
import org.hibernate.usertype.UserType;
import static org.hibernate.boot.model.process.internal.InferredBasicValueResolver.resolveSqlTypeIndicators;
import static org.hibernate.mapping.MappingHelper.injectParameters;
/**
@ -131,9 +131,9 @@ public class TypeDefinition implements Serializable {
);
}
private static BasicValue.Resolution<?> createResolution(
private static <T> BasicValue.Resolution<T> createResolution(
String name,
Class<?> typeImplementorClass,
Class<T> typeImplementorClass,
Map<?,?> parameters,
Map<?,?> usageSiteProperties,
JdbcTypeIndicators indicators,
@ -141,16 +141,18 @@ public class TypeDefinition implements Serializable {
final BootstrapContext bootstrapContext = context.getBootstrapContext();
final TypeConfiguration typeConfiguration = bootstrapContext.getTypeConfiguration();
final BeanInstanceProducer instanceProducer = bootstrapContext.getCustomTypeProducer();
final boolean isKnownType = Type.class.isAssignableFrom( typeImplementorClass )
final boolean isKnownType =
Type.class.isAssignableFrom( typeImplementorClass )
|| UserType.class.isAssignableFrom( typeImplementorClass );
// support for AttributeConverter would be nice too
if ( isKnownType ) {
final Object typeInstance = instantiateType( bootstrapContext.getServiceRegistry(),
final T typeInstance = instantiateType( bootstrapContext.getServiceRegistry(),
context.getBuildingOptions(), name, typeImplementorClass, instanceProducer );
if ( typeInstance instanceof TypeConfigurationAware ) {
( (TypeConfigurationAware) typeInstance ).setTypeConfiguration( typeConfiguration );
final TypeConfigurationAware configurationAware = (TypeConfigurationAware) typeInstance;
configurationAware.setTypeConfiguration( typeConfiguration );
}
final Properties combinedTypeParameters = new Properties();
@ -164,22 +166,23 @@ public class TypeDefinition implements Serializable {
injectParameters( typeInstance, combinedTypeParameters );
if ( typeInstance instanceof UserType ) {
final UserType<?> userType = (UserType<?>) typeInstance;
final CustomType<?> customType = new CustomType<>( userType, typeConfiguration );
return new UserTypeResolution( customType, null, combinedTypeParameters );
@SuppressWarnings("unchecked")
final UserType<T> userType = (UserType<T>) typeInstance;
final CustomType<T> customType = new CustomType<>( userType, typeConfiguration );
return new UserTypeResolution<>( customType, null, combinedTypeParameters );
}
if ( typeInstance instanceof BasicType ) {
final BasicType<?> resolvedBasicType = (BasicType<?>) typeInstance;
@SuppressWarnings("unchecked")
final BasicType<T> resolvedBasicType = (BasicType<T>) typeInstance;
return new BasicValue.Resolution<>() {
@Override
public JdbcMapping getJdbcMapping() {
return resolvedBasicType;
}
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public BasicType getLegacyResolvedBasicType() {
@Override
public BasicType<T> getLegacyResolvedBasicType() {
return resolvedBasicType;
}
@ -188,8 +191,8 @@ public class TypeDefinition implements Serializable {
return combinedTypeParameters;
}
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public JavaType getDomainJavaType() {
@Override
public JavaType<T> getDomainJavaType() {
return resolvedBasicType.getMappedJavaType();
}
@ -204,12 +207,12 @@ public class TypeDefinition implements Serializable {
}
@Override
public BasicValueConverter getValueConverter() {
public BasicValueConverter<T,?> getValueConverter() {
return resolvedBasicType.getValueConverter();
}
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public MutabilityPlan getMutabilityPlan() {
@Override
public MutabilityPlan<T> getMutabilityPlan() {
// a TypeDefinition does not explicitly provide a MutabilityPlan (yet?)
return resolvedBasicType.isMutable()
? getDomainJavaType().getMutabilityPlan()
@ -220,37 +223,35 @@ public class TypeDefinition implements Serializable {
}
// Series of backward compatible special cases
if ( Serializable.class.isAssignableFrom( typeImplementorClass ) ) {
@SuppressWarnings({"rawtypes", "unchecked"})
final SerializableType legacyType = new SerializableType( typeImplementorClass );
return createBasicTypeResolution( legacyType, typeImplementorClass, indicators, typeConfiguration );
}
if ( typeImplementorClass.isInterface() ) {
return createBasicTypeResolution( new JavaObjectType(), typeImplementorClass, indicators, typeConfiguration );
}
throw new IllegalArgumentException(
"Named type [" + typeImplementorClass + "] did not implement BasicType nor UserType"
);
return resolveLegacyCases( typeImplementorClass, indicators, typeConfiguration );
}
private static BasicValue.Resolution<Object> createBasicTypeResolution(
BasicType<?> type,
Class<?> typeImplementorClass,
private static <T> BasicValue.Resolution<T> resolveLegacyCases(
Class<T> typeImplementorClass, JdbcTypeIndicators indicators, TypeConfiguration typeConfiguration) {
final BasicType<T> legacyType;
if ( Serializable.class.isAssignableFrom( typeImplementorClass ) ) {
legacyType = new SerializableType( typeImplementorClass );
}
else if ( typeImplementorClass.isInterface() ) {
legacyType = (BasicType<T>) new JavaObjectType();
}
else {
throw new IllegalArgumentException( "Named type [" + typeImplementorClass
+ "] did not implement BasicType nor UserType" );
}
return createBasicTypeResolution( legacyType, typeImplementorClass, indicators, typeConfiguration );
}
private static <T> BasicValue.Resolution<T> createBasicTypeResolution(
BasicType<T> type,
Class<? extends T> typeImplementorClass,
JdbcTypeIndicators indicators,
TypeConfiguration typeConfiguration
) {
final JavaType<Serializable> jtd = typeConfiguration
.getJavaTypeRegistry()
.resolveDescriptor( typeImplementorClass );
TypeConfiguration typeConfiguration) {
final JavaType<T> jtd = typeConfiguration.getJavaTypeRegistry().resolveDescriptor( typeImplementorClass );
final JdbcType jdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.VARBINARY );
final BasicType<Serializable> resolved = InferredBasicValueResolver.resolveSqlTypeIndicators(
indicators,
typeConfiguration.getBasicTypeRegistry().resolve( jtd, jdbcType ),
jtd
);
final BasicType<T> basicType = typeConfiguration.getBasicTypeRegistry().resolve( jtd, jdbcType );
final BasicType<T> resolved = resolveSqlTypeIndicators( indicators, basicType, jtd );
return new BasicValue.Resolution<>() {
@Override
@ -259,14 +260,12 @@ public class TypeDefinition implements Serializable {
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public BasicType getLegacyResolvedBasicType() {
public BasicType<T> getLegacyResolvedBasicType() {
return type;
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public JavaType getDomainJavaType() {
public JavaType<T> getDomainJavaType() {
return resolved.getMappedJavaType();
}
@ -281,13 +280,12 @@ public class TypeDefinition implements Serializable {
}
@Override
public BasicValueConverter getValueConverter() {
public BasicValueConverter<T,?> getValueConverter() {
return resolved.getValueConverter();
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public MutabilityPlan getMutabilityPlan() {
public MutabilityPlan<T> getMutabilityPlan() {
// a TypeDefinition does not explicitly provide a MutabilityPlan (yet?)
return resolved.isMutable()
? getDomainJavaType().getMutabilityPlan()
@ -296,11 +294,11 @@ public class TypeDefinition implements Serializable {
};
}
private static Object instantiateType(
private static <T> T instantiateType(
StandardServiceRegistry serviceRegistry,
MetadataBuildingOptions buildingOptions,
String name,
Class<?> typeImplementorClass,
Class<T> typeImplementorClass,
BeanInstanceProducer instanceProducer) {
if ( buildingOptions.disallowExtensionsInCdi() ) {
return name != null
@ -308,8 +306,8 @@ public class TypeDefinition implements Serializable {
: instanceProducer.produceBeanInstance( typeImplementorClass );
}
else {
final ManagedBeanRegistry beanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class );
final ManagedBean<?> typeBean = name != null
final ManagedBeanRegistry beanRegistry = serviceRegistry.requireService( ManagedBeanRegistry.class );
final ManagedBean<T> typeBean = name != null
? beanRegistry.getBean( name, typeImplementorClass, instanceProducer )
: beanRegistry.getBean( typeImplementorClass, instanceProducer );
return typeBean.getBeanInstance();

View File

@ -48,6 +48,7 @@ import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
import org.hibernate.boot.model.convert.spi.RegisteredConversion;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.dialect.Dialect;
@ -601,6 +602,8 @@ public final class AnnotationBinder {
private static void handleUserTypeRegistration(
MetadataBuildingContext context,
TypeRegistration compositeTypeRegistration) {
// TODO: check that the two classes agree, i.e. that
// the user type knows how to handle the type
context.getMetadataCollector().registerUserType(
compositeTypeRegistration.basicClass(),
compositeTypeRegistration.userType()
@ -610,6 +613,8 @@ public final class AnnotationBinder {
private static void handleCompositeUserTypeRegistration(
MetadataBuildingContext context,
CompositeTypeRegistration compositeTypeRegistration) {
// TODO: check that the two classes agree, i.e. that
// the user type knows how to handle the type
context.getMetadataCollector().registerCompositeUserType(
compositeTypeRegistration.embeddableClass(),
compositeTypeRegistration.userType()
@ -755,25 +760,21 @@ public final class AnnotationBinder {
}
private static JdbcMapping resolveUserType(Class<UserType<?>> userTypeClass, MetadataBuildingContext context) {
final UserType<?> userType;
if ( context.getBuildingOptions().disallowExtensionsInCdi() ) {
userType = FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( userTypeClass );
}
else {
final StandardServiceRegistry serviceRegistry = context.getBootstrapContext().getServiceRegistry();
final ManagedBeanRegistry beanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class );
userType = beanRegistry.getBean( userTypeClass ).getBeanInstance();
}
final UserType<?> userType = context.getBuildingOptions().disallowExtensionsInCdi()
? FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( userTypeClass )
: context.getBootstrapContext().getServiceRegistry()
.requireService( ManagedBeanRegistry.class )
.getBean( userTypeClass ).getBeanInstance();
return new CustomType<>( userType, context.getBootstrapContext().getTypeConfiguration() );
}
private static JdbcMapping resolveAttributeConverter(Class<AttributeConverter<?, ?>> type, MetadataBuildingContext context) {
final StandardServiceRegistry serviceRegistry = context.getBootstrapContext().getServiceRegistry();
final ManagedBeanRegistry beanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class );
final BootstrapContext bootstrapContext = context.getBootstrapContext();
final ManagedBeanRegistry beanRegistry =
bootstrapContext.getServiceRegistry().requireService( ManagedBeanRegistry.class );
final ManagedBean<AttributeConverter<?, ?>> bean = beanRegistry.getBean( type );
final TypeConfiguration typeConfiguration = context.getBootstrapContext().getTypeConfiguration();
final TypeConfiguration typeConfiguration = bootstrapContext.getTypeConfiguration();
final JavaTypeRegistry jtdRegistry = typeConfiguration.getJavaTypeRegistry();
final JavaType<? extends AttributeConverter<?,?>> converterJtd = jtdRegistry.resolveDescriptor( bean.getBeanClass() );

View File

@ -20,9 +20,9 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
/**
* @author Steve Ebersole
*/
public class UserTypeResolution implements BasicValue.Resolution {
private final CustomType<?> userTypeAdapter;
private final MutabilityPlan<?> mutabilityPlan;
public class UserTypeResolution<T> implements BasicValue.Resolution<T> {
private final CustomType<T> userTypeAdapter;
private final MutabilityPlan<T> mutabilityPlan;
/**
* We need this for the way envers interprets the boot-model
@ -31,8 +31,8 @@ public class UserTypeResolution implements BasicValue.Resolution {
private final Properties combinedTypeParameters;
public UserTypeResolution(
CustomType<?> userTypeAdapter,
MutabilityPlan<?> explicitMutabilityPlan,
CustomType<T> userTypeAdapter,
MutabilityPlan<T> explicitMutabilityPlan,
Properties combinedTypeParameters) {
this.userTypeAdapter = userTypeAdapter;
this.combinedTypeParameters = combinedTypeParameters;
@ -42,7 +42,7 @@ public class UserTypeResolution implements BasicValue.Resolution {
}
@Override
public JavaType<?> getDomainJavaType() {
public JavaType<T> getDomainJavaType() {
return userTypeAdapter.getJavaTypeDescriptor();
}
@ -57,7 +57,7 @@ public class UserTypeResolution implements BasicValue.Resolution {
}
@Override
public BasicValueConverter getValueConverter() {
public BasicValueConverter<T,?> getValueConverter() {
// Even though we could expose the value converter of the user type here,
// we can not do it, as the conversion is done behind the scenes in the binder/extractor,
// whereas the converter returned here would, AFAIU, be used to construct a converted attribute mapping
@ -65,12 +65,12 @@ public class UserTypeResolution implements BasicValue.Resolution {
}
@Override
public MutabilityPlan getMutabilityPlan() {
public MutabilityPlan<T> getMutabilityPlan() {
return mutabilityPlan;
}
@Override
public BasicType getLegacyResolvedBasicType() {
public BasicType<T> getLegacyResolvedBasicType() {
return userTypeAdapter;
}

View File

@ -147,7 +147,6 @@ import org.hibernate.mapping.UnionSubclass;
import org.hibernate.mapping.UniqueKey;
import org.hibernate.mapping.Value;
import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.spi.NavigablePath;
import org.hibernate.tuple.GenerationTiming;
@ -156,6 +155,7 @@ import org.hibernate.type.BasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType;
@ -2349,13 +2349,11 @@ public class ModelBinder {
Map<String,String> parameters,
Any.MetaValue discriminatorMapping) {
final BootstrapContext bootstrapContext = metadataBuildingContext.getBootstrapContext();
final TypeConfiguration typeConfiguration = bootstrapContext.getTypeConfiguration();
if ( isEmpty( parameters ) ) {
// can use a standard one
final BasicType<?> basicTypeByName = bootstrapContext
.getTypeConfiguration()
.getBasicTypeRegistry()
.getRegisteredType( typeName );
final BasicType<?> basicTypeByName = typeConfiguration.getBasicTypeRegistry().getRegisteredType( typeName );
if ( basicTypeByName != null ) {
return basicTypeByName;
}
@ -2368,7 +2366,7 @@ public class ModelBinder {
parameters,
null,
metadataBuildingContext,
bootstrapContext.getTypeConfiguration().getCurrentBaseSqlTypeIndicators()
typeConfiguration.getCurrentBaseSqlTypeIndicators()
);
if ( resolution.getCombinedTypeParameters() != null ) {
@ -2377,56 +2375,50 @@ public class ModelBinder {
return resolution.getLegacyResolvedBasicType();
}
else {
final ClassLoaderService classLoaderService =
bootstrapContext.getServiceRegistry().requireService( ClassLoaderService.class );
try {
final Object typeInstance = typeInstance( typeName, classLoaderService.classForName( typeName ) );
final ClassLoaderService classLoaderService = bootstrapContext
.getServiceRegistry()
.getService( ClassLoaderService.class );
try {
final Class<?> typeJavaType = classLoaderService.classForName( typeName );
final Object typeInstance;
if ( metadataBuildingContext.getBuildingOptions().disallowExtensionsInCdi() ) {
typeInstance = FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( typeJavaType );
}
else {
final ManagedBeanRegistry beanRegistry = bootstrapContext
.getServiceRegistry()
.getService( ManagedBeanRegistry.class );
final String beanName = typeName + ":" + TypeDefinition.NAME_COUNTER.getAndIncrement();
final ManagedBean<?> bean = beanRegistry.getBean( beanName, typeJavaType );
typeInstance = bean.getBeanInstance();
}
if ( typeInstance instanceof ParameterizedType ) {
if ( parameters != null ) {
Properties properties = new Properties();
properties.putAll( parameters );
( (ParameterizedType) typeInstance ).setParameterValues( properties );
if ( typeInstance instanceof ParameterizedType ) {
if ( parameters != null ) {
Properties properties = new Properties();
properties.putAll( parameters );
( (ParameterizedType) typeInstance ).setParameterValues( properties );
}
}
if ( typeInstance instanceof UserType ) {
return new CustomType<>( (UserType<?>) typeInstance, typeConfiguration);
}
return (BasicType<?>) typeInstance;
}
catch (ClassLoadingException e) {
log.debugf( "Unable to load explicit any-discriminator type name as Java Class - %s", typeName );
}
if ( typeInstance instanceof UserType ) {
//noinspection unchecked
return new CustomType<>(
(UserType<Object>) typeInstance,
bootstrapContext.getTypeConfiguration()
);
}
assert typeInstance instanceof BasicType;
return (BasicType<?>) typeInstance;
}
catch (ClassLoadingException e) {
log.debugf( "Unable to load explicit any-discriminator type name as Java Class - %s", typeName );
throw new org.hibernate.MappingException(
String.format(
Locale.ROOT,
"Unable to resolve explicit any-discriminator type name - %s",
typeName
)
);
}
}
throw new org.hibernate.MappingException(
String.format(
Locale.ROOT,
"Unable to resolve explicit any-discriminator type name - %s",
typeName
)
);
private Object typeInstance(String typeName, Class<?> typeJavaType) {
if ( metadataBuildingContext.getBuildingOptions().disallowExtensionsInCdi() ) {
return FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( typeJavaType );
}
else {
final String beanName = typeName + ":" + TypeDefinition.NAME_COUNTER.getAndIncrement();
return metadataBuildingContext.getBootstrapContext()
.getServiceRegistry().requireService( ManagedBeanRegistry.class )
.getBean( beanName, typeJavaType ).getBeanInstance();
}
}
private void prepareValueTypeViaReflection(

View File

@ -28,8 +28,7 @@ public class BasicTypeRegistration {
}
public BasicTypeRegistration(UserType<?> type, String[] keys, TypeConfiguration typeConfiguration) {
//noinspection unchecked
this( new CustomType<>( (UserType<Object>) type, keys, typeConfiguration ), keys );
this( new CustomType<>( type, keys, typeConfiguration ), keys );
}
public BasicType<?> getBasicType() {

View File

@ -250,7 +250,7 @@ public final class ReflectHelper {
String name,
ClassLoaderService classLoaderService) throws MappingException {
try {
Class clazz = classLoaderService.classForName( className );
Class<?> clazz = classLoaderService.classForName( className );
return getter( clazz, name ).getReturnType();
}
catch ( ClassLoadingException e ) {
@ -368,7 +368,7 @@ public final class ReflectHelper {
try {
constructor = clazz.getDeclaredConstructor( constructorArgs );
try {
ReflectHelper.ensureAccessibility( constructor );
ensureAccessibility( constructor );
}
catch ( SecurityException e ) {
constructor = null;
@ -425,11 +425,9 @@ public final class ReflectHelper {
}
public static void ensureAccessibility(AccessibleObject accessibleObject) {
if ( accessibleObject.isAccessible() ) {
return;
if ( !accessibleObject.isAccessible() ) {
accessibleObject.setAccessible( true );
}
accessibleObject.setAccessible( true );
}
private static Field locateField(Class clazz, String propertyName) {

View File

@ -67,6 +67,7 @@ import jakarta.persistence.EnumType;
import jakarta.persistence.TemporalType;
import static java.lang.Boolean.parseBoolean;
import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty;
import static org.hibernate.mapping.MappingHelper.injectParameters;
/**
@ -260,14 +261,14 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
final Selectable column = getColumn();
if ( column == incomingColumn || column.getText().equals( incomingColumn.getText() ) ) {
log.debugf( "Skipping column re-registration: %s.%s", getTable().getName(), column.getText() );
return;
}
// throw new IllegalStateException(
// "BasicValue [" + ownerName + "." + propertyName +
// "] already had column associated: `" + column.getText() +
// "` -> `" + incomingColumn.getText() + "`"
// );
// else {
// throw new IllegalStateException(
// "BasicValue [" + ownerName + "." + propertyName +
// "] already had column associated: `" + column.getText() +
// "` -> `" + incomingColumn.getText() + "`"
// );
// }
}
@Override
@ -390,12 +391,13 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
}
protected Resolution<?> buildResolution() {
Properties typeParameters = getTypeParameters();
final Properties typeParameters = getTypeParameters();
if ( typeParameters != null
&& parseBoolean( typeParameters.getProperty(DynamicParameterizedType.IS_DYNAMIC) )
&& typeParameters.get(DynamicParameterizedType.PARAMETER_TYPE) == null ) {
createParameterImpl();
}
if ( explicitTypeName != null ) {
return interpretExplicitlyNamedType(
explicitTypeName,
@ -410,108 +412,115 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
);
}
if ( isVersion() ) {
return VersionResolution.from( implicitJavaTypeAccess, timeZoneStorageType, getBuildingContext() );
}
// determine JavaType if we can
final BasicJavaType explicitJavaType = explicitJavaTypeAccess == null ? null
: explicitJavaTypeAccess.apply( getTypeConfiguration() );
final BasicJavaType<?> explicitJavaType =
explicitJavaTypeAccess == null ? null : explicitJavaTypeAccess.apply( getTypeConfiguration() );
final JavaType<?> javaType = determineJavaType( explicitJavaType );
final ConverterDescriptor attributeConverterDescriptor = getAttributeConverterDescriptor();
final Selectable column = getColumn();
if ( attributeConverterDescriptor != null ) {
final ManagedBeanRegistry managedBeanRegistry = getServiceRegistry().getService( ManagedBeanRegistry.class );
return attributeConverterDescriptor != null
? converterResolution( javaType, attributeConverterDescriptor )
: resolution( explicitJavaType, javaType );
}
final NamedConverterResolution<?> converterResolution = NamedConverterResolution.from(
attributeConverterDescriptor,
explicitJavaTypeAccess,
explicitJdbcTypeAccess,
explicitMutabilityPlanAccess,
this,
new JpaAttributeConverterCreationContext() {
@Override
public ManagedBeanRegistry getManagedBeanRegistry() {
return managedBeanRegistry;
}
@Override
public TypeConfiguration getTypeConfiguration() {
return BasicValue.this.getTypeConfiguration();
}
},
getBuildingContext()
);
if ( javaType instanceof BasicPluralJavaType<?>
&& !attributeConverterDescriptor.getDomainValueResolvedType()
.getErasedType()
.isAssignableFrom( javaType.getJavaTypeClass() ) ) {
// In this case, the converter applies to the element of a BasicPluralJavaType
final BasicPluralJavaType<?> containerJtd = (BasicPluralJavaType<?>) javaType;
final BasicType registeredElementType = converterResolution.getLegacyResolvedBasicType();
final BasicType<?> registeredType = registeredElementType == null ? null
: containerJtd.resolveType(
getTypeConfiguration(),
getDialect(),
registeredElementType,
column instanceof ColumnTypeInformation ? (ColumnTypeInformation) column : null,
this
);
if ( registeredType != null ) {
getTypeConfiguration().getBasicTypeRegistry().register( registeredType );
return new InferredBasicValueResolution(
registeredType,
registeredType.getJavaTypeDescriptor(),
registeredType.getJavaTypeDescriptor(),
registeredType.getJdbcType(),
registeredType,
null
);
}
}
return converterResolution;
private Resolution<?> resolution(BasicJavaType explicitJavaType, JavaType<?> javaType) {
final JavaType<?> basicJavaType;
final JdbcType jdbcType;
if ( explicitJdbcTypeAccess != null ) {
final TypeConfiguration typeConfiguration = getTypeConfiguration();
jdbcType = explicitJdbcTypeAccess.apply( typeConfiguration );
basicJavaType = javaType == null && jdbcType != null
? jdbcType.getJdbcRecommendedJavaTypeMapping(null, null, typeConfiguration)
: javaType;
}
else {
jdbcType = null;
basicJavaType = javaType;
}
final JdbcType jdbcType = explicitJdbcTypeAccess != null
? explicitJdbcTypeAccess.apply( getTypeConfiguration() )
: null;
final JavaType<?> basicJavaType = javaType == null && jdbcType != null
? jdbcType.getJdbcRecommendedJavaTypeMapping( null, null, getTypeConfiguration() )
: javaType;
if ( basicJavaType == null ) {
throw new MappingException( "Unable to determine JavaType to use : " + this );
}
final TypeDefinition autoAppliedTypeDef = basicJavaType instanceof BasicJavaType<?>
? getBuildingContext().getTypeDefinitionRegistry().resolveAutoApplied( (BasicJavaType<?>) basicJavaType )
: null;
if ( autoAppliedTypeDef != null
if ( basicJavaType instanceof BasicJavaType<?>
&& ( !basicJavaType.getJavaTypeClass().isEnum() || enumerationStyle == null ) ) {
log.debug( "BasicValue resolution matched auto-applied type-definition" );
return autoAppliedTypeDef.resolve( typeParameters, null, getBuildingContext(), this );
final TypeDefinition autoAppliedTypeDef =
getBuildingContext().getTypeDefinitionRegistry()
.resolveAutoApplied( (BasicJavaType<?>) basicJavaType );
if ( autoAppliedTypeDef != null ) {
log.debug("BasicValue resolution matched auto-applied type-definition");
return autoAppliedTypeDef.resolve( getTypeParameters(), null, getBuildingContext(), this );
}
}
else {
return InferredBasicValueResolver.from(
explicitJavaType,
jdbcType,
resolvedJavaType,
this::determineReflectedJavaType,
explicitMutabilityPlanAccess,
this,
getTable(),
column,
ownerName,
propertyName,
getBuildingContext()
return InferredBasicValueResolver.from(
explicitJavaType,
jdbcType,
resolvedJavaType,
this::determineReflectedJavaType,
explicitMutabilityPlanAccess,
this,
getTable(),
getColumn(),
ownerName,
propertyName,
getBuildingContext()
);
}
private Resolution<?> converterResolution(JavaType<?> javaType, ConverterDescriptor attributeConverterDescriptor) {
final ManagedBeanRegistry managedBeanRegistry = getServiceRegistry().getService( ManagedBeanRegistry.class );
final NamedConverterResolution<?> converterResolution = NamedConverterResolution.from(
attributeConverterDescriptor,
explicitJavaTypeAccess,
explicitJdbcTypeAccess,
explicitMutabilityPlanAccess,
this,
new JpaAttributeConverterCreationContext() {
@Override
public ManagedBeanRegistry getManagedBeanRegistry() {
return managedBeanRegistry;
}
@Override
public TypeConfiguration getTypeConfiguration() {
return BasicValue.this.getTypeConfiguration();
}
},
getBuildingContext()
);
if ( javaType instanceof BasicPluralJavaType<?>
&& !attributeConverterDescriptor.getDomainValueResolvedType().getErasedType()
.isAssignableFrom( javaType.getJavaTypeClass() ) ) {
// In this case, the converter applies to the element of a BasicPluralJavaType
final BasicPluralJavaType<?> containerJtd = (BasicPluralJavaType<?>) javaType;
final BasicType registeredElementType = converterResolution.getLegacyResolvedBasicType();
final Selectable column = getColumn();
final BasicType<?> registeredType = registeredElementType == null ? null
: containerJtd.resolveType(
getTypeConfiguration(),
getDialect(),
registeredElementType,
column instanceof ColumnTypeInformation ? (ColumnTypeInformation) column : null,
this
);
if ( registeredType != null ) {
getTypeConfiguration().getBasicTypeRegistry().register( registeredType );
return new InferredBasicValueResolution(
registeredType,
registeredType.getJavaTypeDescriptor(),
registeredType.getJavaTypeDescriptor(),
registeredType.getJdbcType(),
registeredType,
null
);
}
}
return converterResolution;
}
private JavaType<?> determineJavaType(JavaType<?> explicitJavaType) {
@ -549,7 +558,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
impliedJavaType = ReflectHelper.reflectedPropertyType(
ownerName,
propertyName,
getServiceRegistry().getService( ClassLoaderService.class )
getServiceRegistry().requireService( ClassLoaderService.class )
);
}
else {
@ -666,7 +675,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
// see if the name is a UserType or BasicType implementor class name
final ClassLoaderService cls = serviceRegistry.getService( ClassLoaderService.class );
final ClassLoaderService cls = serviceRegistry.requireService( ClassLoaderService.class );
try {
final Class<?> typeNamedClass = cls.classForName( name );
@ -779,7 +788,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
if ( StringHelper.isNotEmpty( typeName ) ) {
if ( typeName.startsWith( ConverterDescriptor.TYPE_NAME_PREFIX ) ) {
final String converterClassName = typeName.substring( ConverterDescriptor.TYPE_NAME_PREFIX.length() );
final ClassLoaderService cls = getServiceRegistry().getService( ClassLoaderService.class );
final ClassLoaderService cls = getServiceRegistry().requireService( ClassLoaderService.class );
try {
final Class<AttributeConverter<?,?>> converterClass = cls.classForName( converterClassName );
setAttributeConverterDescriptor( new ClassBasedConverterDescriptor(
@ -803,65 +812,70 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
private static int COUNTER;
public <T extends UserType<?>> void setExplicitCustomType(Class<T> explicitCustomType) {
public void setExplicitCustomType(Class<? extends UserType<?>> explicitCustomType) {
if ( explicitCustomType != null ) {
if ( resolution != null ) {
throw new UnsupportedOperationException( "Unsupported attempt to set an explicit-custom-type when value is already resolved" );
}
final BeanInstanceProducer instanceProducer =
getBuildingContext().getBootstrapContext().getCustomTypeProducer();
final Properties properties = new Properties();
if ( CollectionHelper.isNotEmpty( getTypeParameters() ) ) {
properties.putAll( getTypeParameters() );
}
if ( CollectionHelper.isNotEmpty( explicitLocalTypeParams ) ) {
properties.putAll( explicitLocalTypeParams );
}
final T typeInstance;
if ( getBuildingContext().getBuildingOptions().disallowExtensionsInCdi() ) {
typeInstance = FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( explicitCustomType );
}
else {
final boolean hasParameters = CollectionHelper.isNotEmpty( properties );
final ManagedBean<T> typeBean;
if ( hasParameters ) {
final String name = explicitCustomType.getName() + COUNTER++;
typeBean = getServiceRegistry().getService( ManagedBeanRegistry.class )
.getBean( name, explicitCustomType, instanceProducer );
}
else {
typeBean = getServiceRegistry().getService( ManagedBeanRegistry.class )
.getBean( explicitCustomType, instanceProducer );
}
typeInstance = typeBean.getBeanInstance();
resolution = new UserTypeResolution<>(
new CustomType<>(
getConfiguredUserTypeBean( explicitCustomType, getCustomTypeProperties() ),
getTypeConfiguration()
),
null,
getCustomTypeProperties()
);
}
}
}
if ( typeInstance instanceof TypeConfigurationAware ) {
( (TypeConfigurationAware) typeInstance ).setTypeConfiguration( getTypeConfiguration() );
}
private Properties getCustomTypeProperties() {
final Properties properties = new Properties();
if ( isNotEmpty( getTypeParameters() ) ) {
properties.putAll( getTypeParameters() );
}
if ( isNotEmpty( explicitLocalTypeParams ) ) {
properties.putAll( explicitLocalTypeParams );
}
return properties;
}
if ( typeInstance instanceof DynamicParameterizedType ) {
if (parseBoolean(properties.getProperty(DynamicParameterizedType.IS_DYNAMIC))) {
if (properties.get(DynamicParameterizedType.PARAMETER_TYPE) == null) {
final DynamicParameterizedType.ParameterType parameterType = makeParameterImpl();
properties.put(DynamicParameterizedType.PARAMETER_TYPE, parameterType);
}
private UserType<?> getConfiguredUserTypeBean(Class<? extends UserType<?>> explicitCustomType, Properties properties) {
final UserType<?> typeInstance =
getBuildingContext().getBuildingOptions().disallowExtensionsInCdi()
? FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( explicitCustomType )
: getUserTypeBean( explicitCustomType, properties ).getBeanInstance();
if ( typeInstance instanceof TypeConfigurationAware ) {
final TypeConfigurationAware configurationAware = (TypeConfigurationAware) typeInstance;
configurationAware.setTypeConfiguration( getTypeConfiguration() );
}
if ( typeInstance instanceof DynamicParameterizedType ) {
if ( parseBoolean( properties.getProperty( DynamicParameterizedType.IS_DYNAMIC ) ) ) {
if ( properties.get( DynamicParameterizedType.PARAMETER_TYPE ) == null ) {
properties.put( DynamicParameterizedType.PARAMETER_TYPE, makeParameterImpl() );
}
}
}
injectParameters( typeInstance, properties );
// envers - grr
setTypeParameters( properties );
injectParameters( typeInstance, properties);
// envers - grr
setTypeParameters( properties );
this.resolution = new UserTypeResolution(
new CustomType<>( (UserType<?>) typeInstance, getTypeConfiguration() ),
null,
properties
);
return typeInstance;
}
private <T> ManagedBean<T> getUserTypeBean(Class<T> explicitCustomType, Properties properties) {
final BeanInstanceProducer producer = getBuildingContext().getBootstrapContext().getCustomTypeProducer();
final ManagedBeanRegistry registry = getServiceRegistry().requireService( ManagedBeanRegistry.class );
if ( isNotEmpty( properties ) ) {
final String name = explicitCustomType.getName() + COUNTER++;
return registry.getBean( name, explicitCustomType, producer );
}
else {
return registry.getBean( explicitCustomType, producer );
}
}
@ -882,9 +896,9 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
@Internal
public boolean isDisallowedWrapperArray() {
return getBuildingContext().getBuildingOptions().getWrapperArrayHandling() == WrapperArrayHandling.DISALLOW
&& !isLob()
&& ( explicitJavaTypeAccess == null || explicitJavaTypeAccess.apply( getTypeConfiguration() ) == null )
&& isWrapperByteOrCharacterArray();
&& !isLob()
&& ( explicitJavaTypeAccess == null || explicitJavaTypeAccess.apply( getTypeConfiguration() ) == null )
&& isWrapperByteOrCharacterArray();
}
private boolean isWrapperByteOrCharacterArray() {

View File

@ -957,6 +957,7 @@ public abstract class SimpleValue implements KeyValue {
throw new MappingException( "Could not create DynamicParameterizedType for type: " + typeName, e );
}
}
public DynamicParameterizedType.ParameterType makeParameterImpl() {
try {
final String[] columnNames = new String[ columns.size() ];

View File

@ -113,16 +113,19 @@ public class ResultMementoBasicStandard implements ResultMementoBasic {
else {
final JavaTypeRegistry jtdRegistry = typeConfiguration.getJavaTypeRegistry();
final JavaType<Object> registeredJtd = jtdRegistry.getDescriptor( definition.type() );
final ManagedBeanRegistry beanRegistry = sessionFactory.getServiceRegistry().getService( ManagedBeanRegistry.class );
final ManagedBeanRegistry beanRegistry =
sessionFactory.getServiceRegistry().requireService( ManagedBeanRegistry.class );
if ( BasicType.class.isAssignableFrom( registeredJtd.getJavaTypeClass() ) ) {
final ManagedBean<BasicType<?>> typeBean = (ManagedBean) beanRegistry.getBean( registeredJtd.getJavaTypeClass() );
final ManagedBean<BasicType<?>> typeBean =
(ManagedBean) beanRegistry.getBean( registeredJtd.getJavaTypeClass() );
explicitType = typeBean.getBeanInstance();
explicitJavaType = explicitType.getJavaTypeDescriptor();
}
else if ( UserType.class.isAssignableFrom( registeredJtd.getJavaTypeClass() ) ) {
final ManagedBean<UserType<?>> userTypeBean = (ManagedBean) beanRegistry.getBean( registeredJtd.getJavaTypeClass() );
final ManagedBean<UserType<?>> userTypeBean =
(ManagedBean) beanRegistry.getBean( registeredJtd.getJavaTypeClass() );
// todo (6.0) : is this the best approach? or should we keep a Class<? extends UserType> -> @Type mapping somewhere?
explicitType = new CustomType<>( (UserType<Object>) userTypeBean.getBeanInstance(), typeConfiguration );
explicitType = new CustomType<>( userTypeBean.getBeanInstance(), typeConfiguration );
explicitJavaType = explicitType.getJavaTypeDescriptor();
}
else {

View File

@ -68,7 +68,8 @@ public class CustomType<J>
this( userType, ArrayHelper.EMPTY_STRING_ARRAY, typeConfiguration );
}
public CustomType(UserType<J> userType, String[] registrationKeys, TypeConfiguration typeConfiguration) throws MappingException {
public CustomType(UserType<J> userType, String[] registrationKeys, TypeConfiguration typeConfiguration)
throws MappingException {
this.userType = userType;
name = userType.getClass().getName();