1
1
/*
2
- * Copyright 2008-2012 the original author or authors.
2
+ * Copyright 2008-2015 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
25
25
import javax .persistence .criteria .CriteriaBuilder ;
26
26
import javax .persistence .criteria .CriteriaQuery ;
27
27
import javax .persistence .criteria .Expression ;
28
+ import javax .persistence .criteria .Path ;
28
29
import javax .persistence .criteria .Predicate ;
29
30
import javax .persistence .criteria .Root ;
30
31
@@ -147,27 +148,11 @@ private Predicate toPredicate(Part part, Root<?> root) {
147
148
return new PredicateBuilder (part , root ).build ();
148
149
}
149
150
150
- /**
151
- * Returns a path to a {@link Comparable}.
152
- *
153
- * @param root
154
- * @param part
155
- * @return
156
- */
157
- @ SuppressWarnings ({ "rawtypes" })
158
- private Expression <? extends Comparable > getComparablePath (Root <?> root , Part part ) {
159
-
160
- return getTypedPath (root , part );
161
- }
162
-
163
- private <T > Expression <T > getTypedPath (Root <?> root , Part part ) {
164
- return toExpressionRecursively (root , part .getProperty ());
165
- }
166
-
167
151
/**
168
152
* Simple builder to contain logic to create JPA {@link Predicate}s from {@link Part}s.
169
153
*
170
154
* @author Phil Webb
155
+ * @author Oliver Gierke
171
156
*/
172
157
@ SuppressWarnings ({ "unchecked" , "rawtypes" })
173
158
private class PredicateBuilder {
@@ -197,7 +182,6 @@ public PredicateBuilder(Part part, Root<?> root) {
197
182
public Predicate build () {
198
183
199
184
PropertyPath property = part .getProperty ();
200
- Expression <Object > path = toExpressionRecursively (root , property );
201
185
Type type = part .getType ();
202
186
203
187
switch (type ) {
@@ -207,31 +191,42 @@ public Predicate build() {
207
191
return builder .between (getComparablePath (root , part ), first .getExpression (), second .getExpression ());
208
192
case AFTER :
209
193
case GREATER_THAN :
210
- return builder .greaterThan (getComparablePath (root , part ), provider . next ( part , Comparable . class )
211
- .getExpression ());
194
+ return builder .greaterThan (getComparablePath (root , part ),
195
+ provider . next ( part , Comparable . class ) .getExpression ());
212
196
case GREATER_THAN_EQUAL :
213
- return builder .greaterThanOrEqualTo (getComparablePath (root , part ), provider . next ( part , Comparable . class )
214
- .getExpression ());
197
+ return builder .greaterThanOrEqualTo (getComparablePath (root , part ),
198
+ provider . next ( part , Comparable . class ) .getExpression ());
215
199
case BEFORE :
216
200
case LESS_THAN :
217
201
return builder .lessThan (getComparablePath (root , part ), provider .next (part , Comparable .class ).getExpression ());
218
202
case LESS_THAN_EQUAL :
219
- return builder .lessThanOrEqualTo (getComparablePath (root , part ), provider . next ( part , Comparable . class )
220
- .getExpression ());
203
+ return builder .lessThanOrEqualTo (getComparablePath (root , part ),
204
+ provider . next ( part , Comparable . class ) .getExpression ());
221
205
case IS_NULL :
222
- return path .isNull ();
206
+ return getTypedPath ( root , part ) .isNull ();
223
207
case IS_NOT_NULL :
224
- return path .isNotNull ();
208
+ return getTypedPath ( root , part ) .isNotNull ();
225
209
case NOT_IN :
226
- return path .in (provider .next (part , Collection .class ).getExpression ()).not ();
210
+ return getTypedPath ( root , part ) .in (provider .next (part , Collection .class ).getExpression ()).not ();
227
211
case IN :
228
- return path .in (provider .next (part , Collection .class ).getExpression ());
212
+ return getTypedPath ( root , part ) .in (provider .next (part , Collection .class ).getExpression ());
229
213
case STARTING_WITH :
230
214
case ENDING_WITH :
231
215
case CONTAINING :
216
+ case NOT_CONTAINING :
217
+
218
+ if (property .isCollection ()) {
219
+
220
+ Expression <Collection <Object >> propertyExpression = traversePath (root , property );
221
+ Expression <Object > parameterExpression = provider .next (part ).getExpression ();
222
+
223
+ // Can't just call .not() in case of negation as EclipseLink chokes on that.
224
+ return type .equals (NOT_CONTAINING ) ? builder .isNotMember (parameterExpression , propertyExpression )
225
+ : builder .isMember (parameterExpression , propertyExpression );
226
+ }
227
+
232
228
case LIKE :
233
229
case NOT_LIKE :
234
- case NOT_CONTAINING :
235
230
Expression <String > stringPath = getTypedPath (root , part );
236
231
Expression <String > propertyExpression = upperIfIgnoreCase (stringPath );
237
232
Expression <String > parameterExpression = upperIfIgnoreCase (provider .next (part , String .class ).getExpression ());
@@ -245,10 +240,12 @@ public Predicate build() {
245
240
return builder .isFalse (falsePath );
246
241
case SIMPLE_PROPERTY :
247
242
ParameterMetadata <Object > expression = provider .next (part );
248
- return expression .isIsNullParameter () ? path .isNull () : builder .equal (upperIfIgnoreCase (path ),
249
- upperIfIgnoreCase (expression .getExpression ()));
243
+ Expression <Object > path = getTypedPath (root , part );
244
+ return expression .isIsNullParameter () ? path .isNull ()
245
+ : builder .equal (upperIfIgnoreCase (path ), upperIfIgnoreCase (expression .getExpression ()));
250
246
case NEGATING_SIMPLE_PROPERTY :
251
- return builder .notEqual (upperIfIgnoreCase (path ), upperIfIgnoreCase (provider .next (part ).getExpression ()));
247
+ return builder .notEqual (upperIfIgnoreCase (getTypedPath (root , part )),
248
+ upperIfIgnoreCase (provider .next (part ).getExpression ()));
252
249
default :
253
250
throw new IllegalArgumentException ("Unsupported keyword " + type );
254
251
}
@@ -287,5 +284,26 @@ private <T> Expression<T> upperIfIgnoreCase(Expression<? extends T> expression)
287
284
private boolean canUpperCase (Expression <?> expression ) {
288
285
return String .class .equals (expression .getJavaType ());
289
286
}
287
+
288
+ /**
289
+ * Returns a path to a {@link Comparable}.
290
+ *
291
+ * @param root
292
+ * @param part
293
+ * @return
294
+ */
295
+ private Expression <? extends Comparable > getComparablePath (Root <?> root , Part part ) {
296
+ return getTypedPath (root , part );
297
+ }
298
+
299
+ private <T > Expression <T > getTypedPath (Root <?> root , Part part ) {
300
+ return toExpressionRecursively (root , part .getProperty ());
301
+ }
302
+
303
+ private <T > Expression <T > traversePath (Path <?> root , PropertyPath path ) {
304
+
305
+ Path <Object > result = root .get (path .getSegment ());
306
+ return (Expression <T >) (path .hasNext () ? traversePath (result , path .next ()) : result );
307
+ }
290
308
}
291
309
}
0 commit comments