Skip to content

Commit 8afa3ba

Browse files
committed
HHH-19976 Don't adopt AdjustableBasicType name to create derived type
Also, store BasicTypeReferences by java type name and try finding a JavaType/JdbcType match when resolving a BasicType
1 parent aca8b4d commit 8afa3ba

File tree

8 files changed

+235
-85
lines changed

8 files changed

+235
-85
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java

Lines changed: 80 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public static <T> BasicValue.Resolution<T> from(
6464
final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext();
6565
final TypeConfiguration typeConfiguration = bootstrapContext.getTypeConfiguration();
6666

67-
final JavaType<T> reflectedJtd = reflectedJtdResolver.get();
67+
final JavaType<T> reflectedJtd;
6868

6969
// NOTE : the distinction that is made below wrt `explicitJavaType` and `reflectedJtd` is
7070
// needed temporarily to trigger "legacy resolution" versus "ORM6 resolution. Yes, it
@@ -105,7 +105,7 @@ else if ( explicitJdbcType != null ) {
105105
}
106106
}
107107
}
108-
else if ( reflectedJtd != null ) {
108+
else if ( ( reflectedJtd = reflectedJtdResolver.get() ) != null ) {
109109
// we were able to determine the "reflected java-type"
110110
// Use JTD if we know it to apply any specialized resolutions
111111
if ( reflectedJtd instanceof EnumJavaType ) {
@@ -135,59 +135,20 @@ else if ( explicitJdbcType != null ) {
135135
else {
136136
// see if there is a registered BasicType for this JavaType and, if so, use it.
137137
// this mimics the legacy handling
138-
final BasicType registeredType;
139-
if ( reflectedJtd instanceof BasicPluralJavaType<?> ) {
140-
final BasicPluralJavaType<?> containerJtd = (BasicPluralJavaType<?>) reflectedJtd;
141-
final JavaType<?> elementJtd = containerJtd.getElementJavaType();
142-
final BasicType registeredElementType;
143-
if ( elementJtd instanceof EnumJavaType ) {
144-
final BasicValue.Resolution<?> resolution = fromEnum(
145-
(EnumJavaType<?>) elementJtd,
138+
final BasicType registeredType =
139+
registeredType(
146140
explicitJdbcType,
147-
stdIndicators,
148-
bootstrapContext);
149-
registeredElementType = (BasicType<?>) resolution.getJdbcMapping();
150-
}
151-
else if ( isTemporal( elementJtd ) ) {
152-
final BasicValue.Resolution<?> resolution = fromTemporal(
153-
(TemporalJavaType<?>) elementJtd,
154-
null,
155-
null,
156141
explicitMutabilityPlanAccess,
157-
stdIndicators
142+
stdIndicators,
143+
selectable,
144+
reflectedJtd,
145+
bootstrapContext,
146+
buildingContext.getMetadataCollector().getDatabase().getDialect()
158147
);
159-
registeredElementType = resolution.getLegacyResolvedBasicType();
160-
}
161-
else {
162-
registeredElementType = typeConfiguration.getBasicTypeRegistry()
163-
.getRegisteredType( elementJtd.getJavaType() );
164-
}
165-
final ColumnTypeInformation columnTypeInformation;
166-
if ( selectable instanceof ColumnTypeInformation ) {
167-
columnTypeInformation = (ColumnTypeInformation) selectable;
168-
}
169-
else {
170-
columnTypeInformation = null;
171-
}
172-
registeredType = registeredElementType == null ? null : containerJtd.resolveType(
173-
typeConfiguration,
174-
dialect,
175-
resolveSqlTypeIndicators( stdIndicators, registeredElementType, elementJtd ),
176-
columnTypeInformation,
177-
stdIndicators
178-
);
179-
if ( registeredType instanceof BasicPluralType<?, ?> ) {
180-
typeConfiguration.getBasicTypeRegistry().register( registeredType );
181-
}
182-
}
183-
else {
184-
registeredType = typeConfiguration.getBasicTypeRegistry()
185-
.getRegisteredType( reflectedJtd.getJavaType() );
186-
}
187148

188149
if ( registeredType != null ) {
189150
// so here is the legacy resolution
190-
jdbcMapping = resolveSqlTypeIndicators( stdIndicators, registeredType, reflectedJtd );
151+
jdbcMapping = resolveSqlTypeIndicators( stdIndicators, registeredType, registeredType.getJavaTypeDescriptor() );
191152
}
192153
else {
193154
// there was not a "legacy" BasicType registration, so use `JavaType#getRecommendedJdbcType`, if
@@ -273,6 +234,76 @@ else if ( column.getLength() != null ) {
273234
);
274235
}
275236

237+
private static <T> BasicType<?> registeredType(
238+
JdbcType explicitJdbcType,
239+
Function<TypeConfiguration, MutabilityPlan> explicitMutabilityPlanAccess,
240+
JdbcTypeIndicators stdIndicators,
241+
Selectable selectable,
242+
JavaType<T> reflectedJtd,
243+
BootstrapContext bootstrapContext,
244+
Dialect dialect) {
245+
final TypeConfiguration typeConfiguration = bootstrapContext.getTypeConfiguration();
246+
247+
if ( reflectedJtd instanceof BasicPluralJavaType<?> ) {
248+
final BasicPluralJavaType<?> pluralJavaType = (BasicPluralJavaType<?>) reflectedJtd;
249+
final JavaType<?> elementJavaType = pluralJavaType.getElementJavaType();
250+
final BasicType registeredElementType = registeredElementType(
251+
explicitJdbcType,
252+
explicitMutabilityPlanAccess,
253+
stdIndicators,
254+
bootstrapContext,
255+
elementJavaType
256+
);
257+
final BasicType<?> registeredType =
258+
registeredElementType == null
259+
? null
260+
: pluralJavaType.resolveType(
261+
typeConfiguration,
262+
dialect,
263+
resolveSqlTypeIndicators(
264+
stdIndicators,
265+
registeredElementType,
266+
registeredElementType.getJavaTypeDescriptor()
267+
),
268+
selectable instanceof ColumnTypeInformation
269+
? (ColumnTypeInformation) selectable
270+
: null,
271+
stdIndicators
272+
);
273+
if ( registeredType instanceof BasicPluralType<?, ?> ) {
274+
typeConfiguration.getBasicTypeRegistry().register( registeredType );
275+
}
276+
return registeredType;
277+
}
278+
else {
279+
return typeConfiguration.getBasicTypeRegistry().getRegisteredType( reflectedJtd.getJavaType() );
280+
}
281+
}
282+
283+
private static BasicType<?> registeredElementType(
284+
JdbcType explicitJdbcType,
285+
Function<TypeConfiguration, MutabilityPlan> explicitMutabilityPlanAccess,
286+
JdbcTypeIndicators stdIndicators,
287+
BootstrapContext context,
288+
JavaType<?> elementJtd) {
289+
if ( elementJtd instanceof EnumJavaType<?> ) {
290+
return (BasicType<?>) fromEnum( (EnumJavaType<?>) elementJtd, explicitJdbcType, stdIndicators, context ).getJdbcMapping();
291+
}
292+
else if ( isTemporal( elementJtd ) ) {
293+
final BasicValue.Resolution<?> resolution = fromTemporal(
294+
(TemporalJavaType<?>) elementJtd,
295+
null,
296+
null,
297+
explicitMutabilityPlanAccess,
298+
stdIndicators
299+
);
300+
return resolution.getLegacyResolvedBasicType();
301+
}
302+
else {
303+
return context.getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( elementJtd.getJavaType() );
304+
}
305+
}
306+
276307
public static <T> BasicType<T> resolveSqlTypeIndicators(
277308
JdbcTypeIndicators stdIndicators,
278309
BasicType<T> resolved,

hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ public void contributeType(CompositeUserType<?> type) {
678678
}
679679

680680
final int preferredSqlTypeCodeForDuration = getPreferredSqlTypeCodeForDuration( serviceRegistry );
681-
if ( preferredSqlTypeCodeForDuration != SqlTypes.INTERVAL_SECOND ) {
681+
if ( preferredSqlTypeCodeForDuration != SqlTypes.DURATION ) {
682682
adaptToPreferredSqlTypeCode(
683683
typeConfiguration,
684684
jdbcTypeRegistry,
@@ -688,9 +688,6 @@ public void contributeType(CompositeUserType<?> type) {
688688
"org.hibernate.type.DurationType"
689689
);
690690
}
691-
else {
692-
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.INTERVAL_SECOND, SqlTypes.DURATION );
693-
}
694691

695692
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.INET, SqlTypes.VARBINARY );
696693
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.GEOMETRY, SqlTypes.VARBINARY );

hibernate-core/src/main/java/org/hibernate/type/AdjustableBasicType.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ default <X> BasicType<X> resolveIndicatedType(JdbcTypeIndicators indicators, Jav
2727
indicators,
2828
domainJtd
2929
);
30-
if ( resolvedJdbcType != jdbcType ) {
30+
if ( getJavaTypeDescriptor() != domainJtd || resolvedJdbcType != jdbcType ) {
3131
return indicators.getTypeConfiguration().getBasicTypeRegistry()
32-
.resolve( domainJtd, resolvedJdbcType, getName() );
32+
.resolve( domainJtd, resolvedJdbcType );
3333
}
3434
}
3535
else {
3636
final int resolvedJdbcTypeCode = indicators.resolveJdbcTypeCode( jdbcType.getDefaultSqlTypeCode() );
37-
if ( resolvedJdbcTypeCode != jdbcType.getDefaultSqlTypeCode() ) {
37+
if ( getJavaTypeDescriptor() != domainJtd || resolvedJdbcTypeCode != jdbcType.getDefaultSqlTypeCode() ) {
3838
return indicators.getTypeConfiguration().getBasicTypeRegistry()
39-
.resolve( domainJtd, indicators.getJdbcType( resolvedJdbcTypeCode ), getName() );
39+
.resolve( domainJtd, indicators.getJdbcType( resolvedJdbcTypeCode ) );
4040
}
4141
}
4242
return (BasicType<X>) this;

hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
package org.hibernate.type;
88

99
import java.io.Serializable;
10+
import java.util.ArrayList;
11+
import java.util.List;
1012
import java.util.Map;
1113
import java.util.concurrent.ConcurrentHashMap;
1214
import java.util.function.Supplier;
1315

16+
import org.checkerframework.checker.nullness.qual.Nullable;
1417
import org.hibernate.HibernateException;
1518
import org.hibernate.Internal;
1619
import org.hibernate.MappingException;
@@ -47,6 +50,7 @@ public class BasicTypeRegistry implements Serializable {
4750

4851
private final Map<String, BasicType<?>> typesByName = new ConcurrentHashMap<>();
4952
private final Map<String, BasicTypeReference<?>> typeReferencesByName = new ConcurrentHashMap<>();
53+
private final Map<String, List<BasicTypeReference<?>>> typeReferencesByJavaTypeName = new ConcurrentHashMap<>();
5054

5155
public BasicTypeRegistry(TypeConfiguration typeConfiguration){
5256
this.typeConfiguration = typeConfiguration;
@@ -205,14 +209,28 @@ private <J> BasicType<J> createIfUnregistered(
205209
if ( registeredTypeMatches( javaType, jdbcType, registeredType ) ) {
206210
return registeredType;
207211
}
208-
else {
209-
final BasicType<J> createdType = creator.get();
210-
register( javaType, jdbcType, createdType );
211-
return createdType;
212+
// Create an ad-hoc type since the java type doesn't come from the registry and is probably explicitly defined
213+
else if ( typeConfiguration.getJavaTypeRegistry().resolveDescriptor( javaType.getJavaType() ) == javaType ) {
214+
final var basicTypeReferences = typeReferencesByJavaTypeName.get( javaType.getTypeName() );
215+
if ( basicTypeReferences != null && !basicTypeReferences.isEmpty() ) {
216+
final var jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry();
217+
for ( var typeReference : basicTypeReferences ) {
218+
if ( jdbcTypeRegistry.getDescriptor( typeReference.getSqlTypeCode() ) == jdbcType ) {
219+
final var basicType = typesByName.get( typeReference.getName() );
220+
//noinspection unchecked
221+
return registeredTypeMatches( javaType, jdbcType, basicType )
222+
? (BasicType<J>) basicType
223+
: (BasicType<J>) createBasicType( typeReference.getName(), typeReference );
224+
}
225+
}
226+
}
212227
}
228+
final BasicType<J> createdType = creator.get();
229+
register( javaType, jdbcType, createdType );
230+
return createdType;
213231
}
214232

215-
private static <J> boolean registeredTypeMatches(JavaType<J> javaType, JdbcType jdbcType, BasicType<J> registeredType) {
233+
private static boolean registeredTypeMatches(JavaType<?> javaType, JdbcType jdbcType, @Nullable BasicType<?> registeredType) {
216234
return registeredType != null
217235
&& registeredType.getJdbcType() == jdbcType
218236
&& registeredType.getMappedJavaType() == javaType;
@@ -296,7 +314,7 @@ public void addTypeReferenceRegistrationKey(String typeReferenceKey, String... a
296314
throw new IllegalArgumentException( "Couldn't find type reference with name: " + typeReferenceKey );
297315
}
298316
for ( String additionalTypeReferenceKey : additionalTypeReferenceKeys ) {
299-
typeReferencesByName.put( additionalTypeReferenceKey, basicTypeReference );
317+
addTypeReference( additionalTypeReferenceKey, basicTypeReference );
300318
}
301319
}
302320

@@ -348,7 +366,7 @@ public void addPrimeEntry(BasicTypeReference<?> type, String legacyTypeClassName
348366

349367
// Legacy name registration
350368
if ( StringHelper.isNotEmpty( legacyTypeClassName ) ) {
351-
typeReferencesByName.put( legacyTypeClassName, type );
369+
addTypeReference( legacyTypeClassName, type );
352370
}
353371

354372
// explicit registration keys
@@ -417,16 +435,29 @@ private void applyRegistrationKeys(BasicTypeReference<?> type, String[] keys) {
417435
//Incidentally this might help with map lookup efficiency too.
418436
key = key.intern();
419437

420-
LOG.debugf( "Adding type registration %s -> %s", key, type );
438+
addTypeReference( key, type );
439+
}
440+
}
421441

422-
final BasicTypeReference<?> old = typeReferencesByName.put( key, type );
423-
if ( old != null && old != type ) {
424-
LOG.debugf(
425-
"Type registration key [%s] overrode previous entry : `%s`",
426-
key,
427-
old
428-
);
429-
}
442+
private void addTypeReference(String name, BasicTypeReference<?> typeReference) {
443+
// Incredibly verbose logging disabled
444+
LOG.tracef( "Adding type registration %s -> %s", name, typeReference );
445+
446+
final BasicTypeReference<?> old = typeReferencesByName.put( name, typeReference );
447+
if ( old != null && old != typeReference ) {
448+
LOG.tracef(
449+
"Type registration key [%s] overrode previous entry : `%s`",
450+
name,
451+
old
452+
);
453+
}
454+
455+
final var basicTypeReferences = typeReferencesByJavaTypeName.computeIfAbsent(
456+
typeReference.getBindableJavaType().getTypeName(),
457+
s -> new ArrayList<>()
458+
);
459+
if ( !basicTypeReferences.contains( typeReference ) ) {
460+
basicTypeReferences.add( typeReference );
430461
}
431462
}
432463
}

hibernate-core/src/main/java/org/hibernate/type/StandardBasicTypes.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,12 @@ private StandardBasicTypes() {
347347
// Date / time data
348348

349349
/**
350-
* The standard Hibernate type for mapping {@link Duration} to JDBC {@link org.hibernate.type.SqlTypes#INTERVAL_SECOND INTERVAL_SECOND}
351-
* or {@link org.hibernate.type.SqlTypes#NUMERIC NUMERIC} as a fallback.
350+
* The standard Hibernate type for mapping {@link Duration} to JDBC {@link org.hibernate.type.SqlTypes#DURATION DURATION}.
352351
*/
353352
public static final BasicTypeReference<Duration> DURATION = new BasicTypeReference<>(
354353
"Duration",
355354
Duration.class,
356-
SqlTypes.INTERVAL_SECOND
355+
SqlTypes.DURATION
357356
);
358357

359358
/**

hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/DurationMappingTests.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
1919
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
2020
import org.hibernate.persister.entity.EntityPersister;
21+
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
22+
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
2123
import org.hibernate.type.SqlTypes;
2224
import org.hibernate.type.descriptor.jdbc.AdjustableJdbcType;
2325
import org.hibernate.type.descriptor.jdbc.JdbcType;
@@ -46,6 +48,7 @@
4648
* 2.2.21. Duration
4749
* By default, Hibernate maps Duration to the NUMERIC SQL type.
4850
*/
51+
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsIntervalSecondType.class)
4952
@ServiceRegistry(settings = @Setting(name = AvailableSettings.PREFERRED_DURATION_JDBC_TYPE, value = "INTERVAL_SECOND"))
5053
public class DurationMappingTests {
5154

0 commit comments

Comments
 (0)