28
28
import org .hibernate .query .sqm .tree .expression .SqmLiteralNull ;
29
29
import org .hibernate .type .BasicPluralType ;
30
30
import org .hibernate .type .BasicType ;
31
+ import org .hibernate .type .ConvertedBasicType ;
31
32
import org .hibernate .type .QueryParameterJavaObjectType ;
32
33
import org .hibernate .type .descriptor .converter .spi .BasicValueConverter ;
33
34
import org .hibernate .type .descriptor .jdbc .JdbcType ;
34
35
35
36
import java .time .temporal .Temporal ;
36
37
import java .time .temporal .TemporalAmount ;
38
+ import java .util .Objects ;
37
39
38
40
import static org .hibernate .type .descriptor .java .JavaTypeHelper .isUnknown ;
39
41
@@ -110,7 +112,16 @@ public static boolean areTypesComparable(
110
112
return true ;
111
113
}
112
114
113
- // for query with parameters we are unable to resolve the correct JavaType, especially for tuple of parameters
115
+ // if one of the types is unknown, assume that this is the result
116
+ // of an error that will be detected / reported elsewhere
117
+
118
+ if ( isUnknown ( lhsType .getExpressibleJavaType () )
119
+ || isUnknown ( rhsType .getExpressibleJavaType () ) ) {
120
+ return true ;
121
+ }
122
+
123
+ // for query with parameters we are unable to resolve the correct JavaType,
124
+ // especially for tuple of parameters
114
125
115
126
if ( lhsType instanceof QueryParameterJavaObjectType || rhsType instanceof QueryParameterJavaObjectType ) {
116
127
return true ;
@@ -177,18 +188,17 @@ && areJdbcMappingsComparable( lhsMapping, rhsMapping, bindingContext ) ) {
177
188
return true ;
178
189
}
179
190
180
- // Workaround: these are needed for a handful of slightly "weird" cases
181
- // involving Java field literals and converters, where we don't have
182
- // access to the correct JDBC type above. However, this is exactly the
183
- // sort of hole warned about above, and accepts many things which are
184
- // not well-typed.
191
+ // if one of the types has a ValueConverter, things get really complicated
192
+ // we do something a bit broken here and check that the Java types
185
193
186
- // // TODO: sort all this out, and remove this branch
187
- if ( isSameJavaType ( lhsType , rhsType ) ) {
194
+ if ( ( isConvertedType ( lhsType ) || isConvertedType ( rhsType ) )
195
+ && sameJavaType ( lhsType , rhsType ) ) {
188
196
return true ;
189
197
}
190
198
191
- return false ;
199
+ // if both have the same JDBC type, the assignment is acceptable
200
+
201
+ return lhsType .getRelationalJavaType () == rhsType .getRelationalJavaType ();
192
202
}
193
203
194
204
private static boolean areJdbcMappingsComparable (
@@ -310,6 +320,14 @@ private static boolean isTypeAssignable(
310
320
return true ;
311
321
}
312
322
323
+ // if one of the types is unknown, assume that this is the result
324
+ // of an error that will be detected / reported elsewhere
325
+
326
+ if ( isUnknown ( targetType .getExpressibleJavaType () )
327
+ || isUnknown ( expressionType .getExpressibleJavaType () ) ) {
328
+ return true ;
329
+ }
330
+
313
331
// entities can be assigned if they belong to the same inheritance hierarchy
314
332
315
333
if ( targetType instanceof EntityType <?> targetEntity
@@ -339,25 +357,39 @@ private static boolean isTypeAssignable(
339
357
}
340
358
}
341
359
342
- // Workaround: these are needed for a handful of slightly "weird" cases
343
- // involving Java field literals and converters, where we don't have
344
- // access to the correct JDBC type above. However, this is exactly the
345
- // sort of hole warned about above, and accepts many things which are
346
- // not well-typed.
360
+ // if one of the types has a ValueConverter, things get really complicated
361
+ // we do something a bit broken here and check that the Java types
347
362
348
- // TODO: sort all this out, and remove this branch
349
- if ( isSameJavaType ( targetType , expressionType ) ) {
363
+ if ( ( isConvertedType ( targetType ) || isConvertedType ( expressionType ) )
364
+ && sameJavaType ( targetType , expressionType ) ) {
350
365
return true ;
351
366
}
352
367
353
- return false ;
368
+ // if both have the same JDBC type, the assignment is acceptable
369
+
370
+ return targetType .getRelationalJavaType () == expressionType .getRelationalJavaType ();
371
+ }
372
+
373
+ private static boolean sameJavaType (SqmExpressible <?> leftType , SqmExpressible <?> rightType ) {
374
+ return canonicalize ( leftType .getBindableJavaType () ) == canonicalize ( rightType .getBindableJavaType () );
354
375
}
355
376
356
- private static boolean isSameJavaType (SqmExpressible <?> leftType , SqmExpressible <?> rightType ) {
357
- return isUnknown ( leftType .getExpressibleJavaType () ) || isUnknown ( rightType .getExpressibleJavaType () )
358
- || leftType .getRelationalJavaType () == rightType .getRelationalJavaType ()
359
- || leftType .getExpressibleJavaType () == rightType .getExpressibleJavaType ()
360
- || leftType .getBindableJavaType () == rightType .getBindableJavaType ();
377
+ private static boolean isConvertedType (SqmExpressible <?> type ) {
378
+ return type .getSqmType () instanceof ConvertedBasicType <?>;
379
+ }
380
+
381
+ private static Class <?> canonicalize (Class <?> lhs ) {
382
+ return switch (lhs .getCanonicalName ()) {
383
+ case "boolean" -> Boolean .class ;
384
+ case "byte" -> Byte .class ;
385
+ case "short" -> Short .class ;
386
+ case "int" -> Integer .class ;
387
+ case "long" -> Long .class ;
388
+ case "float" -> Float .class ;
389
+ case "double" -> Double .class ;
390
+ case "char" -> Character .class ;
391
+ default -> lhs ;
392
+ };
361
393
}
362
394
363
395
private static boolean isEntityTypeAssignable (
@@ -396,7 +428,19 @@ public static void assertComparable(Expression<?> x, Expression<?> y, BindingCon
396
428
if ( !( left instanceof SqmLiteralNull ) && !( right instanceof SqmLiteralNull ) ) {
397
429
final SqmExpressible <?> leftType = left .getExpressible ();
398
430
final SqmExpressible <?> rightType = right .getExpressible ();
399
- if ( !areTypesComparable ( leftType , rightType , bindingContext ) ) {
431
+ if ( leftType != null && rightType != null
432
+ && left .isEnum () && right .isEnum () ) {
433
+ // this is needed by Hibernate Processor due to the weird
434
+ // handling of enumerated types in the annotation processor
435
+ if ( !Objects .equals ( leftType .getTypeName (), rightType .getTypeName () ) ) {
436
+ String .format (
437
+ "Cannot compare left expression of enumerated type '%s' with right expression of enumerated type '%s'" ,
438
+ leftType .getTypeName (),
439
+ rightType .getTypeName ()
440
+ );
441
+ }
442
+ }
443
+ else if ( !areTypesComparable ( leftType , rightType , bindingContext ) ) {
400
444
throw new SemanticException (
401
445
String .format (
402
446
"Cannot compare left expression of type '%s' with right expression of type '%s'" ,
@@ -422,7 +466,18 @@ public static void assertAssignable(
422
466
else {
423
467
final SqmPathSource <?> targetType = targetPath .getNodeType ();
424
468
final SqmExpressible <?> expressionType = expression .getNodeType ();
425
- if ( !isTypeAssignable ( targetType , expressionType , bindingContext ) ) {
469
+ if ( targetType != null && expressionType != null && targetPath .isEnum () ) {
470
+ // this is needed by Hibernate Processor due to the weird
471
+ // handling of enumerated types in the annotation processor
472
+ if ( !Objects .equals ( targetType .getTypeName (), expressionType .getTypeName () ) ) {
473
+ String .format (
474
+ "Cannot compare left expression of enumerated type '%s' with right expression of enumerated type '%s'" ,
475
+ targetType .getTypeName (),
476
+ expressionType .getTypeName ()
477
+ );
478
+ }
479
+ }
480
+ else if ( !isTypeAssignable ( targetType , expressionType , bindingContext ) ) {
426
481
throw new SemanticException (
427
482
String .format (
428
483
"Cannot assign expression of type '%s' to target path '%s' of type '%s'" ,
0 commit comments