Skip to content

Commit 6b5099d

Browse files
committed
HHH-19500 get rid of layer-breaking operations in UserType
- getValueConverter() to return JPA AttributeConverter since this is a much less technical interface and is easier for user to implement - had to fix a problem with embeddable discriminators manifesting in JsonHelper and StructHelper and took the opportunity to clean up use of generic types - now probably need efficient impls of isInstance()
1 parent da0e125 commit 6b5099d

File tree

60 files changed

+598
-182
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+598
-182
lines changed

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

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55
package org.hibernate.boot.model.internal;
66

7-
import java.lang.reflect.ParameterizedType;
87
import java.util.HashMap;
98

109
import org.hibernate.annotations.Parameter;
@@ -17,7 +16,7 @@
1716
import org.hibernate.resource.beans.spi.ManagedBean;
1817
import org.hibernate.type.BasicType;
1918
import org.hibernate.type.CustomType;
20-
import org.hibernate.type.descriptor.converter.internal.JpaAttributeConverterImpl;
19+
import org.hibernate.type.descriptor.converter.spi.JpaAttributeConverter;
2120
import org.hibernate.type.descriptor.java.JavaType;
2221
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
2322
import org.hibernate.type.descriptor.jdbc.JdbcType;
@@ -28,18 +27,17 @@
2827

2928
import jakarta.persistence.AttributeConverter;
3029

31-
import static org.hibernate.internal.util.GenericsHelper.extractClass;
32-
import static org.hibernate.internal.util.GenericsHelper.extractParameterizedType;
3330
import static org.hibernate.internal.util.collections.CollectionHelper.mapOfSize;
31+
import static org.hibernate.type.descriptor.converter.internal.ConverterHelper.createJpaAttributeConverter;
3432

3533
/**
3634
* @author Steve Ebersole
3735
*/
3836
public class AnnotationHelper {
3937
public static HashMap<String, String> extractParameterMap(Parameter[] parameters) {
4038
final HashMap<String,String> paramMap = mapOfSize( parameters.length );
41-
for ( int i = 0; i < parameters.length; i++ ) {
42-
paramMap.put( parameters[i].name(), parameters[i].value() );
39+
for ( Parameter parameter : parameters ) {
40+
paramMap.put( parameter.name(), parameter.value() );
4341
}
4442
return paramMap;
4543
}
@@ -58,33 +56,21 @@ public static <X,Y> JdbcMapping resolveAttributeConverter(
5856
MetadataBuildingContext context) {
5957
final BootstrapContext bootstrapContext = context.getBootstrapContext();
6058
final TypeConfiguration typeConfiguration = bootstrapContext.getTypeConfiguration();
61-
6259
final var bean = bootstrapContext.getManagedBeanRegistry().getBean( type );
63-
64-
final ParameterizedType converterParameterizedType = extractParameterizedType( bean.getBeanClass() );
65-
final Class<?> domainJavaClass = extractClass( converterParameterizedType.getActualTypeArguments()[0] );
66-
final Class<?> relationalJavaClass = extractClass( converterParameterizedType.getActualTypeArguments()[1] );
67-
60+
@SuppressWarnings("unchecked")
61+
final var castBean = (ManagedBean<? extends AttributeConverter<X,Y>>) bean;
6862
final JavaTypeRegistry registry = typeConfiguration.getJavaTypeRegistry();
69-
final JavaType<X> domainJtd = registry.resolveDescriptor( domainJavaClass );
70-
final JavaType<Y> relationalJtd = registry.resolveDescriptor( relationalJavaClass );
71-
72-
final JpaAttributeConverterImpl<X,Y> valueConverter =
73-
new JpaAttributeConverterImpl<>(
74-
(ManagedBean<? extends AttributeConverter<X,Y>>) bean,
75-
registry.resolveDescriptor( bean.getBeanClass() ),
76-
domainJtd,
77-
relationalJtd
78-
);
63+
final JpaAttributeConverter<X, Y> valueConverter = createJpaAttributeConverter( castBean, registry );
7964
return new ConvertedBasicTypeImpl<>(
8065
ConverterDescriptor.TYPE_NAME_PREFIX
8166
+ valueConverter.getConverterJavaType().getTypeName(),
8267
String.format(
8368
"BasicType adapter for AttributeConverter<%s,%s>",
84-
domainJtd.getTypeName(),
85-
relationalJtd.getTypeName()
69+
valueConverter.getDomainJavaType().getTypeName(),
70+
valueConverter.getRelationalJavaType().getTypeName()
8671
),
87-
relationalJtd.getRecommendedJdbcType( typeConfiguration.getCurrentBaseSqlTypeIndicators() ),
72+
registry.<Y>resolveDescriptor( valueConverter.getRelationalJavaType().getJavaType() )
73+
.getRecommendedJdbcType( typeConfiguration.getCurrentBaseSqlTypeIndicators() ),
8874
valueConverter
8975
);
9076
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public JdbcType getJdbcType() {
7070
@Override @SuppressWarnings("unchecked")
7171
public BasicValueConverter<J,T> getValueConverter() {
7272
return updatedType == null
73-
? jdbcMapping.getValueConverter()
73+
? (BasicValueConverter<J, T>) jdbcMapping.getValueConverter()
7474
: (BasicValueConverter<J, T>) updatedType.getValueConverter();
7575
}
7676

hibernate-core/src/main/java/org/hibernate/metamodel/mapping/JdbcMapping.java

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,25 +102,41 @@ default JavaType<?> getJdbcJavaType() {
102102
* or <code>null</code> if there is no conversion.
103103
*/
104104
@Incubating
105-
default BasicValueConverter getValueConverter() {
105+
default BasicValueConverter<?,?> getValueConverter() {
106106
return null;
107107
}
108108

109109
//TODO: would it be better to just give JdbcMapping a
110110
// noop converter by default, instead of having
111111
// to deal with null here?
112-
@SuppressWarnings({"rawtypes", "unchecked"})
113-
default Object convertToRelationalValue(Object value) {
114-
BasicValueConverter valueConverter = getValueConverter();
115-
return valueConverter == null ? value : valueConverter.toRelationalValue( value );
112+
default <T> Object convertToRelationalValue(T value) {
113+
final var converter = getValueConverter();
114+
if ( converter == null ) {
115+
return value;
116+
}
117+
else {
118+
assert value == null
119+
|| converter.getDomainJavaType().isInstance( value );
120+
@SuppressWarnings( "unchecked" ) // safe, we just checked
121+
final var valueConverter = (BasicValueConverter<T,?>) converter;
122+
return valueConverter.toRelationalValue( value );
123+
}
116124
}
117125

118-
default Object convertToDomainValue(Object value) {
119-
BasicValueConverter valueConverter = getValueConverter();
120-
return valueConverter == null ? value : valueConverter.toDomainValue( value );
126+
default <T> Object convertToDomainValue(T value) {
127+
var converter = getValueConverter();
128+
if ( converter == null ) {
129+
return value;
130+
}
131+
else {
132+
assert value == null
133+
|| converter.getRelationalJavaType().isInstance( value );
134+
@SuppressWarnings( "unchecked" ) // safe, we just checked
135+
final var valueConverter = (BasicValueConverter<?, T>) converter;
136+
return valueConverter.toDomainValue( value );
137+
}
121138
}
122139

123-
124140
@Override
125141
default int getJdbcTypeCount() {
126142
return 1;

hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ protected Object[] getAttributeValues(Object compositeInstance) {
871871
? getValue( compositeInstance, i )
872872
: null;
873873
}
874-
results[i] = compositeInstance.getClass().getName();
874+
results[i] = compositeInstance.getClass();
875875
return results;
876876
}
877877
}

hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public DomainResult<T> createDomainResult(
102102
final BasicValueConverter<T, ?> converter;
103103
if ( jdbcMapping != null ) {
104104
jdbcJavaType = (JavaType<T>) jdbcMapping.getJdbcJavaType();
105-
converter = jdbcMapping.getValueConverter();
105+
converter = (BasicValueConverter<T, ?>) jdbcMapping.getValueConverter();
106106
}
107107
else if ( type != null ) {
108108
jdbcJavaType = type.getExpressibleJavaType();

hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicResult.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public BasicResult(
5555
jdbcValuesArrayPosition,
5656
resultVariable,
5757
jdbcMapping.getJavaTypeDescriptor(),
58-
jdbcMapping.getValueConverter(),
58+
(BasicValueConverter<T,?>)
59+
jdbcMapping.getValueConverter(),
5960
navigablePath,
6061
coerceResultType,
6162
unwrapRowProcessingState

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

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.Arrays;
1212
import java.util.Map;
1313

14+
import jakarta.persistence.AttributeConverter;
1415
import org.hibernate.HibernateException;
1516
import org.hibernate.MappingException;
1617
import org.hibernate.cache.MutableCacheKeyBuilder;
@@ -33,6 +34,7 @@
3334
import org.hibernate.usertype.UserVersionType;
3435

3536
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY;
37+
import static org.hibernate.type.descriptor.converter.internal.ConverterHelper.createValueConverter;
3638

3739
/**
3840
* Adapts {@link UserType} to the generic {@link Type} interface, in order
@@ -62,18 +64,21 @@ public class CustomType<J>
6264
private final ValueBinder<J> valueBinder;
6365
private final JdbcLiteralFormatter<J> jdbcLiteralFormatter;
6466

67+
private final BasicValueConverter<J, ?> converter;
68+
6569
public CustomType(UserType<J> userType, TypeConfiguration typeConfiguration) throws MappingException {
6670
this( userType, EMPTY_STRING_ARRAY, typeConfiguration );
6771
}
6872

6973
public CustomType(UserType<J> userType, String[] registrationKeys, TypeConfiguration typeConfiguration) {
7074
this.userType = userType;
75+
this.registrationKeys = registrationKeys;
7176
name = userType.getClass().getName();
72-
7377
mappedJavaType = getMappedJavaType( userType );
7478

75-
final BasicValueConverter<J, Object> converter = userType.getValueConverter();
76-
if ( converter != null ) {
79+
final AttributeConverter<J, ?> valueConverter = userType.getValueConverter();
80+
if ( valueConverter != null ) {
81+
converter = createValueConverter( valueConverter, typeConfiguration.getJavaTypeRegistry() );
7782
// When an explicit value converter is given,
7883
// we configure the custom type to use that instead of adapters that delegate to UserType.
7984
// This is necessary to support selecting a column with multiple domain type representations.
@@ -93,16 +98,17 @@ public CustomType(UserType<J> userType, String[] registrationKeys, TypeConfigura
9398
valueExtractor = jdbcType.getExtractor( mappedJavaType );
9499
valueBinder = jdbcType.getBinder( mappedJavaType );
95100
jdbcLiteralFormatter =
96-
userType instanceof EnhancedUserType ? jdbcType.getJdbcLiteralFormatter( mappedJavaType ) : null;
101+
userType instanceof EnhancedUserType
102+
? jdbcType.getJdbcLiteralFormatter( mappedJavaType )
103+
: null;
104+
converter = null;
97105
}
98-
99-
this.registrationKeys = registrationKeys;
100106
}
101107

102108
private JavaType<J> getMappedJavaType(UserType<J> userType) {
103109
return userType instanceof UserVersionType<J> userVersionType
104-
? new UserTypeVersionJavaTypeWrapper<>( userVersionType )
105-
: new UserTypeJavaTypeWrapper<>( userType );
110+
? new UserTypeVersionJavaTypeWrapper<>( userVersionType, this )
111+
: new UserTypeJavaTypeWrapper<>( userType, this );
106112
}
107113

108114
public UserType<J> getUserType() {
@@ -166,11 +172,9 @@ public Object assemble(Serializable cached, SharedSessionContractImplementor ses
166172
// we have to handle the fact that it could produce a null value,
167173
// in which case we will try to use a converter for assembling,
168174
// or if that doesn't exist, simply use the relational value as is
169-
if ( assembled == null && cached != null ) {
170-
final BasicValueConverter<J, Object> converter = getUserType().getValueConverter();
171-
return converter == null ? cached : converter.toDomainValue( cached );
172-
}
173-
return assembled;
175+
return assembled == null && cached != null
176+
? convertToDomainValue( cached )
177+
: assembled;
174178
}
175179

176180
@Override
@@ -189,20 +193,15 @@ private Serializable disassembleForCache(Object value) {
189193
// we have to handle the fact that it could produce a null value,
190194
// in which case we will try to use a converter for disassembling,
191195
// or if that doesn't exist, simply use the domain value as is
192-
if ( disassembled == null ){
193-
final BasicValueConverter<J, Object> converter = getUserType().getValueConverter();
194-
return converter == null ? disassembled : (Serializable) converter.toRelationalValue( (J) value );
195-
}
196-
else {
197-
return disassembled;
198-
}
196+
return disassembled == null
197+
? (Serializable) convertToRelationalValue( (J) value )
198+
: disassembled;
199199
}
200200

201201
@Override
202202
public Object disassemble(Object value, SharedSessionContractImplementor session) {
203203
// Use the value converter if available for conversion to the jdbc representation
204-
final BasicValueConverter<J, Object> converter = getUserType().getValueConverter();
205-
return converter == null ? value : converter.toRelationalValue( (J) value );
204+
return convertToRelationalValue( (J) value );
206205
}
207206

208207
@Override
@@ -395,8 +394,8 @@ public JavaType<?> getJdbcJavaType() {
395394
}
396395

397396
@Override
398-
public BasicValueConverter<J, Object> getValueConverter() {
399-
return userType.getValueConverter();
397+
public BasicValueConverter<J, ?> getValueConverter() {
398+
return converter;
400399
}
401400

402401
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.type.descriptor.converter.internal;
6+
7+
import jakarta.persistence.AttributeConverter;
8+
import jakarta.persistence.PersistenceException;
9+
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
10+
import org.hibernate.type.descriptor.java.JavaType;
11+
12+
/**
13+
* @author Gavin King
14+
* @since 7.0
15+
*/
16+
public class AttributeConverterWrapper<O,R> implements BasicValueConverter<O,R> {
17+
private final AttributeConverter<O,R> converter;
18+
private final JavaType<? extends AttributeConverter<O, R>> converterJtd;
19+
private final JavaType<O> domainJtd;
20+
private final JavaType<R> jdbcJtd;
21+
22+
public AttributeConverterWrapper(
23+
AttributeConverter<O, R> converter,
24+
JavaType<? extends AttributeConverter<O,R>> converterJtd,
25+
JavaType<O> domainJtd,
26+
JavaType<R> jdbcJtd) {
27+
this.converter = converter;
28+
this.converterJtd = converterJtd;
29+
this.domainJtd = domainJtd;
30+
this.jdbcJtd = jdbcJtd;
31+
}
32+
33+
@Override
34+
public O toDomainValue(R relationalForm) {
35+
try {
36+
return converter.convertToEntityAttribute( relationalForm );
37+
}
38+
catch (PersistenceException pe) {
39+
throw pe;
40+
}
41+
catch (RuntimeException re) {
42+
throw new PersistenceException( "Error attempting to apply AttributeConverter", re );
43+
}
44+
}
45+
46+
@Override
47+
public R toRelationalValue(O domainForm) {
48+
try {
49+
return converter.convertToDatabaseColumn( domainForm );
50+
}
51+
catch (PersistenceException pe) {
52+
throw pe;
53+
}
54+
catch (RuntimeException re) {
55+
throw new PersistenceException( "Error attempting to apply AttributeConverter: " + re.getMessage(), re );
56+
}
57+
}
58+
59+
@Override
60+
public JavaType<O> getDomainJavaType() {
61+
return domainJtd;
62+
}
63+
64+
@Override
65+
public JavaType<R> getRelationalJavaType() {
66+
return jdbcJtd;
67+
}
68+
69+
@Override
70+
public boolean equals(Object o) {
71+
if ( this == o ) {
72+
return true;
73+
}
74+
if ( o == null || getClass() != o.getClass() ) {
75+
return false;
76+
}
77+
78+
AttributeConverterWrapper<?, ?> that = (AttributeConverterWrapper<?, ?>) o;
79+
80+
if ( !converter.equals( that.converter ) ) {
81+
return false;
82+
}
83+
if ( !converterJtd.equals( that.converterJtd ) ) {
84+
return false;
85+
}
86+
if ( !domainJtd.equals( that.domainJtd ) ) {
87+
return false;
88+
}
89+
return jdbcJtd.equals( that.jdbcJtd );
90+
}
91+
92+
@Override
93+
public int hashCode() {
94+
int result = converter.hashCode();
95+
result = 31 * result + converterJtd.hashCode();
96+
result = 31 * result + domainJtd.hashCode();
97+
result = 31 * result + jdbcJtd.hashCode();
98+
return result;
99+
}
100+
}

0 commit comments

Comments
 (0)