66
77import java .lang .annotation .Annotation ;
88import java .lang .reflect .InvocationTargetException ;
9+ import java .lang .reflect .ParameterizedType ;
910import java .util .HashMap ;
1011import java .util .Map ;
1112import java .util .Properties ;
1213import java .util .function .Consumer ;
1314import java .util .function .Function ;
1415
16+ import org .hibernate .AnnotationException ;
17+ import org .hibernate .AssertionFailure ;
1518import org .hibernate .Incubating ;
1619import org .hibernate .Internal ;
1720import org .hibernate .MappingException ;
21+ import org .hibernate .models .spi .MemberDetails ;
22+ import org .hibernate .service .ServiceRegistry ;
1823import org .hibernate .type .TimeZoneStorageStrategy ;
1924import org .hibernate .annotations .SoftDelete ;
2025import org .hibernate .annotations .SoftDeleteType ;
6570import org .hibernate .type .internal .ConvertedBasicTypeImpl ;
6671import org .hibernate .type .spi .TypeConfiguration ;
6772import org .hibernate .type .spi .TypeConfigurationAware ;
73+ import org .hibernate .usertype .AnnotationBasedUserType ;
6874import org .hibernate .usertype .DynamicParameterizedType ;
6975import org .hibernate .usertype .UserType ;
7076
7177import com .fasterxml .classmate .ResolvedType ;
7278import jakarta .persistence .AttributeConverter ;
7379import jakarta .persistence .EnumType ;
7480import jakarta .persistence .TemporalType ;
81+ import org .hibernate .usertype .UserTypeCreationContext ;
7582
7683import static java .lang .Boolean .parseBoolean ;
7784import static org .hibernate .boot .model .convert .spi .ConverterDescriptor .TYPE_NAME_PREFIX ;
8592
8693/**
8794 * @author Steve Ebersole
95+ * @author Yanming Zhou
8896 */
8997public class BasicValue extends SimpleValue
9098 implements JdbcTypeIndicators , Resolvable , JpaAttributeConverterCreationContext {
@@ -1080,9 +1088,10 @@ public void setExplicitCustomType(Class<? extends UserType<?>> explicitCustomTyp
10801088 else {
10811089 final var typeProperties = getCustomTypeProperties ();
10821090 final var typeAnnotation = getTypeAnnotation ();
1091+ final var memberDetails = getMemberDetails ();
10831092 resolution = new UserTypeResolution <>(
10841093 new CustomType <>(
1085- getConfiguredUserTypeBean ( explicitCustomType , typeProperties , typeAnnotation ),
1094+ getConfiguredUserTypeBean ( explicitCustomType , typeProperties , typeAnnotation , memberDetails ),
10861095 getTypeConfiguration ()
10871096 ),
10881097 null ,
@@ -1104,8 +1113,37 @@ private Properties getCustomTypeProperties() {
11041113 }
11051114
11061115 private UserType <?> getConfiguredUserTypeBean (
1107- Class <? extends UserType <?>> explicitCustomType , Properties properties , Annotation typeAnnotation ) {
1108- final var typeInstance = instantiateUserType ( explicitCustomType , properties , typeAnnotation );
1116+ Class <? extends UserType <?>> explicitCustomType , Properties properties , Annotation typeAnnotation , MemberDetails memberDetails ) {
1117+ final var creationContext = new UserTypeCreationContext () {
1118+ @ Override
1119+ public MetadataBuildingContext getBuildingContext () {
1120+ return BasicValue .this .getBuildingContext ();
1121+ }
1122+
1123+ @ Override
1124+ public ServiceRegistry getServiceRegistry () {
1125+ return BasicValue .this .getServiceRegistry ();
1126+ }
1127+
1128+ @ Override
1129+ public MemberDetails getMemberDetails () {
1130+ return memberDetails ;
1131+ }
1132+
1133+ @ Override
1134+ public Properties getParameters () {
1135+ return properties ;
1136+ }
1137+ };
1138+ final var typeInstance = instantiateUserType ( explicitCustomType , creationContext , typeAnnotation );
1139+
1140+ if ( typeInstance instanceof AnnotationBasedUserType <?, ?> annotationBased ) {
1141+ if ( typeAnnotation == null ) {
1142+ throw new AnnotationException ( String .format ( "Custom type '%s' implements 'AnnotationBasedUserType' but no custom type annotation is present" ,
1143+ typeInstance .getClass ().getName () ) );
1144+ }
1145+ initializeAnnotationBasedUserType ( properties , typeAnnotation , memberDetails , annotationBased );
1146+ }
11091147
11101148 if ( typeInstance instanceof TypeConfigurationAware configurationAware ) {
11111149 configurationAware .setTypeConfiguration ( getTypeConfiguration () );
@@ -1126,25 +1164,97 @@ private UserType<?> getConfiguredUserTypeBean(
11261164 return typeInstance ;
11271165 }
11281166
1167+ private <A extends Annotation > void initializeAnnotationBasedUserType (Properties properties ,
1168+ Annotation typeAnnotation ,
1169+ MemberDetails memberDetails ,
1170+ AnnotationBasedUserType <A , ?> annotationBased ) {
1171+ annotationBased .initialize ( castAnnotationType ( typeAnnotation , annotationBased ),
1172+ new UserTypeCreationContext () {
1173+ @ Override
1174+ public MetadataBuildingContext getBuildingContext () {
1175+ return BasicValue .this .getBuildingContext ();
1176+ }
1177+
1178+ @ Override
1179+ public ServiceRegistry getServiceRegistry () {
1180+ return BasicValue .this .getServiceRegistry ();
1181+ }
1182+
1183+ @ Override
1184+ public MemberDetails getMemberDetails () {
1185+ return memberDetails ;
1186+ }
1187+
1188+ @ Override
1189+ public Properties getParameters () {
1190+ return properties ;
1191+ }
1192+ } );
1193+ }
1194+
1195+ private <A extends Annotation > A castAnnotationType (
1196+ Annotation typeAnnotation , AnnotationBasedUserType <A , ?> annotationBased ) {
1197+ final var annotationType = annotationBased .getClass ();
1198+ for ( var iface : annotationType .getGenericInterfaces () ) {
1199+ if ( iface instanceof ParameterizedType parameterizedType
1200+ && parameterizedType .getRawType () == AnnotationBasedUserType .class ) {
1201+ final var typeArguments = parameterizedType .getActualTypeArguments ();
1202+ if ( typeArguments .length > 0
1203+ && typeArguments [0 ] instanceof Class <?> annotationClass ) {
1204+ if ( !annotationClass .isInstance ( typeAnnotation ) ) {
1205+ throw new AnnotationException ( String .format ( "Annotation '%s' is not assignable to '%s'" ,
1206+ annotationType .getName (), iface .getTypeName () ) );
1207+ }
1208+ @ SuppressWarnings ("unchecked" ) // safe, we just checked it
1209+ final var castAnnotation = (A ) typeAnnotation ;
1210+ return castAnnotation ;
1211+ }
1212+ }
1213+ }
1214+ throw new AssertionFailure ( "Could not find implementing interface" );
1215+ }
1216+
11291217 private <T extends UserType <?>> T instantiateUserType (
1130- Class <T > customType , Properties properties , Annotation typeAnnotation ) {
1131- if ( typeAnnotation != null ) {
1132- // attempt to instantiate it with the annotation as a constructor argument
1218+ Class <T > customType , UserTypeCreationContext creationContext , Annotation typeAnnotation ) {
1219+ try {
1220+ if ( typeAnnotation != null ) {
1221+ // attempt to instantiate it with the annotation and context object as constructor arguments
1222+ try {
1223+ final var constructor = customType .getDeclaredConstructor ( typeAnnotation .annotationType (),
1224+ UserTypeCreationContext .class );
1225+ constructor .setAccessible ( true );
1226+ return constructor .newInstance ( typeAnnotation , creationContext );
1227+ }
1228+ catch (NoSuchMethodException ignored ) {
1229+ // attempt to instantiate it with the annotation as a constructor argument
1230+ try {
1231+ final var constructor = customType .getDeclaredConstructor ( typeAnnotation .annotationType () );
1232+ constructor .setAccessible ( true );
1233+ return constructor .newInstance ( typeAnnotation );
1234+ }
1235+ catch (NoSuchMethodException ignored_ ) {
1236+ // no such constructor
1237+ }
1238+ }
1239+ }
1240+
1241+ // attempt to instantiate it with the context object as a constructor argument
11331242 try {
1134- final var constructor = customType .getDeclaredConstructor ( typeAnnotation . annotationType () );
1243+ final var constructor = customType .getDeclaredConstructor ( UserTypeCreationContext . class );
11351244 constructor .setAccessible ( true );
1136- return constructor .newInstance ( typeAnnotation );
1245+ return constructor .newInstance ( creationContext );
11371246 }
1138- catch ( NoSuchMethodException ignored ) {
1247+ catch (NoSuchMethodException ignored ) {
11391248 // no such constructor, instantiate it the old way
11401249 }
1141- catch (InvocationTargetException | InstantiationException | IllegalAccessException e ) {
1142- throw new org .hibernate .InstantiationException ( "Could not instantiate custom type" , customType , e );
1143- }
1250+
1251+ }
1252+ catch (InvocationTargetException | InstantiationException | IllegalAccessException e ) {
1253+ throw new org .hibernate .InstantiationException ( "Could not instantiate custom type" , customType , e );
11441254 }
11451255
11461256 return getBuildingContext ().getBuildingOptions ().isAllowExtensionsInCdi ()
1147- ? getUserTypeBean ( customType , properties ).getBeanInstance ()
1257+ ? getUserTypeBean ( customType , creationContext . getParameters () ).getBeanInstance ()
11481258 : FallbackBeanInstanceProducer .INSTANCE .produceBeanInstance ( customType );
11491259 }
11501260
0 commit comments