1111import java .util .function .Function ;
1212import java .util .function .Supplier ;
1313
14+ import org .checkerframework .checker .nullness .qual .NonNull ;
1415import org .hibernate .MappingException ;
1516import org .hibernate .boot .spi .BootstrapContext ;
1617import org .hibernate .boot .spi .MetadataBuildingContext ;
4546
4647import static org .hibernate .type .SqlTypes .SMALLINT ;
4748import static org .hibernate .type .descriptor .java .JavaTypeHelper .isTemporal ;
49+ import static org .hibernate .type .descriptor .java .TemporalJavaType .resolveJdbcTypeCode ;
4850
4951/**
5052 * BasicValue.Resolution resolver for cases where no explicit
@@ -156,23 +158,8 @@ else if ( explicitJdbcType != null ) {
156158 // there was not a "legacy" BasicType registration,
157159 // so use `JavaType#getRecommendedJdbcType`, if one,
158160 // to create a mapping
159- final JdbcType recommendedJdbcType ;
160- try {
161- recommendedJdbcType = reflectedJtd .getRecommendedJdbcType ( stdIndicators );
162- }
163- catch (JdbcTypeRecommendationException jtre ) {
164- if ( buildingContext .getMetadataCollector ()
165- .getEntityBindingMap ().values ().stream ()
166- .anyMatch ( pc -> pc .getMappedClass ().equals (resolvedJavaType ) ) ) {
167- throw new MappingException ( "Incorrect use of entity type '"
168- + resolvedJavaType .getTypeName ()
169- + "' (possibly due to missing association mapping annotation)" ,
170- jtre );
171- }
172- else {
173- throw jtre ;
174- }
175- }
161+ final JdbcType recommendedJdbcType =
162+ recommendedJdbcType ( resolvedJavaType , stdIndicators , buildingContext , reflectedJtd );
176163 if ( recommendedJdbcType != null ) {
177164 jdbcMapping = resolveSqlTypeIndicators (
178165 stdIndicators ,
@@ -254,6 +241,27 @@ else if ( column.getLength() != null ) {
254241 );
255242 }
256243
244+ private static <T > JdbcType recommendedJdbcType (
245+ Type resolvedJavaType ,
246+ JdbcTypeIndicators stdIndicators ,
247+ MetadataBuildingContext buildingContext ,
248+ JavaType <T > reflectedJtd ) {
249+ try {
250+ return reflectedJtd .getRecommendedJdbcType ( stdIndicators );
251+ }
252+ catch (JdbcTypeRecommendationException jtre ) {
253+ if ( buildingContext .getMetadataCollector ()
254+ .getEntityBindingMap ().values ().stream ()
255+ .anyMatch ( pc -> pc .getMappedClass ().equals ( resolvedJavaType ) ) ) {
256+ throw new MappingException ( "Incorrect use of entity type '" + resolvedJavaType .getTypeName ()
257+ + "' (possibly due to missing association mapping annotation)" , jtre );
258+ }
259+ else {
260+ throw jtre ;
261+ }
262+ }
263+ }
264+
257265 private static <T > BasicType <T > registeredType (
258266 JdbcType explicitJdbcType ,
259267 Function <TypeConfiguration , MutabilityPlan <?>> explicitMutabilityPlanAccess ,
@@ -489,43 +497,16 @@ public static <T> BasicValue.Resolution<T> fromTemporal(
489497 JdbcType explicitJdbcType ,
490498 Function <TypeConfiguration , MutabilityPlan <?>> explicitMutabilityPlanAccess ,
491499 JdbcTypeIndicators stdIndicators ) {
492- final var typeConfiguration = stdIndicators .getTypeConfiguration ();
493- final var basicTypeRegistry = typeConfiguration .getBasicTypeRegistry ();
494- final var requestedTemporalPrecision = stdIndicators .getTemporalPrecision ();
495500
496501 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
497502 // Case #1 - explicit JavaType
498503
499504 if ( explicitJavaType != null ) {
500- if ( !isTemporal ( explicitJavaType ) ) {
501- throw new MappingException (
502- "Explicit JavaType [" + explicitJavaType +
503- "] defined for temporal value must implement TemporalJavaType"
504- );
505- }
506-
507- @ SuppressWarnings ("unchecked" )
508- final var explicitTemporalJtd = (TemporalJavaType <T >) explicitJavaType ;
509- if ( requestedTemporalPrecision != null && explicitTemporalJtd .getPrecision () != requestedTemporalPrecision ) {
510- throw new MappingException (
511- "Temporal precision (`jakarta.persistence.TemporalType`) mismatch... requested precision = " + requestedTemporalPrecision +
512- "; explicit JavaType (`" + explicitTemporalJtd + "`) precision = " + explicitTemporalJtd .getPrecision ()
513-
514- );
515- }
516-
517- final var jdbcType =
518- explicitJdbcType != null
519- ? explicitJdbcType
520- : explicitTemporalJtd .getRecommendedJdbcType ( stdIndicators );
521- final var jdbcMapping = basicTypeRegistry .resolve ( explicitTemporalJtd , jdbcType );
522- return new InferredBasicValueResolution <>(
523- jdbcMapping ,
524- explicitTemporalJtd ,
525- explicitTemporalJtd ,
526- jdbcType ,
527- jdbcMapping ,
528- determineMutabilityPlan ( explicitMutabilityPlanAccess , explicitTemporalJtd , typeConfiguration )
505+ return fromTemporalExplicitJavaType (
506+ explicitJavaType ,
507+ explicitJdbcType ,
508+ explicitMutabilityPlanAccess ,
509+ stdIndicators
529510 );
530511 }
531512
@@ -536,19 +517,10 @@ public static <T> BasicValue.Resolution<T> fromTemporal(
536517 // due to the new annotations being used
537518
538519 if ( explicitJdbcType != null ) {
539- final TemporalJavaType <T > temporalJavaType =
540- requestedTemporalPrecision != null
541- ? reflectedJtd .resolveTypeForPrecision ( requestedTemporalPrecision , typeConfiguration )
542- // Avoid using the DateJavaType and prefer the JdbcTimestampJavaType
543- : reflectedJtd .resolveTypeForPrecision ( reflectedJtd .getPrecision (), typeConfiguration );
544- final var jdbcMapping = basicTypeRegistry .resolve ( temporalJavaType , explicitJdbcType );
545- return new InferredBasicValueResolution <>(
546- jdbcMapping ,
547- temporalJavaType ,
548- temporalJavaType ,
520+ return fromTemporalExplicitJdbcType (
521+ reflectedJtd ,
549522 explicitJdbcType ,
550- jdbcMapping ,
551- temporalJavaType .getMutabilityPlan ()
523+ stdIndicators
552524 );
553525 }
554526
@@ -558,12 +530,27 @@ public static <T> BasicValue.Resolution<T> fromTemporal(
558530 // - for the moment continue to use the legacy resolution to registered
559531 // BasicType
560532
533+ return fromTemporalImplicit (
534+ reflectedJtd ,
535+ explicitMutabilityPlanAccess ,
536+ stdIndicators
537+ );
538+ }
539+
540+ private static <T > @ NonNull InferredBasicValueResolution <T , T > fromTemporalImplicit (
541+ TemporalJavaType <T > reflectedJtd ,
542+ Function <TypeConfiguration , MutabilityPlan <?>> explicitMutabilityPlanAccess ,
543+ JdbcTypeIndicators stdIndicators ) {
544+ final var typeConfiguration = stdIndicators .getTypeConfiguration ();
545+ final var basicTypeRegistry = typeConfiguration .getBasicTypeRegistry ();
546+ final var requestedTemporalPrecision = stdIndicators .getTemporalPrecision ();
547+
561548 final BasicType <T > basicType ;
562549 if ( requestedTemporalPrecision != null
563550 && requestedTemporalPrecision != reflectedJtd .getPrecision () ) {
564551 basicType = basicTypeRegistry .resolve (
565552 reflectedJtd .resolveTypeForPrecision ( requestedTemporalPrecision , typeConfiguration ),
566- TemporalJavaType . resolveJdbcTypeCode ( requestedTemporalPrecision )
553+ resolveJdbcTypeCode ( requestedTemporalPrecision )
567554 );
568555 }
569556 else {
@@ -583,6 +570,69 @@ public static <T> BasicValue.Resolution<T> fromTemporal(
583570 );
584571 }
585572
573+ private static <T > @ NonNull InferredBasicValueResolution <T , T > fromTemporalExplicitJdbcType (
574+ TemporalJavaType <T > reflectedJtd ,
575+ JdbcType explicitJdbcType ,
576+ JdbcTypeIndicators stdIndicators ) {
577+ final var typeConfiguration = stdIndicators .getTypeConfiguration ();
578+ final var basicTypeRegistry = typeConfiguration .getBasicTypeRegistry ();
579+ final var requestedTemporalPrecision = stdIndicators .getTemporalPrecision ();
580+
581+ final var temporalJavaType =
582+ requestedTemporalPrecision != null
583+ ? reflectedJtd .resolveTypeForPrecision ( requestedTemporalPrecision , typeConfiguration )
584+ : reflectedJtd .resolveTypeForPrecision ( reflectedJtd .getPrecision (), typeConfiguration );
585+ final var jdbcMapping = basicTypeRegistry .resolve ( temporalJavaType , explicitJdbcType );
586+ return new InferredBasicValueResolution <>(
587+ jdbcMapping ,
588+ temporalJavaType ,
589+ temporalJavaType ,
590+ explicitJdbcType ,
591+ jdbcMapping ,
592+ temporalJavaType .getMutabilityPlan ()
593+ );
594+ }
595+
596+ private static <T > @ NonNull InferredBasicValueResolution <T , T > fromTemporalExplicitJavaType (
597+ BasicJavaType <?> explicitJavaType ,
598+ JdbcType explicitJdbcType ,
599+ Function <TypeConfiguration , MutabilityPlan <?>> explicitMutabilityPlanAccess ,
600+ JdbcTypeIndicators stdIndicators ) {
601+ final var typeConfiguration = stdIndicators .getTypeConfiguration ();
602+ final var basicTypeRegistry = typeConfiguration .getBasicTypeRegistry ();
603+ final var requestedTemporalPrecision = stdIndicators .getTemporalPrecision ();
604+
605+ if ( !isTemporal ( explicitJavaType ) ) {
606+ throw new MappingException ( "Explicit JavaType [" + explicitJavaType +
607+ "] defined for temporal value must implement TemporalJavaType" );
608+ }
609+
610+ @ SuppressWarnings ("unchecked" )
611+ final var explicitTemporalJtd = (TemporalJavaType <T >) explicitJavaType ;
612+ if ( requestedTemporalPrecision != null
613+ && explicitTemporalJtd .getPrecision () != requestedTemporalPrecision ) {
614+ throw new MappingException (
615+ "Temporal precision (TemporalType) mismatch; requested precision = %s; explicit JavaType (%s) precision = %s"
616+ .formatted ( requestedTemporalPrecision , explicitTemporalJtd , explicitTemporalJtd .getPrecision () )
617+
618+ );
619+ }
620+
621+ final var jdbcType =
622+ explicitJdbcType != null
623+ ? explicitJdbcType
624+ : explicitTemporalJtd .getRecommendedJdbcType ( stdIndicators );
625+ final var jdbcMapping = basicTypeRegistry .resolve ( explicitTemporalJtd , jdbcType );
626+ return new InferredBasicValueResolution <>(
627+ jdbcMapping ,
628+ explicitTemporalJtd ,
629+ explicitTemporalJtd ,
630+ jdbcType ,
631+ jdbcMapping ,
632+ determineMutabilityPlan ( explicitMutabilityPlanAccess , explicitTemporalJtd , typeConfiguration )
633+ );
634+ }
635+
586636 private static <T > MutabilityPlan <T > determineMutabilityPlan (
587637 Function <TypeConfiguration , MutabilityPlan <?>> explicitMutabilityPlanAccess ,
588638 JavaType <T > javaType ,
0 commit comments