Skip to content

Commit 4e14a07

Browse files
committed
HHH-16311 - Migrate enum handling away from UserType
1 parent ad90bf2 commit 4e14a07

File tree

21 files changed

+282
-234
lines changed

21 files changed

+282
-234
lines changed

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

+100-17
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,84 @@
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.type.BasicType;
16+
import org.hibernate.service.ServiceRegistry;
1117
import org.hibernate.type.ConvertedBasicType;
12-
import org.hibernate.type.CustomType;
13-
import org.hibernate.type.EnumType;
18+
import org.hibernate.type.descriptor.converter.internal.NamedEnumValueConverter;
19+
import org.hibernate.type.descriptor.converter.internal.OrdinalEnumValueConverter;
1420
import org.hibernate.type.descriptor.converter.spi.EnumValueConverter;
1521
import org.hibernate.type.descriptor.java.EnumJavaType;
1622
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
1723
import org.hibernate.type.descriptor.java.JavaType;
1824
import org.hibernate.type.descriptor.java.MutabilityPlan;
25+
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
1926
import org.hibernate.type.descriptor.jdbc.JdbcType;
27+
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
28+
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
2029
import org.hibernate.type.internal.ConvertedBasicTypeImpl;
2130
import org.hibernate.type.spi.TypeConfiguration;
2231

32+
import jakarta.persistence.EnumType;
33+
34+
import static org.hibernate.type.SqlTypes.SMALLINT;
35+
import static org.hibernate.type.SqlTypes.TINYINT;
36+
2337
/**
2438
* Resolution for {@linkplain Enum enum} mappings
2539
*
2640
* @author Steve Ebersole
2741
*/
2842
public class EnumeratedValueResolution<E extends Enum<E>,R> implements BasicValue.Resolution<E> {
29-
private final EnumValueConverter<E,R> valueConverter;
43+
public static final String PREFIX = "enum::";
3044

45+
private final EnumValueConverter<E,R> valueConverter;
3146
private final ConvertedBasicType<E> jdbcMapping;
32-
private final CustomType<E> legacyTypeResolution;
3347

3448
public EnumeratedValueResolution(
3549
JdbcType jdbcType,
3650
EnumValueConverter<E, R> valueConverter,
37-
TypeConfiguration typeConfiguration) {
51+
MetadataBuildingContext context) {
3852
this.valueConverter = valueConverter;
3953

40-
final EnumJavaType<E> domainJavaType = valueConverter.getDomainJavaType();
41-
this.jdbcMapping = new ConvertedBasicTypeImpl<>(
42-
domainJavaType.getJavaTypeClass().getName(),
43-
jdbcType,
44-
valueConverter
45-
);
46-
this.legacyTypeResolution = new CustomType<>(
47-
new EnumType<>( domainJavaType.getJavaTypeClass(), valueConverter, typeConfiguration ),
48-
typeConfiguration
54+
final String externalizableName = createName( valueConverter );
55+
this.jdbcMapping = new ConvertedBasicTypeImpl<>( externalizableName, jdbcType, valueConverter );
56+
57+
context.getMetadataCollector().registerEnumMapping( jdbcMapping );
58+
}
59+
60+
private String createName(EnumValueConverter<E, R> valueConverter) {
61+
return String.format(
62+
Locale.ROOT,
63+
PREFIX + "%s::%s",
64+
valueConverter.getDomainJavaType().getJavaType().getName(),
65+
enumStyle( valueConverter ).name()
4966
);
5067
}
5168

69+
private static EnumType enumStyle(EnumValueConverter<?,?> valueConverter) {
70+
if ( valueConverter instanceof NamedEnumValueConverter ) {
71+
return EnumType.STRING;
72+
}
73+
else if ( valueConverter instanceof OrdinalEnumValueConverter ) {
74+
return EnumType.ORDINAL;
75+
}
76+
throw new UnsupportedOperationException();
77+
}
78+
5279
@Override
5380
public ConvertedBasicType<E> getJdbcMapping() {
5481
return jdbcMapping;
5582
}
5683

5784
@Override
58-
public BasicType getLegacyResolvedBasicType() {
59-
return legacyTypeResolution;
85+
public ConvertedBasicType<E> getLegacyResolvedBasicType() {
86+
return jdbcMapping;
6087
}
6188

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

0 commit comments

Comments
 (0)