24
24
import org .springframework .data .jpa .repository .query .JpaParameters .JpaParameter ;
25
25
import org .springframework .data .jpa .repository .query .ParameterMetadataProvider .ParameterMetadata ;
26
26
import org .springframework .data .jpa .repository .query .QueryParameterSetter .NamedOrIndexedQueryParameterSetter ;
27
+ import org .springframework .data .jpa .repository .query .StringQuery .LikeParameterBinding ;
27
28
import org .springframework .data .jpa .repository .query .StringQuery .ParameterBinding ;
28
29
import org .springframework .data .repository .query .Parameter ;
29
30
import org .springframework .data .repository .query .Parameters ;
@@ -62,6 +63,20 @@ static QueryParameterSetterFactory basic(JpaParameters parameters) {
62
63
return new BasicQueryParameterSetterFactory (parameters );
63
64
}
64
65
66
+ /**
67
+ * Creates a new {@link QueryParameterSetterFactory} for the given {@link JpaParameters} applying LIKE rewrite for
68
+ * renamed {@code :foo%} or {@code %:bar} bindings.
69
+ *
70
+ * @param parameters must not be {@literal null}.
71
+ * @return a basic {@link QueryParameterSetterFactory} that can handle named parameters.
72
+ */
73
+ static QueryParameterSetterFactory forLikeRewrite (JpaParameters parameters ) {
74
+
75
+ Assert .notNull (parameters , "JpaParameters must not be null" );
76
+
77
+ return new LikeRewritingQueryParameterSetterFactory (parameters );
78
+ }
79
+
65
80
/**
66
81
* Creates a new {@link QueryParameterSetterFactory} using the given {@link JpaParameters} and
67
82
* {@link ParameterMetadata}.
@@ -117,6 +132,29 @@ private static QueryParameterSetter createSetter(Function<JpaParametersParameter
117
132
ParameterImpl .of (parameter , binding ), temporalType );
118
133
}
119
134
135
+ @ Nullable
136
+ private static JpaParameter findParameterForBinding (Parameters <JpaParameters , JpaParameter > parameters , String name ) {
137
+
138
+ JpaParameters bindableParameters = parameters .getBindableParameters ();
139
+
140
+ for (JpaParameter bindableParameter : bindableParameters ) {
141
+ if (name .equals (getRequiredName (bindableParameter ))) {
142
+ return bindableParameter ;
143
+ }
144
+ }
145
+
146
+ return null ;
147
+ }
148
+
149
+ private static String getRequiredName (JpaParameter p ) {
150
+ return p .getName ().orElseThrow (() -> new IllegalStateException (ParameterBinder .PARAMETER_NEEDS_TO_BE_NAMED ));
151
+ }
152
+
153
+ @ Nullable
154
+ static Object getValue (JpaParametersParameterAccessor accessor , Parameter parameter ) {
155
+ return accessor .getValue (parameter );
156
+ }
157
+
120
158
/**
121
159
* Handles bindings that are SpEL expressions by evaluating the expression to obtain a value.
122
160
*
@@ -176,6 +214,46 @@ private Object evaluateExpression(Expression expression, JpaParametersParameterA
176
214
}
177
215
}
178
216
217
+ /**
218
+ * Handles bindings that use Like-rewriting.
219
+ *
220
+ * @author Mark Paluch
221
+ * @since 3.1.2
222
+ */
223
+ private static class LikeRewritingQueryParameterSetterFactory extends QueryParameterSetterFactory {
224
+
225
+ private final Parameters <?, ?> parameters ;
226
+
227
+ /**
228
+ * @param parameters must not be {@literal null}.
229
+ */
230
+ LikeRewritingQueryParameterSetterFactory (Parameters <?, ?> parameters ) {
231
+
232
+ Assert .notNull (parameters , "Parameters must not be null" );
233
+
234
+ this .parameters = parameters ;
235
+ }
236
+
237
+ @ Nullable
238
+ @ Override
239
+ public QueryParameterSetter create (ParameterBinding binding , DeclaredQuery declaredQuery ) {
240
+
241
+ if (binding .isExpression () || !(binding instanceof LikeParameterBinding likeBinding )
242
+ || !declaredQuery .hasNamedParameter ()) {
243
+ return null ;
244
+ }
245
+ JpaParameter parameter = QueryParameterSetterFactory .findParameterForBinding ((JpaParameters ) parameters ,
246
+ likeBinding .getDeclaredName ());
247
+
248
+ if (parameter == null ) {
249
+ return null ;
250
+ }
251
+
252
+ return createSetter (values -> values .getValue (parameter ), binding , parameter );
253
+ }
254
+
255
+ }
256
+
179
257
/**
180
258
* Extracts values for parameter bindings from method parameters. It handles named as well as indexed parameters.
181
259
*
@@ -205,7 +283,7 @@ public QueryParameterSetter create(ParameterBinding binding, DeclaredQuery decla
205
283
JpaParameter parameter ;
206
284
207
285
if (declaredQuery .hasNamedParameter ()) {
208
- parameter = findParameterForBinding (binding );
286
+ parameter = findParameterForBinding (parameters , binding . getRequiredName () );
209
287
} else {
210
288
211
289
int parameterIndex = binding .getRequiredPosition () - 1 ;
@@ -228,28 +306,6 @@ public QueryParameterSetter create(ParameterBinding binding, DeclaredQuery decla
228
306
: createSetter (values -> getValue (values , parameter ), binding , parameter );
229
307
}
230
308
231
- @ Nullable
232
- private JpaParameter findParameterForBinding (ParameterBinding binding ) {
233
-
234
- JpaParameters bindableParameters = parameters .getBindableParameters ();
235
-
236
- for (JpaParameter bindableParameter : bindableParameters ) {
237
- if (binding .getRequiredName ().equals (getName (bindableParameter ))) {
238
- return bindableParameter ;
239
- }
240
- }
241
-
242
- return null ;
243
- }
244
-
245
- @ Nullable
246
- private Object getValue (JpaParametersParameterAccessor accessor , Parameter parameter ) {
247
- return accessor .getValue (parameter );
248
- }
249
-
250
- private static String getName (JpaParameter p ) {
251
- return p .getName ().orElseThrow (() -> new IllegalStateException (ParameterBinder .PARAMETER_NEEDS_TO_BE_NAMED ));
252
- }
253
309
}
254
310
255
311
/**
@@ -366,7 +422,7 @@ public Class<T> getParameterType() {
366
422
@ Nullable
367
423
private static String getName (@ Nullable JpaParameter parameter , ParameterBinding binding ) {
368
424
369
- if (parameter == null ) {
425
+ if (binding . hasName () || parameter == null ) {
370
426
return binding .getName ();
371
427
}
372
428
0 commit comments