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.SqmFunctionRegistry;
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.jboss.jandex.IndexView;
@ -220,17 +220,17 @@ public class BootstrapContextImpl implements BootstrapContext {
return cacheRegionDefinitions == null ? Collections.emptyList() : cacheRegionDefinitions;
}
private final Map<String,BasicTypeImpl<?>> adHocBasicTypeRegistrations = new HashMap<>();
private final Map<String,BasicType<?>> adHocBasicTypeRegistrations = new HashMap<>();
@Override
public void registerAdHocBasicType(BasicTypeImpl<?> basicType) {
public void registerAdHocBasicType(BasicType<?> basicType) {
adHocBasicTypeRegistrations.put( basicType.getName(), basicType );
}
@Override
public <T> BasicTypeImpl<T> resolveAdHocBasicType(String key) {
public <T> BasicType<T> resolveAdHocBasicType(String key) {
//noinspection unchecked
return (BasicTypeImpl<T>) adHocBasicTypeRegistrations.get( key );
return (BasicType<T>) adHocBasicTypeRegistrations.get( key );
}
@Override

View File

@ -365,7 +365,8 @@ public class InferredBasicValueResolver {
jtd = reflectedJtd.resolveTypeForPrecision( requestedTemporalPrecision, typeConfiguration );
}
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 );
@ -394,7 +395,8 @@ public class InferredBasicValueResolver {
}
else {
basicType = typeConfiguration.getBasicTypeRegistry().resolve(
reflectedJtd,
// Avoid using the DateJavaType and prefer the JdbcTimestampJavaType
reflectedJtd.resolveTypeForPrecision( reflectedJtd.getPrecision(), typeConfiguration ),
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.SqmFunctionRegistry;
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.jboss.jandex.IndexView;
@ -232,10 +232,10 @@ public interface BootstrapContext {
/**
* To support Envers.
*/
void registerAdHocBasicType(BasicTypeImpl<?> basicType);
void registerAdHocBasicType(BasicType<?> basicType);
/**
* 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 ) ) {
final BasicTypeImpl<Object> basicType = context.getBootstrapContext().resolveAdHocBasicType( name );
final BasicType<Object> basicType = context.getBootstrapContext().resolveAdHocBasicType( name );
return new NamedBasicTypeResolution<>(
basicType.getJavaTypeDescriptor(),
basicType,

View File

@ -146,9 +146,9 @@ public class BasicTypeRegistry implements Serializable {
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(
jtdToUse,
javaType,
typeConfiguration.getJdbcTypeRegistry().getDescriptor( sqlTypeCode )
);
}
@ -157,32 +157,19 @@ public class BasicTypeRegistry implements Serializable {
* Find an existing {@link BasicType} registration for the given {@link JavaType}
* 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(
jtdToUse,
stdToUse,
() -> {
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;
}
javaType,
jdbcType,
() -> new BasicTypeImpl<>( javaType, jdbcType )
);
}
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(
jtdToUse,
stdToUse,
() -> new NamedBasicTypeImpl<>( jtdToUse, stdToUse, baseTypeName )
javaType,
jdbcType,
() -> new NamedBasicTypeImpl<>( javaType, jdbcType, baseTypeName )
);
}
@ -190,30 +177,34 @@ public class BasicTypeRegistry implements Serializable {
* Find an existing BasicType registration for the given JavaType and
* JdbcType combo or create (and register) one.
*/
public <J> BasicType<J> resolve(JavaType<J> jtdToUse, JdbcType stdToUse, Supplier<BasicType<J>> creator) {
final Map<JavaType<?>, BasicType<?>> typeByJtdForStd = registryValues.computeIfAbsent(
stdToUse,
sqlTypeDescriptor -> new ConcurrentHashMap<>()
public <J> BasicType<J> resolve(JavaType<J> javaType, JdbcType jdbcType, Supplier<BasicType<J>> creator) {
final Map<JavaType<?>, BasicType<?>> typeByJavaTypeForJdbcType = registryValues.computeIfAbsent(
jdbcType,
key -> new ConcurrentHashMap<>()
);
final BasicType<?> foundBasicType = typeByJtdForStd.get( jtdToUse );
final BasicType<?> foundBasicType = typeByJavaTypeForJdbcType.get( javaType );
if ( foundBasicType != null ) {
//noinspection unchecked
return (BasicType<J>) foundBasicType;
}
// 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
final BasicType<J> basicType = getRegisteredType( jtdToUse.getJavaType() );
if ( basicType != null ) {
if ( basicType.getJdbcType() == stdToUse ) {
return basicType;
}
else {
return new NamedBasicTypeImpl<>( jtdToUse, stdToUse, basicType.getName() );
}
final BasicType<J> registeredType = getRegisteredType( javaType.getJavaType() );
if ( registeredType != null && registeredType.getJdbcType() == jdbcType && registeredType.getMappedJavaType() == javaType ) {
return registeredType;
}
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;
}
@ -250,12 +241,12 @@ public class BasicTypeRegistry implements Serializable {
}
private void applyOrOverwriteEntry(BasicType<?> type) {
final Map<JavaType<?>, BasicType<?>> mappingsForStdToUse = registryValues.computeIfAbsent(
final Map<JavaType<?>, BasicType<?>> typeByJavaTypeForJdbcType = registryValues.computeIfAbsent(
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 ) {
LOG.debugf(
"BasicTypeRegistry registration overwritten (%s + %s); previous =`%s`",
@ -350,12 +341,12 @@ public class BasicTypeRegistry implements Serializable {
}
private void primeRegistryEntry(BasicType<?> type) {
final Map<JavaType<?>, BasicType<?>> mappingsForStdToUse = registryValues.computeIfAbsent(
final Map<JavaType<?>, BasicType<?>> typeByJavaTypeForJdbcType = registryValues.computeIfAbsent(
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 ) {
LOG.debugf(
@ -366,7 +357,7 @@ public class BasicTypeRegistry implements Serializable {
);
}
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.SqmFunctionRegistry;
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.jboss.jandex.IndexView;
@ -159,11 +159,11 @@ public class BootstrapContextImpl implements BootstrapContext {
}
@Override
public void registerAdHocBasicType(BasicTypeImpl<?> basicType) {
public void registerAdHocBasicType(BasicType<?> basicType) {
}
@Override
public <T> BasicTypeImpl<T> resolveAdHocBasicType(String key) {
public <T> BasicType<T> resolveAdHocBasicType(String key) {
return null;
}