Skip to content

Commit 0722f2c

Browse files
committed
rethink of the previous approach to query parameter binding validation
1 parent da91390 commit 0722f2c

File tree

3 files changed

+44
-24
lines changed

3 files changed

+44
-24
lines changed

hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ private T cast(Object value) {
304304
}
305305

306306
private void validate(Object value) {
307-
QueryParameterBindingValidator.validate( getBindType(), value, sessionFactory );
307+
QueryParameterBindingValidator.validate( queryParameter, bindType, value, sessionFactory );
308308
}
309309

310310
private Object coerce(Object value) {

hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingValidator.java

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66

77
import java.util.Collection;
88

9+
import org.checkerframework.checker.nullness.qual.NonNull;
910
import org.hibernate.engine.spi.SessionFactoryImplementor;
1011
import org.hibernate.query.QueryArgumentException;
12+
import org.hibernate.query.QueryParameter;
1113
import org.hibernate.type.BindableType;
1214

1315
import static org.hibernate.query.internal.QueryArguments.areInstances;
@@ -21,30 +23,41 @@ class QueryParameterBindingValidator {
2123
private QueryParameterBindingValidator() {
2224
}
2325

24-
public static void validate(BindableType<?> parameterType, Object argument, SessionFactoryImplementor factory) {
26+
public static void validate(
27+
QueryParameter<?> parameter,
28+
BindableType<?> parameterType,
29+
Object argument,
30+
SessionFactoryImplementor factory) {
2531
if ( argument != null && parameterType != null ) {
2632
final var parameterJavaType = getParameterJavaType( parameterType, factory );
2733
if ( parameterJavaType != null ) {
34+
final var criteriaBuilder = factory.getQueryEngine().getCriteriaBuilder();
2835
if ( argument instanceof Collection<?> collection
2936
&& !Collection.class.isAssignableFrom( parameterJavaType ) ) {
3037
// We have a collection passed in where we were expecting a non-collection.
3138
// NOTE: This can happen in Hibernate's notion of "parameter list" binding.
3239
// NOTE2: The case of a collection value and an expected collection
3340
// (if that can even happen) will fall through to the main check.
34-
validateCollectionValuedParameterBinding( parameterType, parameterJavaType, collection, factory );
41+
if ( !areInstances( parameterType, collection, criteriaBuilder ) ) {
42+
throw queryArgumentException( parameterJavaType, collection, parameter );
43+
}
3544
}
36-
else if ( argument.getClass().isArray() ) {
37-
validateArrayValuedParameterBinding( parameterJavaType, argument );
45+
else if ( !argument.getClass().isArray() ) {
46+
// assume single-valued argument
47+
if ( !isInstance( parameterType, argument, criteriaBuilder ) ) {
48+
throw queryArgumentException( parameterJavaType, argument, parameter );
49+
}
3850
}
3951
else {
40-
validateSingleValuedParameterBinding( parameterType, parameterJavaType, argument, factory );
52+
validateArrayValuedParameterBinding( parameterJavaType, argument, parameter );
4153
}
4254
}
4355
// else nothing we can check
4456
}
4557
}
4658

47-
private static Class<?> getParameterJavaType(BindableType<?> parameterType, SessionFactoryImplementor factory) {
59+
private static Class<?> getParameterJavaType(
60+
BindableType<?> parameterType, SessionFactoryImplementor factory) {
4861
final var javaType = parameterType.getJavaType();
4962
return javaType != null
5063
? javaType
@@ -53,30 +66,37 @@ private static Class<?> getParameterJavaType(BindableType<?> parameterType, Sess
5366
.getJavaType();
5467
}
5568

56-
private static void validateSingleValuedParameterBinding(
57-
BindableType<?> parameterType, Class<?> parameterJavaType,
58-
Object value,
59-
SessionFactoryImplementor factory) {
60-
if ( !isInstance( parameterType, value,
61-
factory.getQueryEngine().getCriteriaBuilder() ) ) {
62-
throw new QueryArgumentException( "Argument did not match parameter type",
69+
private static @NonNull QueryArgumentException queryArgumentException(
70+
Class<?> parameterJavaType, Object value, QueryParameter<?> parameter) {
71+
if ( parameter.isNamed() ) {
72+
return new QueryArgumentException( "Argument to parameter named '"
73+
+ parameter.getName() + "' has an element with an incompatible type",
74+
parameterJavaType, value );
75+
}
76+
else {
77+
return new QueryArgumentException( "Argument to parameter at position "
78+
+ parameter.isOrdinal() + " has an element with an incompatible type",
6379
parameterJavaType, value );
6480
}
6581
}
6682

67-
private static void validateCollectionValuedParameterBinding(
68-
BindableType<?> parameterType, Class<?> parameterJavaType,
69-
Collection<?> values,
70-
SessionFactoryImplementor factory) {
71-
if ( !areInstances( parameterType, values,
72-
factory.getQueryEngine().getCriteriaBuilder() ) ) {
73-
throw new QueryArgumentException( "Collection-valued argument did not match parameter type",
83+
private static @NonNull QueryArgumentException queryArgumentException(
84+
Class<?> parameterJavaType, Collection<?> values, QueryParameter<?> parameter) {
85+
if ( parameter.isNamed() ) {
86+
return new QueryArgumentException( "Collection-values argument to parameter named '"
87+
+ parameter.getName() + "' has an incompatible type",
88+
parameterJavaType, values );
89+
}
90+
else {
91+
return new QueryArgumentException( "Collection-values argument to parameter at position "
92+
+ parameter.isOrdinal() + " has has an incompatible type",
7493
parameterJavaType, values );
75-
7694
}
7795
}
7896

79-
private static void validateArrayValuedParameterBinding(Class<?> parameterType, Object value) {
97+
private static void validateArrayValuedParameterBinding(
98+
Class<?> parameterType, Object value, QueryParameter<?> parameter) {
99+
// TODO: improve the error messages using the given parameter info
80100
if ( !parameterType.isArray() ) {
81101
throw new QueryArgumentException( "Unexpected array-valued parameter binding",
82102
parameterType, value );

hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ObjectParameterTypeForEmbeddableTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public void testSettingParameterOfTypeWrongType(EntityManagerFactoryScope scope)
9797
)
9898
);
9999

100-
assertThat( thrown.getMessage() ).contains( "did not match parameter type" );
100+
assertThat( thrown.getMessage() ).contains( "incompatible type" );
101101
}
102102

103103
@Entity(name = "TestEntity")

0 commit comments

Comments
 (0)