Skip to content

Commit 5ae7547

Browse files
christophstroblmp911de
authored andcommitted
DATAMONGO-2545 - Fix regression in String query SpEL parameter binding.
We reenabled parameter binding within SpEL using query parameter placeholders ?0, ?1,... instead of their array index [0],[1],... Original pull request: #864.
1 parent cf4e04a commit 5ae7547

File tree

2 files changed

+88
-21
lines changed

2 files changed

+88
-21
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReader.java

+37-21
Original file line numberDiff line numberDiff line change
@@ -370,26 +370,33 @@ private BindableValue bindableValueFor(JsonToken token) {
370370

371371
if (token.getType().equals(JsonTokenType.UNQUOTED_STRING)) {
372372

373-
if (matcher.find()) {
374-
375-
int index = computeParameterIndex(matcher.group());
376-
bindableValue.setValue(getBindableValueForIndex(index));
377-
bindableValue.setType(bsonTypeForValue(getBindableValueForIndex(index)));
378-
return bindableValue;
379-
}
380-
381373
Matcher regexMatcher = EXPRESSION_BINDING_PATTERN.matcher(tokenValue);
382374
if (regexMatcher.find()) {
383375

384376
String binding = regexMatcher.group();
385377
String expression = binding.substring(3, binding.length() - 1);
386378

379+
Matcher inSpelMatcher = PARAMETER_BINDING_PATTERN.matcher(expression);
380+
while (inSpelMatcher.find()) {
381+
382+
int index = computeParameterIndex(inSpelMatcher.group());
383+
expression = expression.replace(inSpelMatcher.group(), getBindableValueForIndex(index).toString());
384+
}
385+
387386
Object value = evaluateExpression(expression);
388387
bindableValue.setValue(value);
389388
bindableValue.setType(bsonTypeForValue(value));
390389
return bindableValue;
391390
}
392391

392+
if (matcher.find()) {
393+
394+
int index = computeParameterIndex(matcher.group());
395+
bindableValue.setValue(getBindableValueForIndex(index));
396+
bindableValue.setType(bsonTypeForValue(getBindableValueForIndex(index)));
397+
return bindableValue;
398+
}
399+
393400
bindableValue.setValue(tokenValue);
394401
bindableValue.setType(BsonType.STRING);
395402
return bindableValue;
@@ -398,26 +405,35 @@ private BindableValue bindableValueFor(JsonToken token) {
398405

399406
String computedValue = tokenValue;
400407

401-
boolean matched = false;
402-
while (matcher.find()) {
403408

404-
matched = true;
405-
String group = matcher.group();
406-
int index = computeParameterIndex(group);
407-
computedValue = computedValue.replace(group, nullSafeToString(getBindableValueForIndex(index)));
408-
}
409409

410-
if (!matched) {
410+
Matcher regexMatcher = EXPRESSION_BINDING_PATTERN.matcher(computedValue);
411411

412-
Matcher regexMatcher = EXPRESSION_BINDING_PATTERN.matcher(tokenValue);
412+
while (regexMatcher.find()) {
413413

414-
while (regexMatcher.find()) {
414+
String binding = regexMatcher.group();
415+
String expression = binding.substring(3, binding.length() - 1);
415416

416-
String binding = regexMatcher.group();
417-
String expression = binding.substring(3, binding.length() - 1);
417+
Matcher inSpelMatcher = PARAMETER_BINDING_PATTERN.matcher(expression);
418+
while (inSpelMatcher.find()) {
418419

419-
computedValue = computedValue.replace(binding, nullSafeToString(evaluateExpression(expression)));
420+
int index = computeParameterIndex(inSpelMatcher.group());
421+
expression = expression.replace(inSpelMatcher.group(), getBindableValueForIndex(index).toString());
420422
}
423+
424+
computedValue = computedValue.replace(binding, nullSafeToString(evaluateExpression(expression)));
425+
426+
bindableValue.setValue(computedValue);
427+
bindableValue.setType(BsonType.STRING);
428+
429+
return bindableValue;
430+
}
431+
432+
while (matcher.find()) {
433+
434+
String group = matcher.group();
435+
int index = computeParameterIndex(group);
436+
computedValue = computedValue.replace(group, nullSafeToString(getBindableValueForIndex(index)));
421437
}
422438

423439
bindableValue.setValue(computedValue);

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReaderUnitTests.java

+51
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.bson.Document;
2727
import org.bson.codecs.DecoderContext;
2828
import org.junit.jupiter.api.Test;
29+
import org.springframework.data.spel.EvaluationContextProvider;
2930
import org.springframework.expression.EvaluationContext;
3031
import org.springframework.expression.TypedValue;
3132
import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -264,10 +265,60 @@ void bindQuotedMulitParameterInArray() {
264265
assertThat(target).isEqualTo(Document.parse("{\"$and\": [{\"v1\": {\"$in\": [1]}}]}"));
265266
}
266267

268+
@Test // DATAMONGO-2545
269+
void shouldABindArgumentsViaIndexInSpelExpressions() {
270+
271+
Object[] args = new Object[] { "yess", "nooo" };
272+
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
273+
.getEvaluationContext(args);
274+
275+
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(
276+
"{ 'isBatman' : ?#{ T(" + this.getClass().getName() + ").isBatman() ? [0] : [1] }}",
277+
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
278+
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
279+
280+
assertThat(target).isEqualTo(new Document("isBatman", "nooo"));
281+
}
282+
283+
@Test // DATAMONGO-2545
284+
void shouldAllowMethodArgumentPlaceholdersInSpelExpressions/*becuase this worked before*/() {
285+
286+
Object[] args = new Object[] { "yess", "nooo" };
287+
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
288+
.getEvaluationContext(args);
289+
290+
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(
291+
"{ 'isBatman' : ?#{ T(" + this.getClass().getName() + ").isBatman() ? '?0' : '?1' }}",
292+
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
293+
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
294+
295+
assertThat(target).isEqualTo(new Document("isBatman", "nooo"));
296+
}
297+
298+
@Test // DATAMONGO-2545
299+
void shouldAllowMethodArgumentPlaceholdersInQuotedSpelExpressions/*becuase this worked before*/() {
300+
301+
Object[] args = new Object[] { "yess", "nooo" };
302+
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
303+
.getEvaluationContext(args);
304+
305+
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(
306+
"{ 'isBatman' : \"?#{ T(" + this.getClass().getName() + ").isBatman() ? '?0' : '?1' }\" }",
307+
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
308+
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
309+
310+
assertThat(target).isEqualTo(new Document("isBatman", "nooo"));
311+
}
312+
267313
private static Document parse(String json, Object... args) {
268314

269315
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json, args);
270316
return new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
271317
}
272318

319+
// DATAMONGO-2545
320+
public static boolean isBatman() {
321+
return false;
322+
}
323+
273324
}

0 commit comments

Comments
 (0)