Skip to content

Commit 65de5d9

Browse files
committed
HHH-18998 pass annotation to constructor of UserType
1 parent eacb836 commit 65de5d9

File tree

8 files changed

+355
-26
lines changed

8 files changed

+355
-26
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/TypeDefinition.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public BasicValue.Resolution<?> resolve(
108108
MetadataBuildingContext context,
109109
JdbcTypeIndicators indicators) {
110110
if ( isEmpty( localConfigParameters ) ) {
111-
// we can use the re-usable resolution...
111+
// we can use the reusable resolution...
112112
if ( reusableResolution == null ) {
113113
reusableResolution = createResolution( this.name, emptyMap(), indicators, context );
114114
}
@@ -151,9 +151,10 @@ private static <T> BasicValue.Resolution<T> createResolution(
151151

152152
// support for AttributeConverter would be nice too
153153
if ( isKnownType ) {
154+
154155
final T typeInstance =
155156
instantiateType( bootstrapContext.getServiceRegistry(), context.getBuildingOptions(),
156-
name, typeImplementorClass, instanceProducer );
157+
name, typeImplementorClass, bootstrapContext.getCustomTypeProducer() );
157158

158159
if ( typeInstance instanceof TypeConfigurationAware configurationAware ) {
159160
configurationAware.setTypeConfiguration( typeConfiguration );

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

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ public enum Kind {
102102
// in-flight info
103103

104104
private Class<? extends UserType<?>> explicitCustomType;
105-
private Map<String,String> explicitLocalTypeParams;
105+
private Map<String,String> explicitLocalCustomTypeParams;
106+
private Annotation explicitCustomTypeAnnotation;
106107

107108
private Function<TypeConfiguration, JdbcType> explicitJdbcTypeAccess;
108109
private Function<TypeConfiguration, BasicJavaType<?>> explicitJavaTypeAccess;
@@ -338,8 +339,9 @@ private boolean applyCustomType(MemberDetails memberDetails, TypeDetails typeDet
338339
final var modelContext = getSourceModelContext();
339340
final var userTypeImpl = kind.mappingAccess.customType( memberDetails, modelContext );
340341
if ( userTypeImpl != null ) {
341-
applyExplicitType( userTypeImpl,
342-
kind.mappingAccess.customTypeParameters( memberDetails, modelContext ) );
342+
this.explicitCustomType = userTypeImpl;
343+
this.explicitLocalCustomTypeParams = kind.mappingAccess.customTypeParameters( memberDetails, modelContext );
344+
this.explicitCustomTypeAnnotation = kind.mappingAccess.customTypeAnnotation( memberDetails, modelContext );
343345
// An explicit custom UserType has top precedence when we get to BasicValue resolution.
344346
return true;
345347
}
@@ -349,7 +351,8 @@ private boolean applyCustomType(MemberDetails memberDetails, TypeDetails typeDet
349351
final var registeredUserTypeImpl =
350352
getMetadataCollector().findRegisteredUserType( basicClass );
351353
if ( registeredUserTypeImpl != null ) {
352-
applyExplicitType( registeredUserTypeImpl, emptyMap() );
354+
this.explicitCustomType = registeredUserTypeImpl;
355+
this.explicitLocalCustomTypeParams = emptyMap();
353356
return true;
354357
}
355358
}
@@ -384,11 +387,6 @@ private void prepareValue(MemberDetails value, TypeDetails typeDetails, @Nullabl
384387
}
385388
}
386389

387-
private void applyExplicitType(Class<? extends UserType<?>> userTypeImpl, Map<String,String> parameters) {
388-
explicitCustomType = userTypeImpl;
389-
explicitLocalTypeParams = parameters;
390-
}
391-
392390
private void prepareCollectionId(MemberDetails attribute) {
393391
final var collectionId = attribute.getDirectAnnotationUsage( CollectionId.class );
394392
if ( collectionId == null ) {
@@ -1195,7 +1193,7 @@ else if ( aggregateComponent != null ) {
11951193
}
11961194

11971195
public void fillSimpleValue() {
1198-
basicValue.setExplicitTypeParams( explicitLocalTypeParams );
1196+
basicValue.setExplicitTypeParams( explicitLocalCustomTypeParams );
11991197

12001198
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12011199
// todo (6.0) : we are dropping support for @Type and @TypeDef from annotations
@@ -1211,6 +1209,10 @@ public void fillSimpleValue() {
12111209
basicValue.setTypeParameters( createDynamicParameterizedTypeParameters() );
12121210
}
12131211

1212+
if ( explicitCustomType != null ) {
1213+
basicValue.setTypeAnnotation( explicitCustomTypeAnnotation );
1214+
}
1215+
12141216
if ( converterDescriptor != null ) {
12151217
basicValue.setJpaAttributeConverterDescriptor( converterDescriptor );
12161218
}
@@ -1282,8 +1284,8 @@ private Map<String, Object> createDynamicParameterizedTypeParameters() {
12821284
parameters.put( DynamicParameterizedType.ACCESS_TYPE, accessType.getType() );
12831285
}
12841286

1285-
if ( explicitLocalTypeParams != null ) {
1286-
parameters.putAll( explicitLocalTypeParams );
1287+
if ( explicitLocalCustomTypeParams != null ) {
1288+
parameters.putAll( explicitLocalCustomTypeParams );
12871289
}
12881290

12891291
return parameters;
@@ -1295,6 +1297,7 @@ private Map<String, Object> createDynamicParameterizedTypeParameters() {
12951297
private interface BasicMappingAccess {
12961298
Class<? extends UserType<?>> customType(MemberDetails attribute, ModelsContext context);
12971299
Map<String,String> customTypeParameters(MemberDetails attribute, ModelsContext context);
1300+
Annotation customTypeAnnotation(MemberDetails attribute, ModelsContext context);
12981301
}
12991302

13001303
private static class ValueMappingAccess implements BasicMappingAccess {
@@ -1311,6 +1314,12 @@ public Map<String,String> customTypeParameters(MemberDetails attribute, ModelsCo
13111314
final var customType = attribute.locateAnnotationUsage( Type.class, context );
13121315
return customType == null ? null : extractParameterMap( customType.parameters() );
13131316
}
1317+
1318+
@Override
1319+
public Annotation customTypeAnnotation(MemberDetails attribute, ModelsContext context) {
1320+
final var annotations = attribute.getMetaAnnotated( Type.class, context );
1321+
return annotations == null || annotations.isEmpty() ? null : annotations.get( 0 );
1322+
}
13141323
}
13151324

13161325
private static class AnyDiscriminatorMappingAccess implements BasicMappingAccess {
@@ -1325,6 +1334,11 @@ public Class<? extends UserType<?>> customType(MemberDetails attribute, ModelsCo
13251334
public Map<String,String> customTypeParameters(MemberDetails attribute, ModelsContext context) {
13261335
return emptyMap();
13271336
}
1337+
1338+
@Override
1339+
public Annotation customTypeAnnotation(MemberDetails attribute, ModelsContext context) {
1340+
return null;
1341+
}
13281342
}
13291343

13301344
private static class AnyKeyMappingAccess implements BasicMappingAccess {
@@ -1339,6 +1353,11 @@ public Class<? extends UserType<?>> customType(MemberDetails attribute, ModelsCo
13391353
public Map<String,String> customTypeParameters(MemberDetails attribute, ModelsContext context) {
13401354
return emptyMap();
13411355
}
1356+
1357+
@Override
1358+
public Annotation customTypeAnnotation(MemberDetails attribute, ModelsContext context) {
1359+
return null;
1360+
}
13421361
}
13431362

13441363
private static class MapKeyMappingAccess implements BasicMappingAccess {
@@ -1357,6 +1376,12 @@ public Map<String,String> customTypeParameters(MemberDetails attribute, ModelsCo
13571376
return customType == null ? null : extractParameterMap( customType.parameters() );
13581377

13591378
}
1379+
1380+
@Override
1381+
public Annotation customTypeAnnotation(MemberDetails attribute, ModelsContext context) {
1382+
final var annotations = attribute.getMetaAnnotated( MapKeyType.class, context );
1383+
return annotations == null || annotations.isEmpty() ? null : annotations.get( 0 );
1384+
}
13601385
}
13611386

13621387
private static class CollectionIdMappingAccess implements BasicMappingAccess {
@@ -1373,7 +1398,12 @@ public Class<? extends UserType<?>> customType(MemberDetails attribute, ModelsCo
13731398
public Map<String,String> customTypeParameters(MemberDetails attribute, ModelsContext context) {
13741399
final var customType = attribute.locateAnnotationUsage( CollectionIdType.class, context );
13751400
return customType == null ? null : extractParameterMap( customType.parameters() );
1401+
}
13761402

1403+
@Override
1404+
public Annotation customTypeAnnotation(MemberDetails attribute, ModelsContext context) {
1405+
final var annotations = attribute.getMetaAnnotated( CollectionIdType.class, context );
1406+
return annotations == null || annotations.isEmpty() ? null : annotations.get( 0 );
13771407
}
13781408
}
13791409

@@ -1389,6 +1419,11 @@ public Class<? extends UserType<?>> customType(MemberDetails attribute, ModelsCo
13891419
public Map<String,String> customTypeParameters(MemberDetails attribute, ModelsContext context) {
13901420
return emptyMap();
13911421
}
1422+
1423+
@Override
1424+
public Annotation customTypeAnnotation(MemberDetails attribute, ModelsContext context) {
1425+
return null;
1426+
}
13921427
}
13931428

13941429
private static AnnotatedJoinColumns convertToJoinColumns(AnnotatedColumns columns, MetadataBuildingContext context) {

hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,9 +2029,9 @@ private BasicType<?> anyDiscriminatorType(Any anyBinding, TypeResolution discrim
20292029
);
20302030
}
20312031
else {
2032-
return metadataBuildingContext.getBootstrapContext()
2033-
.getTypeConfiguration().getBasicTypeRegistry()
2034-
.resolve( StandardBasicTypes.STRING );
2032+
return
2033+
metadataBuildingContext.getBootstrapContext().getTypeConfiguration().getBasicTypeRegistry()
2034+
.resolve( StandardBasicTypes.STRING );
20352035
}
20362036
}
20372037

hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
package org.hibernate.mapping;
66

7+
import java.lang.annotation.Annotation;
8+
import java.lang.reflect.InvocationTargetException;
79
import java.util.HashMap;
810
import java.util.Map;
911
import java.util.Properties;
@@ -1055,13 +1057,15 @@ public void setExplicitCustomType(Class<? extends UserType<?>> explicitCustomTyp
10551057
throw new UnsupportedOperationException( "Unsupported attempt to set an explicit-custom-type when value is already resolved" );
10561058
}
10571059
else {
1060+
final var typeProperties = getCustomTypeProperties();
1061+
final var typeAnnotation = getTypeAnnotation();
10581062
resolution = new UserTypeResolution<>(
10591063
new CustomType<>(
1060-
getConfiguredUserTypeBean( explicitCustomType, getCustomTypeProperties() ),
1064+
getConfiguredUserTypeBean( explicitCustomType, typeProperties, typeAnnotation ),
10611065
getTypeConfiguration()
10621066
),
10631067
null,
1064-
getCustomTypeProperties()
1068+
typeProperties
10651069
);
10661070
}
10671071
}
@@ -1078,11 +1082,9 @@ private Properties getCustomTypeProperties() {
10781082
return properties;
10791083
}
10801084

1081-
private UserType<?> getConfiguredUserTypeBean(Class<? extends UserType<?>> explicitCustomType, Properties properties) {
1082-
final var typeInstance =
1083-
getBuildingContext().getBuildingOptions().isAllowExtensionsInCdi()
1084-
? getUserTypeBean( explicitCustomType, properties ).getBeanInstance()
1085-
: FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( explicitCustomType );
1085+
private UserType<?> getConfiguredUserTypeBean(
1086+
Class<? extends UserType<?>> explicitCustomType, Properties properties, Annotation typeAnnotation) {
1087+
final var typeInstance = instantiateUserType( explicitCustomType, properties, typeAnnotation );
10861088

10871089
if ( typeInstance instanceof TypeConfigurationAware configurationAware ) {
10881090
configurationAware.setTypeConfiguration( getTypeConfiguration() );
@@ -1103,6 +1105,28 @@ private UserType<?> getConfiguredUserTypeBean(Class<? extends UserType<?>> expli
11031105
return typeInstance;
11041106
}
11051107

1108+
private <T extends UserType<?>> T instantiateUserType(
1109+
Class<T> customType, Properties properties, Annotation typeAnnotation) {
1110+
if ( typeAnnotation != null ) {
1111+
// attempt to instantiate it with the annotation as a constructor argument
1112+
try {
1113+
final var constructor = customType.getDeclaredConstructor( typeAnnotation.annotationType() );
1114+
constructor.setAccessible( true );
1115+
return constructor.newInstance( typeAnnotation );
1116+
}
1117+
catch ( NoSuchMethodException ignored ) {
1118+
// no such constructor, instantiate it the old way
1119+
}
1120+
catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
1121+
throw new org.hibernate.InstantiationException( "Could not instantiate custom type", customType, e );
1122+
}
1123+
}
1124+
1125+
return getBuildingContext().getBuildingOptions().isAllowExtensionsInCdi()
1126+
? getUserTypeBean( customType, properties ).getBeanInstance()
1127+
: FallbackBeanInstanceProducer.INSTANCE.produceBeanInstance( customType );
1128+
}
1129+
11061130
private <T> ManagedBean<? extends T> getUserTypeBean(Class<T> explicitCustomType, Properties properties) {
11071131
final var producer = getBootstrapContext().getCustomTypeProducer();
11081132
final var managedBeanRegistry = getManagedBeanRegistry();

hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public abstract class SimpleValue implements KeyValue {
8888

8989
private String typeName;
9090
private Properties typeParameters;
91+
private Annotation typeAnnotation;
9192
private boolean isVersion;
9293
private boolean isNationalized;
9394
private boolean isLob;
@@ -127,6 +128,7 @@ protected SimpleValue(SimpleValue original) {
127128
this.partitionKey = original.partitionKey;
128129
this.typeName = original.typeName;
129130
this.typeParameters = original.typeParameters == null ? null : new Properties( original.typeParameters );
131+
this.typeAnnotation = original.typeAnnotation;
130132
this.isVersion = original.isVersion;
131133
this.isNationalized = original.isNationalized;
132134
this.isLob = original.isLob;
@@ -792,11 +794,19 @@ public void setTypeParameters(Map<String, ?> parameters) {
792794
}
793795
}
794796

797+
public void setTypeAnnotation(Annotation typeAnnotation) {
798+
this.typeAnnotation = typeAnnotation;
799+
}
800+
795801
public Properties getTypeParameters() {
796802
return typeParameters;
797803
}
798804

799-
public void copyTypeFrom( SimpleValue sourceValue ) {
805+
public Annotation getTypeAnnotation() {
806+
return typeAnnotation;
807+
}
808+
809+
public void copyTypeFrom(SimpleValue sourceValue ) {
800810
setTypeName( sourceValue.getTypeName() );
801811
setTypeParameters( sourceValue.getTypeParameters() );
802812

@@ -818,6 +828,7 @@ public boolean isSame(SimpleValue other) {
818828
return Objects.equals( columns, other.columns )
819829
&& Objects.equals( typeName, other.typeName )
820830
&& Objects.equals( typeParameters, other.typeParameters )
831+
&& Objects.equals( typeAnnotation, other.typeAnnotation )
821832
&& Objects.equals( table, other.table )
822833
&& Objects.equals( foreignKeyName, other.foreignKeyName )
823834
&& Objects.equals( foreignKeyDefinition, other.foreignKeyDefinition );

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class BitSetHelper {
1616
public static String bitSetToString(BitSet bitSet) {
1717
StringBuilder builder = new StringBuilder();
1818
for (long token : bitSet.toLongArray()) {
19-
if (builder.length() > 0) {
19+
if ( !builder.isEmpty() ) {
2020
builder.append(DELIMITER);
2121
}
2222
builder.append(Long.toString(token, 2));

0 commit comments

Comments
 (0)