Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3af7269

Browse files
christophstroblmp911de
authored andcommittedMay 26, 2020
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 af39b42 commit 3af7269

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

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -368,26 +368,33 @@ private BindableValue bindableValueFor(JsonToken token) {
368368

369369
if (token.getType().equals(JsonTokenType.UNQUOTED_STRING)) {
370370

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

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

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

390+
if (matcher.find()) {
391+
392+
int index = computeParameterIndex(matcher.group());
393+
bindableValue.setValue(getBindableValueForIndex(index));
394+
bindableValue.setType(bsonTypeForValue(getBindableValueForIndex(index)));
395+
return bindableValue;
396+
}
397+
391398
bindableValue.setValue(tokenValue);
392399
bindableValue.setType(BsonType.STRING);
393400
return bindableValue;
@@ -396,26 +403,35 @@ private BindableValue bindableValueFor(JsonToken token) {
396403

397404
String computedValue = tokenValue;
398405

399-
boolean matched = false;
400-
while (matcher.find()) {
401406

402-
matched = true;
403-
String group = matcher.group();
404-
int index = computeParameterIndex(group);
405-
computedValue = computedValue.replace(group, nullSafeToString(getBindableValueForIndex(index)));
406-
}
407407

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

410-
Matcher regexMatcher = EXPRESSION_BINDING_PATTERN.matcher(tokenValue);
410+
while (regexMatcher.find()) {
411411

412-
while (regexMatcher.find()) {
412+
String binding = regexMatcher.group();
413+
String expression = binding.substring(3, binding.length() - 1);
413414

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

417-
computedValue = computedValue.replace(binding, nullSafeToString(evaluateExpression(expression)));
418+
int index = computeParameterIndex(inSpelMatcher.group());
419+
expression = expression.replace(inSpelMatcher.group(), getBindableValueForIndex(index).toString());
418420
}
421+
422+
computedValue = computedValue.replace(binding, nullSafeToString(evaluateExpression(expression)));
423+
424+
bindableValue.setValue(computedValue);
425+
bindableValue.setType(BsonType.STRING);
426+
427+
return bindableValue;
428+
}
429+
430+
while (matcher.find()) {
431+
432+
String group = matcher.group();
433+
int index = computeParameterIndex(group);
434+
computedValue = computedValue.replace(group, nullSafeToString(getBindableValueForIndex(index)));
419435
}
420436

421437
bindableValue.setValue(computedValue);

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

Lines changed: 51 additions & 0 deletions
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)
Please sign in to comment.