Skip to content

Commit 4f0d972

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 9ce4619 commit 4f0d972

File tree

4 files changed

+117
-23
lines changed

4 files changed

+117
-23
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public static <T> BasicValue.Resolution<T> from(
6868
final var typeConfiguration = bootstrapContext.getTypeConfiguration();
6969
final var basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
7070

71-
final var reflectedJtd = reflectedJtdResolver.get();
71+
final JavaType<T> reflectedJtd;
7272

7373
// NOTE: the distinction that is made below wrt `explicitJavaType` and `reflectedJtd`
7474
// is needed temporarily to trigger "legacy resolution" versus "ORM6 resolution.
@@ -110,7 +110,7 @@ else if ( explicitJdbcType != null ) {
110110
}
111111
}
112112
}
113-
else if ( reflectedJtd != null ) {
113+
else if ( ( reflectedJtd = reflectedJtdResolver.get() ) != null ) {
114114
// we were able to determine the "reflected java-type"
115115
// Use JTD if we know it to apply any specialized resolutions
116116
if ( reflectedJtd instanceof EnumJavaType enumJavaType ) {

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

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

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

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package org.hibernate.type;
66

77
import java.io.Serializable;
8+
import java.util.ArrayList;
9+
import java.util.List;
810
import java.util.Map;
911
import java.util.concurrent.ConcurrentHashMap;
1012
import java.util.function.Supplier;
@@ -49,6 +51,7 @@ public class BasicTypeRegistry implements Serializable {
4951

5052
private final Map<String, BasicType<?>> typesByName = new ConcurrentHashMap<>();
5153
private final Map<String, BasicTypeReference<?>> typeReferencesByName = new ConcurrentHashMap<>();
54+
private final Map<String, List<BasicTypeReference<?>>> typeReferencesByJavaTypeName = new ConcurrentHashMap<>();
5255

5356
public BasicTypeRegistry(TypeConfiguration typeConfiguration){
5457
this.typeConfiguration = typeConfiguration;
@@ -256,11 +259,25 @@ private <J> BasicType<J> createIfUnregistered(
256259
if ( registeredTypeMatches( javaType, jdbcType, registeredType ) ) {
257260
return castNonNull( registeredType );
258261
}
259-
else {
260-
final var createdType = creator.get();
261-
register( javaType, jdbcType, createdType );
262-
return createdType;
262+
// Create an ad-hoc type since the java type doesn't come from the registry and is probably explicitly defined
263+
else if ( typeConfiguration.getJavaTypeRegistry().resolveDescriptor( javaType.getJavaType() ) == javaType ) {
264+
final var basicTypeReferences = typeReferencesByJavaTypeName.get( javaType.getTypeName() );
265+
if ( basicTypeReferences != null && !basicTypeReferences.isEmpty() ) {
266+
final var jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry();
267+
for ( var typeReference : basicTypeReferences ) {
268+
if ( jdbcTypeRegistry.getDescriptor( typeReference.getSqlTypeCode() ) == jdbcType ) {
269+
final var basicType = typesByName.get( typeReference.getName() );
270+
//noinspection unchecked
271+
return basicType != null
272+
? (BasicType<J>) basicType
273+
: (BasicType<J>) createBasicType( typeReference.getName(), typeReference );
274+
}
275+
}
276+
}
263277
}
278+
final var createdType = creator.get();
279+
register( javaType, jdbcType, createdType );
280+
return createdType;
264281
}
265282

266283
private static <J> boolean registeredTypeMatches(JavaType<J> javaType, JdbcType jdbcType, BasicType<J> registeredType) {
@@ -334,7 +351,7 @@ public void addTypeReferenceRegistrationKey(String typeReferenceKey, String... a
334351
throw new IllegalArgumentException( "Couldn't find type reference with name: " + typeReferenceKey );
335352
}
336353
for ( String additionalTypeReferenceKey : additionalTypeReferenceKeys ) {
337-
typeReferencesByName.put( additionalTypeReferenceKey, basicTypeReference );
354+
addTypeReference( additionalTypeReferenceKey, basicTypeReference );
338355
}
339356
}
340357

@@ -384,7 +401,7 @@ public void addPrimeEntry(BasicTypeReference<?> type, String legacyTypeClassName
384401

385402
// Legacy name registration
386403
if ( isNotEmpty( legacyTypeClassName ) ) {
387-
typeReferencesByName.put( legacyTypeClassName, type );
404+
addTypeReference( legacyTypeClassName, type );
388405
}
389406

390407
// explicit registration keys
@@ -429,19 +446,31 @@ private void applyRegistrationKeys(BasicTypeReference<?> type, String[] keys) {
429446
// Incidentally, this might also help with map lookup efficiency.
430447
key = key.intern();
431448

432-
// Incredibly verbose logging disabled
433-
// LOG.tracef( "Adding type registration %s -> %s", key, type );
449+
addTypeReference( key, type );
450+
}
451+
}
452+
}
453+
454+
private void addTypeReference(String name, BasicTypeReference<?> typeReference) {
455+
// Incredibly verbose logging disabled
456+
// LOG.tracef( "Adding type registration %s -> %s", key, type );
434457

435458
// final BasicTypeReference<?> old =
436-
typeReferencesByName.put( key, type );
437-
// if ( old != null && old != type ) {
438-
// LOG.tracef(
439-
// "Type registration key [%s] overrode previous entry : `%s`",
440-
// key,
441-
// old
442-
// );
443-
// }
444-
}
459+
typeReferencesByName.put( name, typeReference );
460+
// if ( old != null && old != type ) {
461+
// LOG.tracef(
462+
// "Type registration key [%s] overrode previous entry : `%s`",
463+
// key,
464+
// old
465+
// );
466+
// }
467+
468+
final var basicTypeReferences = typeReferencesByJavaTypeName.computeIfAbsent(
469+
typeReference.getJavaType().getTypeName(),
470+
s -> new ArrayList<>()
471+
);
472+
if ( !basicTypeReferences.contains( typeReference ) ) {
473+
basicTypeReferences.add( typeReference );
445474
}
446475
}
447476
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.envers.integration.basic;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.GeneratedValue;
9+
import jakarta.persistence.Id;
10+
import org.hibernate.annotations.Nationalized;
11+
import org.hibernate.community.dialect.DerbyDialect;
12+
import org.hibernate.dialect.DB2Dialect;
13+
import org.hibernate.dialect.HANADialect;
14+
import org.hibernate.dialect.OracleDialect;
15+
import org.hibernate.dialect.PostgreSQLDialect;
16+
import org.hibernate.dialect.SybaseDialect;
17+
import org.hibernate.envers.Audited;
18+
import org.hibernate.mapping.Table;
19+
import org.hibernate.testing.orm.junit.DomainModel;
20+
import org.hibernate.testing.orm.junit.DomainModelScope;
21+
import org.hibernate.testing.orm.junit.JiraKey;
22+
import org.hibernate.testing.orm.junit.SessionFactory;
23+
import org.hibernate.testing.orm.junit.SkipForDialect;
24+
import org.hibernate.type.StandardBasicTypes;
25+
import org.junit.jupiter.api.Test;
26+
import org.opentest4j.AssertionFailedError;
27+
28+
import static org.hibernate.boot.model.naming.Identifier.toIdentifier;
29+
import static org.junit.jupiter.api.Assertions.assertEquals;
30+
import static org.junit.jupiter.api.Assertions.assertThrows;
31+
32+
@JiraKey(value = "HHH-19976")
33+
@DomainModel(annotatedClasses = {NationalizedTest.NationalizedEntity.class})
34+
@SessionFactory
35+
@SkipForDialect(dialectClass = OracleDialect.class)
36+
@SkipForDialect(dialectClass = PostgreSQLDialect.class, matchSubTypes = true, reason = "@Lob field in HQL predicate fails with error about text = bigint")
37+
@SkipForDialect(dialectClass = HANADialect.class, matchSubTypes = true, reason = "HANA doesn't support comparing LOBs with the = operator")
38+
@SkipForDialect(dialectClass = SybaseDialect.class, matchSubTypes = true, reason = "Sybase doesn't support comparing LOBs with the = operator")
39+
@SkipForDialect(dialectClass = DB2Dialect.class, matchSubTypes = true, reason = "DB2 jdbc driver doesn't support setNString")
40+
@SkipForDialect(dialectClass = DerbyDialect.class, matchSubTypes = true, reason = "Derby jdbc driver doesn't support setNString")
41+
public class NationalizedTest {
42+
43+
@Test
44+
public void testMetadataBindings(DomainModelScope scope) {
45+
final var domainModel = scope.getDomainModel();
46+
47+
assertThrows( AssertionFailedError.class, () -> {
48+
final Table auditTable = domainModel.getEntityBinding( NationalizedEntity.class.getName() + "_AUD" )
49+
.getTable();
50+
51+
final org.hibernate.mapping.Column colDef = auditTable.getColumn( toIdentifier( "nationalizedString" ) );
52+
assertEquals( StandardBasicTypes.NSTRING.getName(), colDef.getTypeName() );
53+
} );
54+
}
55+
56+
@Entity(name = "NationalizedEntity")
57+
@Audited
58+
public static class NationalizedEntity {
59+
@Id
60+
@GeneratedValue
61+
private Integer id;
62+
@Nationalized
63+
private String nationalizedString;
64+
}
65+
}

0 commit comments

Comments
 (0)