Skip to content

Commit 8c21efd

Browse files
committed
simplify the exception model for query arguments/parameters
1 parent 55df589 commit 8c21efd

File tree

4 files changed

+56
-116
lines changed

4 files changed

+56
-116
lines changed

hibernate-core/src/main/java/org/hibernate/query/QueryArgumentException.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,31 @@
1515
*/
1616
public class QueryArgumentException extends IllegalArgumentException {
1717
private final Class<?> parameterType;
18+
private final Class<?> argumentType;
1819
private final Object argument;
1920

2021
public QueryArgumentException(String message, Class<?> parameterType, Object argument) {
21-
super(message);
22+
super( message + " (argument [" + argument + "] is not assignable to " + parameterType.getName() + ")" );
2223
this.parameterType = parameterType;
24+
this.argumentType = argument == null ? null : argument.getClass();
25+
this.argument = argument;
26+
}
27+
28+
public QueryArgumentException(String message, Class<?> parameterType, Class<?> argumentType, Object argument) {
29+
super( message + " (" + argumentType.getName() + " is not assignable to " + parameterType.getName() + ")" );
30+
this.parameterType = parameterType;
31+
this.argumentType = argumentType;
2332
this.argument = argument;
2433
}
2534

2635
public Class<?> getParameterType() {
2736
return parameterType;
2837
}
2938

39+
public Class<?> getArgumentType() {
40+
return argumentType;
41+
}
42+
3043
public Object getArgument() {
3144
return argument;
3245
}

hibernate-core/src/main/java/org/hibernate/query/QueryArgumentTypeException.java

Lines changed: 0 additions & 31 deletions
This file was deleted.

hibernate-core/src/main/java/org/hibernate/query/spi/AbstractCommonQueryContract.java

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import org.hibernate.query.QueryFlushMode;
3636
import org.hibernate.query.QueryParameter;
3737
import org.hibernate.query.TypedParameterValue;
38-
import org.hibernate.query.QueryArgumentTypeException;
3938
import org.hibernate.query.criteria.JpaExpression;
4039
import org.hibernate.query.internal.QueryOptionsImpl;
4140
import org.hibernate.query.sqm.NodeBuilder;
@@ -643,10 +642,9 @@ public <T> QueryParameterImplementor<T> getParameter(String name, Class<T> type)
643642
try {
644643
final var parameter = getParameterMetadata().getQueryParameter( name );
645644
if ( !type.isAssignableFrom( parameter.getParameterType() ) ) {
646-
throw new QueryArgumentTypeException(
647-
"Type specified for parameter named '" + name + "' is incompatible",
648-
parameter.getParameterType(),
649-
type
645+
throw new IllegalArgumentException(
646+
"Type specified for parameter named '" + name + "' is incompatible"
647+
+ " (" + parameter.getParameterType().getName() + " is not assignable to " + type.getName() + ")"
650648
);
651649
}
652650
@SuppressWarnings("unchecked") // safe, just checked
@@ -673,10 +671,9 @@ public <T> QueryParameterImplementor<T> getParameter(int position, Class<T> type
673671
try {
674672
final var parameter = getParameterMetadata().getQueryParameter( position );
675673
if ( !type.isAssignableFrom( parameter.getParameterType() ) ) {
676-
throw new QueryArgumentTypeException(
677-
"Type specified for parameter at position " + position + " is incompatible",
678-
parameter.getParameterType(),
679-
type
674+
throw new IllegalArgumentException(
675+
"Type specified for parameter at position " + position + " is incompatible"
676+
+ " (" + parameter.getParameterType().getName() + " is not assignable to " + type.getName() + ")"
680677
);
681678
}
682679
@SuppressWarnings("unchecked") // safe, just checked
@@ -746,9 +743,9 @@ protected <P> QueryParameterBinding<P> locateBinding(String name, Class<P> javaT
746743
final var parameterJavaType = parameterType.getJavaType();
747744
if ( !parameterJavaType.isAssignableFrom( javaType )
748745
&& !isInstance( parameterType, value ) ) {
749-
throw new QueryArgumentTypeException(
746+
throw new QueryArgumentException(
750747
"Argument to parameter named '" + name + "' has an incompatible type",
751-
parameterJavaType, javaType);
748+
parameterJavaType, javaType, value );
752749
}
753750
}
754751
@SuppressWarnings("unchecked") // safe, just checked
@@ -764,9 +761,9 @@ protected <P> QueryParameterBinding<P> locateBinding(int position, Class<P> java
764761
final var parameterJavaType = parameterType.getJavaType();
765762
if ( !parameterJavaType.isAssignableFrom( javaType )
766763
&& !isInstance( parameterType, value ) ) {
767-
throw new QueryArgumentTypeException(
764+
throw new QueryArgumentException(
768765
"Argument to parameter at position " + position + " has an incompatible type",
769-
parameterJavaType, javaType );
766+
parameterJavaType, javaType, value );
770767
}
771768
}
772769
@SuppressWarnings("unchecked") // safe, just checked
@@ -782,9 +779,9 @@ protected <P> QueryParameterBinding<P> locateBinding(String name, Class<P> javaT
782779
final var parameterJavaType = parameterType.getJavaType();
783780
if ( !parameterJavaType.isAssignableFrom( javaType )
784781
&& !areInstances( parameterType, values ) ) {
785-
throw new QueryArgumentTypeException(
782+
throw new QueryArgumentException(
786783
"Argument to parameter named '" + name + "' has an incompatible type",
787-
parameterJavaType, javaType);
784+
parameterJavaType, javaType, values );
788785
}
789786
}
790787
@SuppressWarnings("unchecked") // safe, just checked
@@ -800,9 +797,9 @@ protected <P> QueryParameterBinding<P> locateBinding(int position, Class<P> java
800797
final var parameterJavaType = parameterType.getJavaType();
801798
if ( !parameterJavaType.isAssignableFrom( javaType )
802799
&& !areInstances( parameterType, values ) ) {
803-
throw new QueryArgumentTypeException(
800+
throw new QueryArgumentException(
804801
"Argument to parameter at position " + position + " has an incompatible type",
805-
parameterJavaType, javaType );
802+
parameterJavaType, javaType, values );
806803
}
807804
}
808805
@SuppressWarnings("unchecked") // safe, just checked
@@ -865,8 +862,8 @@ private <P> void setParameterValue(Object value, QueryParameterBinding<P> bindin
865862
final var parameterType = binding.getBindType();
866863
if ( parameterType != null
867864
&& !isInstanceOrAreInstances( value, binding, parameterType ) ) {
868-
throw new QueryArgumentTypeException( "Argument to query parameter has an incompatible type",
869-
parameterType.getJavaType(), value.getClass() );
865+
throw new QueryArgumentException( "Argument to query parameter has an incompatible type",
866+
parameterType.getJavaType(), value.getClass(), value );
870867
}
871868
@SuppressWarnings("unchecked") // safe, just checked
872869
final var castValue = (P) value;
@@ -1187,8 +1184,8 @@ private <P> void setParameterValues(Object[] values, QueryParameterBinding<P> bi
11871184
final var parameterType = binding.getBindType();
11881185
if ( parameterType != null
11891186
&& !areInstances( values, parameterType ) ) {
1190-
throw new QueryArgumentTypeException( "Argument to query parameter has an incompatible type",
1191-
parameterType.getJavaType(), values.getClass().getComponentType() );
1187+
throw new QueryArgumentException( "Argument to query parameter has an incompatible type",
1188+
parameterType.getJavaType(), values.getClass().getComponentType(), values );
11921189
}
11931190
@SuppressWarnings("unchecked") // safe, just checked
11941191
final var castArray = (P[]) values;

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

Lines changed: 24 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import java.util.Date;
1010

1111
import org.hibernate.query.QueryArgumentException;
12-
import org.hibernate.query.sqm.SqmBindableType;
1312
import org.hibernate.type.BindableType;
1413
import org.hibernate.type.BindingContext;
1514
import org.hibernate.type.descriptor.java.JavaType;
@@ -40,8 +39,8 @@ public void validate(
4039
return;
4140
}
4241

43-
final SqmBindableType<?> sqmExpressible = bindingContext.resolveExpressible( paramType );
44-
final Class<?> parameterJavaType =
42+
final var sqmExpressible = bindingContext.resolveExpressible( paramType );
43+
final var parameterJavaType =
4544
paramType.getJavaType() != null
4645
? paramType.getJavaType()
4746
: sqmExpressible.getJavaType();
@@ -50,9 +49,9 @@ public void validate(
5049
if ( bind instanceof Collection<?> collection
5150
&& !Collection.class.isAssignableFrom( parameterJavaType ) ) {
5251
// we have a collection passed in where we are expecting a non-collection.
53-
// NOTE : this can happen in Hibernate's notion of "parameter list" binding
54-
// NOTE2 : the case of a collection value and an expected collection (if that can even happen)
55-
// will fall through to the main check.
52+
// NOTE: this can happen in Hibernate's notion of "parameter list" binding
53+
// NOTE2: the case of a collection value and an expected collection (if that can even happen)
54+
// will fall through to the main check.
5655
validateCollectionValuedParameterBinding(
5756
parameterJavaType,
5857
collection,
@@ -72,17 +71,8 @@ else if ( !isValidBindValue(
7271
bind,
7372
temporalPrecision
7473
) ) {
75-
throw new QueryArgumentException(
76-
String.format(
77-
"Argument [%s] of type [%s] did not match parameter type [%s (%s)]",
78-
bind,
79-
bind.getClass().getName(),
80-
parameterJavaType.getName(),
81-
extractName( temporalPrecision )
82-
),
83-
parameterJavaType,
84-
bind
85-
);
74+
throw new QueryArgumentException( "Argument did not match parameter type",
75+
parameterJavaType, bind );
8676
}
8777
}
8878
// else nothing we can check
@@ -99,17 +89,8 @@ private void validateCollectionValuedParameterBinding(
9989
// validate the elements...
10090
for ( Object element : value ) {
10191
if ( !isValidBindValue( parameterType, element, temporalType ) ) {
102-
throw new QueryArgumentException(
103-
String.format(
104-
"Parameter value element [%s] did not match expected type [%s (%s)]",
105-
element,
106-
parameterType.getName(),
107-
extractName( temporalType )
108-
)
109-
,
110-
parameterType,
111-
element
112-
);
92+
throw new QueryArgumentException( "Argument element did not match parameter type",
93+
parameterType, element );
11394
}
11495
}
11596
}
@@ -175,11 +156,12 @@ else if ( expectedType.isInstance( value ) ) {
175156
return true;
176157
}
177158
else if ( temporalType != null ) {
178-
final boolean parameterDeclarationIsTemporal = Date.class.isAssignableFrom( expectedType )
159+
final boolean parameterDeclarationIsTemporal =
160+
Date.class.isAssignableFrom( expectedType )
179161
|| Calendar.class.isAssignableFrom( expectedType );
180-
final boolean bindIsTemporal = value instanceof Date
162+
final boolean bindIsTemporal =
163+
value instanceof Date
181164
|| value instanceof Calendar;
182-
183165
return parameterDeclarationIsTemporal && bindIsTemporal;
184166
}
185167

@@ -191,49 +173,28 @@ private void validateArrayValuedParameterBinding(
191173
Object value,
192174
TemporalType temporalType) {
193175
if ( !parameterType.isArray() ) {
194-
throw new QueryArgumentException(
195-
String.format(
196-
"Encountered array-valued parameter binding, but was expecting [%s (%s)]",
197-
parameterType.getName(),
198-
extractName( temporalType )
199-
),
200-
parameterType,
201-
value
202-
);
176+
throw new QueryArgumentException( "Unexpected array-valued parameter binding",
177+
parameterType, value );
203178
}
204179

205-
if ( value.getClass().getComponentType().isPrimitive() ) {
180+
final var componentType = value.getClass().getComponentType();
181+
final var parameterComponentType = parameterType.getComponentType();
182+
if ( componentType.isPrimitive() ) {
206183
// we have a primitive array. we validate that the actual array has the component type (type of elements)
207184
// we expect based on the component type of the parameter specification
208-
if ( !parameterType.getComponentType().isAssignableFrom( value.getClass().getComponentType() ) ) {
209-
throw new QueryArgumentException(
210-
String.format(
211-
"Primitive array-valued parameter bind value type [%s] did not match expected type [%s (%s)]",
212-
value.getClass().getComponentType().getName(),
213-
parameterType.getName(),
214-
extractName( temporalType )
215-
),
216-
parameterType,
217-
value
218-
);
185+
if ( !parameterComponentType.isAssignableFrom( componentType ) ) {
186+
throw new QueryArgumentException( "Primitive array-valued argument type did not match parameter type",
187+
parameterType, value );
219188
}
220189
}
221190
else {
222191
// we have an object array. Here we loop over the array and physically check each element against
223192
// the type we expect based on the component type of the parameter specification
224193
final Object[] array = (Object[]) value;
225194
for ( Object element : array ) {
226-
if ( !isValidBindValue( parameterType.getComponentType(), element, temporalType ) ) {
227-
throw new QueryArgumentException(
228-
String.format(
229-
"Array-valued parameter value element [%s] did not match expected type [%s (%s)]",
230-
element,
231-
parameterType.getName(),
232-
extractName( temporalType )
233-
),
234-
parameterType,
235-
array
236-
);
195+
if ( !isValidBindValue( parameterComponentType, element, temporalType ) ) {
196+
throw new QueryArgumentException( "Array-valued argument type did not match parameter type",
197+
parameterType, array );
237198
}
238199
}
239200
}

0 commit comments

Comments
 (0)