/
QueryParameterBindingValidator.java
182 lines (167 loc) · 5.64 KB
/
QueryParameterBindingValidator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.query.spi;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import javax.persistence.TemporalType;
import org.hibernate.type.Type;
/**
* @author Andrea Boriero
*/
public class QueryParameterBindingValidator {
public static final QueryParameterBindingValidator INSTANCE = new QueryParameterBindingValidator();
private QueryParameterBindingValidator() {
}
public <P> void validate(Type paramType, Object bind) {
validate( paramType, bind, null );
}
public <P> void validate(Type paramType, Object bind, TemporalType temporalType) {
if ( bind == null || paramType == null ) {
// nothing we can check
return;
}
final Class parameterType = paramType.getReturnedClass();
if ( parameterType == null ) {
// nothing we can check
return;
}
if ( Collection.class.isInstance( bind ) && !Collection.class.isAssignableFrom( parameterType ) ) {
// we have a collection passed in where we are expecting a non-collection.
// NOTE : this can happen in Hibernate's notion of "parameter list" binding
// NOTE2 : the case of a collection value and an expected collection (if that can even happen)
// will fall through to the main check.
validateCollectionValuedParameterBinding( parameterType, (Collection) bind, temporalType );
}
else if ( bind.getClass().isArray() ) {
validateArrayValuedParameterBinding( parameterType, bind, temporalType );
}
else {
if ( !isValidBindValue( parameterType, bind, temporalType ) ) {
throw new IllegalArgumentException(
String.format(
"Parameter value [%s] did not match expected type [%s (%s)]",
bind,
parameterType.getName(),
extractName( temporalType )
)
);
}
}
}
private String extractName(TemporalType temporalType) {
return temporalType == null ? "n/a" : temporalType.name();
}
private void validateCollectionValuedParameterBinding(
Class parameterType,
Collection value,
TemporalType temporalType) {
// validate the elements...
for ( Object element : value ) {
if ( !isValidBindValue( parameterType, element, temporalType ) ) {
throw new IllegalArgumentException(
String.format(
"Parameter value element [%s] did not match expected type [%s (%s)]",
element,
parameterType.getName(),
extractName( temporalType )
)
);
}
}
}
private static boolean isValidBindValue(Class expectedType, Object value, TemporalType temporalType) {
if ( expectedType.isPrimitive() ) {
if ( expectedType == boolean.class ) {
return Boolean.class.isInstance( value );
}
else if ( expectedType == char.class ) {
return Character.class.isInstance( value );
}
else if ( expectedType == byte.class ) {
return Byte.class.isInstance( value );
}
else if ( expectedType == short.class ) {
return Short.class.isInstance( value );
}
else if ( expectedType == int.class ) {
return Integer.class.isInstance( value );
}
else if ( expectedType == long.class ) {
return Long.class.isInstance( value );
}
else if ( expectedType == float.class ) {
return Float.class.isInstance( value );
}
else if ( expectedType == double.class ) {
return Double.class.isInstance( value );
}
return false;
}
else if ( value == null) {
return true;
}
else if ( expectedType.isInstance( value ) ) {
return true;
}
else if ( temporalType != null ) {
final boolean parameterDeclarationIsTemporal = Date.class.isAssignableFrom( expectedType )
|| Calendar.class.isAssignableFrom( expectedType );
final boolean bindIsTemporal = Date.class.isInstance( value )
|| Calendar.class.isInstance( value );
if ( parameterDeclarationIsTemporal && bindIsTemporal ) {
return true;
}
}
return false;
}
private void validateArrayValuedParameterBinding(
Class parameterType,
Object value,
TemporalType temporalType) {
if ( !parameterType.isArray() ) {
throw new IllegalArgumentException(
String.format(
"Encountered array-valued parameter binding, but was expecting [%s (%s)]",
parameterType.getName(),
extractName( temporalType )
)
);
}
if ( value.getClass().getComponentType().isPrimitive() ) {
// we have a primitive array. we validate that the actual array has the component type (type of elements)
// we expect based on the component type of the parameter specification
if ( !parameterType.getComponentType().isAssignableFrom( value.getClass().getComponentType() ) ) {
throw new IllegalArgumentException(
String.format(
"Primitive array-valued parameter bind value type [%s] did not match expected type [%s (%s)]",
value.getClass().getComponentType().getName(),
parameterType.getName(),
extractName( temporalType )
)
);
}
}
else {
// we have an object array. Here we loop over the array and physically check each element against
// the type we expect based on the component type of the parameter specification
final Object[] array = (Object[]) value;
for ( Object element : array ) {
if ( !isValidBindValue( parameterType.getComponentType(), element, temporalType ) ) {
throw new IllegalArgumentException(
String.format(
"Array-valued parameter value element [%s] did not match expected type [%s (%s)]",
element,
parameterType.getName(),
extractName( temporalType )
)
);
}
}
}
}
}