HHH-16781 @JavaType annotation is ignored when basic type is already registered for the preferred JdbcType

This commit is contained in:
Christian Beikov 2023-08-16 15:51:19 +02:00
parent 02c11514fc
commit ccb093e553
6 changed files with 51 additions and 58 deletions

View File

@ -40,7 +40,7 @@ import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry; import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.resource.beans.spi.BeanInstanceProducer; import org.hibernate.resource.beans.spi.BeanInstanceProducer;
import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.jandex.IndexView; import org.jboss.jandex.IndexView;
@ -220,17 +220,17 @@ public class BootstrapContextImpl implements BootstrapContext {
return cacheRegionDefinitions == null ? Collections.emptyList() : cacheRegionDefinitions; return cacheRegionDefinitions == null ? Collections.emptyList() : cacheRegionDefinitions;
} }
private final Map<String,BasicTypeImpl<?>> adHocBasicTypeRegistrations = new HashMap<>(); private final Map<String,BasicType<?>> adHocBasicTypeRegistrations = new HashMap<>();
@Override @Override
public void registerAdHocBasicType(BasicTypeImpl<?> basicType) { public void registerAdHocBasicType(BasicType<?> basicType) {
adHocBasicTypeRegistrations.put( basicType.getName(), basicType ); adHocBasicTypeRegistrations.put( basicType.getName(), basicType );
} }
@Override @Override
public <T> BasicTypeImpl<T> resolveAdHocBasicType(String key) { public <T> BasicType<T> resolveAdHocBasicType(String key) {
//noinspection unchecked //noinspection unchecked
return (BasicTypeImpl<T>) adHocBasicTypeRegistrations.get( key ); return (BasicType<T>) adHocBasicTypeRegistrations.get( key );
} }
@Override @Override

View File

@ -365,7 +365,8 @@ public class InferredBasicValueResolver {
jtd = reflectedJtd.resolveTypeForPrecision( requestedTemporalPrecision, typeConfiguration ); jtd = reflectedJtd.resolveTypeForPrecision( requestedTemporalPrecision, typeConfiguration );
} }
else { else {
jtd = reflectedJtd; // Avoid using the DateJavaType and prefer the JdbcTimestampJavaType
jtd = reflectedJtd.resolveTypeForPrecision( reflectedJtd.getPrecision(), typeConfiguration );
} }
final BasicType<T> jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( jtd, explicitJdbcType ); final BasicType<T> jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( jtd, explicitJdbcType );
@ -394,7 +395,8 @@ public class InferredBasicValueResolver {
} }
else { else {
basicType = typeConfiguration.getBasicTypeRegistry().resolve( basicType = typeConfiguration.getBasicTypeRegistry().resolve(
reflectedJtd, // Avoid using the DateJavaType and prefer the JdbcTimestampJavaType
reflectedJtd.resolveTypeForPrecision( reflectedJtd.getPrecision(), typeConfiguration ),
reflectedJtd.getRecommendedJdbcType( stdIndicators ) reflectedJtd.getRecommendedJdbcType( stdIndicators )
); );
} }

View File

@ -27,7 +27,7 @@ import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry; import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.resource.beans.spi.BeanInstanceProducer; import org.hibernate.resource.beans.spi.BeanInstanceProducer;
import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.jandex.IndexView; import org.jboss.jandex.IndexView;
@ -232,10 +232,10 @@ public interface BootstrapContext {
/** /**
* To support Envers. * To support Envers.
*/ */
void registerAdHocBasicType(BasicTypeImpl<?> basicType); void registerAdHocBasicType(BasicType<?> basicType);
/** /**
* To support Envers. * To support Envers.
*/ */
<T> BasicTypeImpl<T> resolveAdHocBasicType(String key); <T> BasicType<T> resolveAdHocBasicType(String key);
} }

View File

@ -625,7 +625,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
// } // }
if ( name.startsWith( BasicTypeImpl.EXTERNALIZED_PREFIX ) ) { if ( name.startsWith( BasicTypeImpl.EXTERNALIZED_PREFIX ) ) {
final BasicTypeImpl<Object> basicType = context.getBootstrapContext().resolveAdHocBasicType( name ); final BasicType<Object> basicType = context.getBootstrapContext().resolveAdHocBasicType( name );
return new NamedBasicTypeResolution<>( return new NamedBasicTypeResolution<>(
basicType.getJavaTypeDescriptor(), basicType.getJavaTypeDescriptor(),
basicType, basicType,

View File

@ -146,9 +146,9 @@ public class BasicTypeRegistry implements Serializable {
return resolve( typeConfiguration.getJavaTypeRegistry().getDescriptor( javaType ), sqlTypeCode ); return resolve( typeConfiguration.getJavaTypeRegistry().getDescriptor( javaType ), sqlTypeCode );
} }
public <J> BasicType<J> resolve(JavaType<J> jtdToUse, int sqlTypeCode) { public <J> BasicType<J> resolve(JavaType<J> javaType, int sqlTypeCode) {
return resolve( return resolve(
jtdToUse, javaType,
typeConfiguration.getJdbcTypeRegistry().getDescriptor( sqlTypeCode ) typeConfiguration.getJdbcTypeRegistry().getDescriptor( sqlTypeCode )
); );
} }
@ -157,32 +157,19 @@ public class BasicTypeRegistry implements Serializable {
* Find an existing {@link BasicType} registration for the given {@link JavaType} * Find an existing {@link BasicType} registration for the given {@link JavaType}
* descriptor and {@link JdbcType} descriptor combo or create (and register) one. * descriptor and {@link JdbcType} descriptor combo or create (and register) one.
*/ */
public <J> BasicType<J> resolve(JavaType<J> jtdToUse, JdbcType stdToUse) { public <J> BasicType<J> resolve(JavaType<J> javaType, JdbcType jdbcType) {
return resolve( return resolve(
jtdToUse, javaType,
stdToUse, jdbcType,
() -> { () -> new BasicTypeImpl<>( javaType, jdbcType )
final BasicTypeImpl<J> basicType = new BasicTypeImpl<>( jtdToUse, stdToUse );
// if we are still building mappings, register this ad-hoc type
// via a unique code. this is to support envers
try {
typeConfiguration.getMetadataBuildingContext().getBootstrapContext()
.registerAdHocBasicType( basicType );
}
catch (Exception ignore) {
}
return basicType;
}
); );
} }
public <J> BasicType<J> resolve(JavaType<J> jtdToUse, JdbcType stdToUse, String baseTypeName) { public <J> BasicType<J> resolve(JavaType<J> javaType, JdbcType jdbcType, String baseTypeName) {
return resolve( return resolve(
jtdToUse, javaType,
stdToUse, jdbcType,
() -> new NamedBasicTypeImpl<>( jtdToUse, stdToUse, baseTypeName ) () -> new NamedBasicTypeImpl<>( javaType, jdbcType, baseTypeName )
); );
} }
@ -190,30 +177,34 @@ public class BasicTypeRegistry implements Serializable {
* Find an existing BasicType registration for the given JavaType and * Find an existing BasicType registration for the given JavaType and
* JdbcType combo or create (and register) one. * JdbcType combo or create (and register) one.
*/ */
public <J> BasicType<J> resolve(JavaType<J> jtdToUse, JdbcType stdToUse, Supplier<BasicType<J>> creator) { public <J> BasicType<J> resolve(JavaType<J> javaType, JdbcType jdbcType, Supplier<BasicType<J>> creator) {
final Map<JavaType<?>, BasicType<?>> typeByJtdForStd = registryValues.computeIfAbsent( final Map<JavaType<?>, BasicType<?>> typeByJavaTypeForJdbcType = registryValues.computeIfAbsent(
stdToUse, jdbcType,
sqlTypeDescriptor -> new ConcurrentHashMap<>() key -> new ConcurrentHashMap<>()
); );
final BasicType<?> foundBasicType = typeByJtdForStd.get( jtdToUse ); final BasicType<?> foundBasicType = typeByJavaTypeForJdbcType.get( javaType );
if ( foundBasicType != null ) { if ( foundBasicType != null ) {
//noinspection unchecked //noinspection unchecked
return (BasicType<J>) foundBasicType; return (BasicType<J>) foundBasicType;
} }
// Before simply creating the type, we try to find if there is a registered type for this java type, // Before simply creating the type, we try to find if there is a registered type for this java type,
// and if so, if the jdbc type descriptor matches. Unless it does, we at least reuse the name // and if so, if the jdbc type descriptor matches. Unless it does, we at least reuse the name
final BasicType<J> basicType = getRegisteredType( jtdToUse.getJavaType() ); final BasicType<J> registeredType = getRegisteredType( javaType.getJavaType() );
if ( basicType != null ) { if ( registeredType != null && registeredType.getJdbcType() == jdbcType && registeredType.getMappedJavaType() == javaType ) {
if ( basicType.getJdbcType() == stdToUse ) { return registeredType;
return basicType;
}
else {
return new NamedBasicTypeImpl<>( jtdToUse, stdToUse, basicType.getName() );
}
} }
final BasicType<J> createdBasicType = creator.get(); final BasicType<J> createdBasicType = creator.get();
typeByJtdForStd.put( jtdToUse, createdBasicType ); typeByJavaTypeForJdbcType.put( javaType, createdBasicType );
// if we are still building mappings, register this ad-hoc type
// via a unique code. this is to support envers
try {
typeConfiguration.getMetadataBuildingContext().getBootstrapContext()
.registerAdHocBasicType( createdBasicType );
}
catch (Exception ignore) {
}
return createdBasicType; return createdBasicType;
} }
@ -250,12 +241,12 @@ public class BasicTypeRegistry implements Serializable {
} }
private void applyOrOverwriteEntry(BasicType<?> type) { private void applyOrOverwriteEntry(BasicType<?> type) {
final Map<JavaType<?>, BasicType<?>> mappingsForStdToUse = registryValues.computeIfAbsent( final Map<JavaType<?>, BasicType<?>> typeByJavaTypeForJdbcType = registryValues.computeIfAbsent(
type.getJdbcType(), type.getJdbcType(),
sqlTypeDescriptor -> new ConcurrentHashMap<>() jdbcType -> new ConcurrentHashMap<>()
); );
final BasicType<?> existing = mappingsForStdToUse.put( type.getMappedJavaType(), type ); final BasicType<?> existing = typeByJavaTypeForJdbcType.put( type.getMappedJavaType(), type );
if ( existing != null ) { if ( existing != null ) {
LOG.debugf( LOG.debugf(
"BasicTypeRegistry registration overwritten (%s + %s); previous =`%s`", "BasicTypeRegistry registration overwritten (%s + %s); previous =`%s`",
@ -350,12 +341,12 @@ public class BasicTypeRegistry implements Serializable {
} }
private void primeRegistryEntry(BasicType<?> type) { private void primeRegistryEntry(BasicType<?> type) {
final Map<JavaType<?>, BasicType<?>> mappingsForStdToUse = registryValues.computeIfAbsent( final Map<JavaType<?>, BasicType<?>> typeByJavaTypeForJdbcType = registryValues.computeIfAbsent(
type.getJdbcType(), type.getJdbcType(),
sqlTypeDescriptor -> new ConcurrentHashMap<>() jdbcType -> new ConcurrentHashMap<>()
); );
final BasicType<?> existing = mappingsForStdToUse.get( type.getMappedJavaType() ); final BasicType<?> existing = typeByJavaTypeForJdbcType.get( type.getMappedJavaType() );
if ( existing != null ) { if ( existing != null ) {
LOG.debugf( LOG.debugf(
@ -366,7 +357,7 @@ public class BasicTypeRegistry implements Serializable {
); );
} }
else { else {
mappingsForStdToUse.put( type.getMappedJavaType(), type ); typeByJavaTypeForJdbcType.put( type.getMappedJavaType(), type );
} }
} }

View File

@ -29,7 +29,7 @@ import org.hibernate.metamodel.spi.ManagedTypeRepresentationResolver;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry; import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.resource.beans.spi.BeanInstanceProducer; import org.hibernate.resource.beans.spi.BeanInstanceProducer;
import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.jandex.IndexView; import org.jboss.jandex.IndexView;
@ -159,11 +159,11 @@ public class BootstrapContextImpl implements BootstrapContext {
} }
@Override @Override
public void registerAdHocBasicType(BasicTypeImpl<?> basicType) { public void registerAdHocBasicType(BasicType<?> basicType) {
} }
@Override @Override
public <T> BasicTypeImpl<T> resolveAdHocBasicType(String key) { public <T> BasicType<T> resolveAdHocBasicType(String key) {
return null; return null;
} }