Skip to content

Commit 9e05b3a

Browse files
committed
HHH-16311 - Migrate away from UserType for enum handling
1 parent b276128 commit 9e05b3a

File tree

29 files changed

+496
-333
lines changed

29 files changed

+496
-333
lines changed

hibernate-core/hibernate-core.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ plugins {
1010
id 'org.hibernate.build.xjc-jakarta'
1111
}
1212

13+
repositories {
14+
gradlePluginPortal()
15+
}
16+
1317
description = 'Hibernate\'s core ORM functionality'
1418

1519
apply from: rootProject.file( 'gradle/published-java-module.gradle' )

hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java

+17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import java.io.Serializable;
1010
import java.util.ArrayList;
11+
import java.util.Collections;
1112
import java.util.HashMap;
1213
import java.util.HashSet;
1314
import java.util.List;
@@ -105,6 +106,7 @@
105106
import org.hibernate.query.named.NamedObjectRepository;
106107
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
107108
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
109+
import org.hibernate.type.ConvertedBasicType;
108110
import org.hibernate.type.descriptor.java.JavaType;
109111
import org.hibernate.type.descriptor.jdbc.JdbcType;
110112
import org.hibernate.type.spi.TypeConfiguration;
@@ -145,6 +147,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
145147

146148
private final Map<String, FilterDefinition> filterDefinitionMap = new HashMap<>();
147149
private final Map<String, String> imports = new HashMap<>();
150+
private Set<ConvertedBasicType<? extends Enum<?>>> enumMappings;
148151

149152
private final TypeDefinitionRegistry typeDefRegistry = new TypeDefinitionRegistryStandardImpl();
150153

@@ -489,6 +492,19 @@ public CollectionTypeRegistrationDescriptor findCollectionTypeRegistration(Colle
489492
return collectionTypeRegistrations.get( classification );
490493
}
491494

495+
@Override
496+
public <E extends Enum<E>> void registerEnumMapping(ConvertedBasicType<E> enumMapping) {
497+
if ( enumMappings == null ) {
498+
enumMappings = new HashSet<>();
499+
}
500+
enumMappings.add( enumMapping );
501+
}
502+
503+
@Override
504+
public Set<ConvertedBasicType<? extends Enum<?>>> getEnumMappings() {
505+
return enumMappings == null ? Collections.emptySet() : enumMappings;
506+
}
507+
492508
private CollectionTypeRegistrationDescriptor toDescriptor(CollectionTypeRegistration registrationAnnotation) {
493509
final Map<String,String> parameters;
494510
if ( registrationAnnotation.parameters().length > 0 ) {
@@ -2330,6 +2346,7 @@ public MetadataImpl buildMetadataInstance(MetadataBuildingContext buildingContex
23302346
sqlResultSetMappingMap,
23312347
namedEntityGraphMap,
23322348
sqlFunctionMap,
2349+
enumMappings,
23332350
getDatabase(),
23342351
bootstrapContext
23352352
);

hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java

+9
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
import org.hibernate.service.spi.ServiceRegistryImplementor;
7171
import org.hibernate.tool.schema.Action;
7272
import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator;
73+
import org.hibernate.type.ConvertedBasicType;
7374
import org.hibernate.type.spi.TypeConfiguration;
7475

7576
import static org.hibernate.cfg.AvailableSettings.EVENT_LISTENER_PREFIX;
@@ -103,6 +104,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
103104
private final Map<String, NamedResultSetMappingDescriptor> sqlResultSetMappingMap;
104105
private final Map<String, NamedEntityGraphDefinition> namedEntityGraphMap;
105106
private final Map<String, SqmFunctionDescriptor> sqlFunctionMap;
107+
private final Set<ConvertedBasicType<? extends Enum<?>>> enumMappings;
106108
private final Database database;
107109

108110
public MetadataImpl(
@@ -123,6 +125,7 @@ public MetadataImpl(
123125
Map<String, NamedResultSetMappingDescriptor> sqlResultSetMappingMap,
124126
Map<String, NamedEntityGraphDefinition> namedEntityGraphMap,
125127
Map<String, SqmFunctionDescriptor> sqlFunctionMap,
128+
Set<ConvertedBasicType<? extends Enum<?>>> enumMappings,
126129
Database database,
127130
BootstrapContext bootstrapContext) {
128131
this.uuid = uuid;
@@ -142,6 +145,7 @@ public MetadataImpl(
142145
this.sqlResultSetMappingMap = sqlResultSetMappingMap;
143146
this.namedEntityGraphMap = namedEntityGraphMap;
144147
this.sqlFunctionMap = sqlFunctionMap;
148+
this.enumMappings = enumMappings;
145149
this.database = database;
146150
this.bootstrapContext = bootstrapContext;
147151
}
@@ -322,6 +326,11 @@ public Map<String, SqmFunctionDescriptor> getSqlFunctionMap() {
322326
return sqlFunctionMap;
323327
}
324328

329+
@Override
330+
public Set<ConvertedBasicType<? extends Enum<?>>> getEnumMappings() {
331+
return enumMappings;
332+
}
333+
325334
@Override
326335
public Set<String> getContributors() {
327336
final HashSet<String> contributors = new HashSet<>();

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

+119-25
Original file line numberDiff line numberDiff line change
@@ -6,71 +6,165 @@
66
*/
77
package org.hibernate.boot.model.process.internal;
88

9+
import java.util.Locale;
10+
11+
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
12+
import org.hibernate.boot.spi.BootstrapContext;
13+
import org.hibernate.boot.spi.MetadataBuildingContext;
14+
import org.hibernate.internal.util.StringHelper;
915
import org.hibernate.mapping.BasicValue;
10-
import org.hibernate.metamodel.mapping.JdbcMapping;
16+
import org.hibernate.service.ServiceRegistry;
17+
import org.hibernate.type.ConvertedBasicType;
18+
import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter;
19+
import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter;
1120
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
12-
import org.hibernate.type.BasicType;
13-
import org.hibernate.type.CustomType;
21+
import org.hibernate.type.descriptor.java.EnumJavaType;
1422
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
1523
import org.hibernate.type.descriptor.java.JavaType;
1624
import org.hibernate.type.descriptor.java.MutabilityPlan;
25+
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
1726
import org.hibernate.type.descriptor.jdbc.JdbcType;
27+
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
28+
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
29+
import org.hibernate.type.internal.ConvertedBasicTypeImpl;
30+
import org.hibernate.type.spi.TypeConfiguration;
31+
32+
import jakarta.persistence.EnumType;
33+
34+
import static org.hibernate.type.SqlTypes.SMALLINT;
35+
import static org.hibernate.type.SqlTypes.TINYINT;
1836

1937
/**
38+
* Resolution for {@linkplain Enum enum} mappings using {@link jakarta.persistence.Enumerated},
39+
* either implicitly or explicitly
40+
*
2041
* @author Steve Ebersole
2142
*/
22-
public class EnumeratedValueResolution<E extends Enum<E>> implements BasicValue.Resolution<E> {
23-
private final CustomType<Object> enumTypeMapping;
24-
private final JavaType<E> domainJtd;
25-
private final JavaType<?> jdbcJtd;
26-
private final JdbcType jdbcType;
27-
private final EnumValueConverter<E,?> valueConverter;
43+
public class EnumeratedValueResolution<E extends Enum<E>,R> implements BasicValue.Resolution<E> {
44+
public static final String PREFIX = "enum::";
45+
46+
private final EnumValueConverter<E,R> valueConverter;
47+
private final ConvertedBasicType<E> jdbcMapping;
2848

2949
public EnumeratedValueResolution(
30-
CustomType<Object> enumTypeMapping,
31-
JavaType<E> domainJtd,
32-
JavaType<?> jdbcJtd,
3350
JdbcType jdbcType,
34-
EnumValueConverter<E, ?> valueConverter) {
35-
this.enumTypeMapping = enumTypeMapping;
36-
this.domainJtd = domainJtd;
37-
this.jdbcJtd = jdbcJtd;
38-
this.jdbcType = jdbcType;
51+
EnumValueConverter<E, R> valueConverter,
52+
MetadataBuildingContext context) {
3953
this.valueConverter = valueConverter;
54+
55+
final String externalizableName = createName( valueConverter );
56+
this.jdbcMapping = new ConvertedBasicTypeImpl<>( externalizableName, jdbcType, valueConverter );
57+
58+
context.getMetadataCollector().registerEnumMapping( jdbcMapping );
59+
}
60+
61+
private String createName(EnumValueConverter<E, R> valueConverter) {
62+
return String.format(
63+
Locale.ROOT,
64+
PREFIX + "%s::%s",
65+
valueConverter.getDomainJavaType().getJavaType().getName(),
66+
enumStyle( valueConverter ).name()
67+
);
68+
}
69+
70+
private static EnumType enumStyle(EnumValueConverter<?,?> valueConverter) {
71+
if ( valueConverter instanceof NamedEnumValueConverter ) {
72+
return EnumType.STRING;
73+
}
74+
else if ( valueConverter instanceof OrdinalEnumValueConverter ) {
75+
return EnumType.ORDINAL;
76+
}
77+
throw new UnsupportedOperationException();
4078
}
4179

4280
@Override
43-
public JdbcMapping getJdbcMapping() {
44-
return enumTypeMapping;
81+
public ConvertedBasicType<E> getJdbcMapping() {
82+
return jdbcMapping;
4583
}
4684

4785
@Override
48-
public BasicType getLegacyResolvedBasicType() {
49-
return enumTypeMapping;
86+
public ConvertedBasicType<E> getLegacyResolvedBasicType() {
87+
return jdbcMapping;
5088
}
5189

5290
@Override
5391
public JavaType<E> getDomainJavaType() {
54-
return domainJtd;
92+
return jdbcMapping.getJavaTypeDescriptor();
5593
}
5694

5795
@Override
5896
public JavaType<?> getRelationalJavaType() {
59-
return jdbcJtd;
97+
return jdbcMapping.getJdbcJavaType();
6098
}
6199

62100
@Override
63101
public JdbcType getJdbcType() {
64-
return jdbcType;
102+
return jdbcMapping.getJdbcType();
65103
}
66104

67105
@Override
68-
public EnumValueConverter getValueConverter() {
106+
public EnumValueConverter<E,R> getValueConverter() {
69107
return valueConverter;
70108
}
71109

72110
@Override
73111
public MutabilityPlan<E> getMutabilityPlan() {
74112
return ImmutableMutabilityPlan.instance();
75113
}
114+
115+
public static <E extends Enum<E>> EnumeratedValueResolution<E,?> fromName(
116+
String name,
117+
JdbcTypeIndicators jdbcTypeIndicators,
118+
MetadataBuildingContext context) {
119+
assert name != null;
120+
assert name.startsWith( PREFIX );
121+
122+
final String[] parts = StringHelper.split( "::", name );
123+
assert parts.length == 3;
124+
assert "enum".equals( parts[0] );
125+
126+
final TypeConfiguration typeConfiguration = context.getBootstrapContext().getTypeConfiguration();
127+
final JavaTypeRegistry javaTypeRegistry = typeConfiguration.getJavaTypeRegistry();
128+
final JdbcTypeRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry();
129+
130+
final Class<E> enumClass = resolveEnumClass( parts[1], context.getBootstrapContext() );
131+
final jakarta.persistence.EnumType style = jakarta.persistence.EnumType.valueOf( parts[ 2 ] );
132+
133+
//noinspection unchecked,rawtypes
134+
final EnumJavaType<E> enumJavaType = (EnumJavaType) javaTypeRegistry.getDescriptor( enumClass );
135+
final JdbcType jdbcType;
136+
final EnumValueConverter<E,?> converter;
137+
138+
if ( style == EnumType.ORDINAL ) {
139+
jdbcType = jdbcTypeRegistry.getDescriptor( enumJavaType.hasManyValues() ? SMALLINT : TINYINT );
140+
141+
final JavaType<Integer> jdbcJavaType = javaTypeRegistry.getDescriptor( Integer.class );
142+
converter = new OrdinalEnumValueConverter<>( enumJavaType, jdbcType, jdbcJavaType );
143+
}
144+
else if ( style == EnumType.STRING ) {
145+
//noinspection rawtypes
146+
final JavaType jdbcJavaType;
147+
if ( jdbcTypeIndicators.getColumnLength() == 1 ) {
148+
jdbcJavaType = javaTypeRegistry.getDescriptor( Character.class );
149+
}
150+
else {
151+
jdbcJavaType = javaTypeRegistry.getDescriptor( String.class );
152+
}
153+
jdbcType = jdbcJavaType.getRecommendedJdbcType( jdbcTypeIndicators );
154+
//noinspection unchecked,rawtypes
155+
converter = new NamedEnumValueConverter<>( enumJavaType, jdbcType, jdbcJavaType );
156+
}
157+
else {
158+
throw new IllegalArgumentException( );
159+
}
160+
161+
return new EnumeratedValueResolution<>( jdbcType, converter, context );
162+
}
163+
164+
private static <E extends Enum<E>> Class<E> resolveEnumClass(String enumClassName, BootstrapContext bootstrapContext) {
165+
final ServiceRegistry serviceRegistry = bootstrapContext.getServiceRegistry();
166+
final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
167+
168+
return classLoaderService.classForName( enumClassName );
169+
}
76170
}

0 commit comments

Comments
 (0)