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.
This commit is contained in:
Christoph Strobl
2020-05-13 09:48:02 +02:00
committed by Mark Paluch
parent af39b422b6
commit 3af7269dbb
2 changed files with 90 additions and 23 deletions

View File

@@ -368,26 +368,33 @@ public class ParameterBindingJsonReader extends AbstractBsonReader {
if (token.getType().equals(JsonTokenType.UNQUOTED_STRING)) {
if (matcher.find()) {
int index = computeParameterIndex(matcher.group());
bindableValue.setValue(getBindableValueForIndex(index));
bindableValue.setType(bsonTypeForValue(getBindableValueForIndex(index)));
return bindableValue;
}
Matcher regexMatcher = EXPRESSION_BINDING_PATTERN.matcher(tokenValue);
if (regexMatcher.find()) {
String binding = regexMatcher.group();
String expression = binding.substring(3, binding.length() - 1);
Matcher inSpelMatcher = PARAMETER_BINDING_PATTERN.matcher(expression);
while (inSpelMatcher.find()) {
int index = computeParameterIndex(inSpelMatcher.group());
expression = expression.replace(inSpelMatcher.group(), getBindableValueForIndex(index).toString());
}
Object value = evaluateExpression(expression);
bindableValue.setValue(value);
bindableValue.setType(bsonTypeForValue(value));
return bindableValue;
}
if (matcher.find()) {
int index = computeParameterIndex(matcher.group());
bindableValue.setValue(getBindableValueForIndex(index));
bindableValue.setType(bsonTypeForValue(getBindableValueForIndex(index)));
return bindableValue;
}
bindableValue.setValue(tokenValue);
bindableValue.setType(BsonType.STRING);
return bindableValue;
@@ -396,28 +403,37 @@ public class ParameterBindingJsonReader extends AbstractBsonReader {
String computedValue = tokenValue;
boolean matched = false;
Matcher regexMatcher = EXPRESSION_BINDING_PATTERN.matcher(computedValue);
while (regexMatcher.find()) {
String binding = regexMatcher.group();
String expression = binding.substring(3, binding.length() - 1);
Matcher inSpelMatcher = PARAMETER_BINDING_PATTERN.matcher(expression);
while (inSpelMatcher.find()) {
int index = computeParameterIndex(inSpelMatcher.group());
expression = expression.replace(inSpelMatcher.group(), getBindableValueForIndex(index).toString());
}
computedValue = computedValue.replace(binding, nullSafeToString(evaluateExpression(expression)));
bindableValue.setValue(computedValue);
bindableValue.setType(BsonType.STRING);
return bindableValue;
}
while (matcher.find()) {
matched = true;
String group = matcher.group();
int index = computeParameterIndex(group);
computedValue = computedValue.replace(group, nullSafeToString(getBindableValueForIndex(index)));
}
if (!matched) {
Matcher regexMatcher = EXPRESSION_BINDING_PATTERN.matcher(tokenValue);
while (regexMatcher.find()) {
String binding = regexMatcher.group();
String expression = binding.substring(3, binding.length() - 1);
computedValue = computedValue.replace(binding, nullSafeToString(evaluateExpression(expression)));
}
}
bindableValue.setValue(computedValue);
bindableValue.setType(BsonType.STRING);

View File

@@ -26,6 +26,7 @@ import java.util.List;
import org.bson.Document;
import org.bson.codecs.DecoderContext;
import org.junit.jupiter.api.Test;
import org.springframework.data.spel.EvaluationContextProvider;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -264,10 +265,60 @@ class ParameterBindingJsonReaderUnitTests {
assertThat(target).isEqualTo(Document.parse("{\"$and\": [{\"v1\": {\"$in\": [1]}}]}"));
}
@Test // DATAMONGO-2545
void shouldABindArgumentsViaIndexInSpelExpressions() {
Object[] args = new Object[] { "yess", "nooo" };
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
.getEvaluationContext(args);
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(
"{ 'isBatman' : ?#{ T(" + this.getClass().getName() + ").isBatman() ? [0] : [1] }}",
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
assertThat(target).isEqualTo(new Document("isBatman", "nooo"));
}
@Test // DATAMONGO-2545
void shouldAllowMethodArgumentPlaceholdersInSpelExpressions/*becuase this worked before*/() {
Object[] args = new Object[] { "yess", "nooo" };
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
.getEvaluationContext(args);
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(
"{ 'isBatman' : ?#{ T(" + this.getClass().getName() + ").isBatman() ? '?0' : '?1' }}",
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
assertThat(target).isEqualTo(new Document("isBatman", "nooo"));
}
@Test // DATAMONGO-2545
void shouldAllowMethodArgumentPlaceholdersInQuotedSpelExpressions/*becuase this worked before*/() {
Object[] args = new Object[] { "yess", "nooo" };
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
.getEvaluationContext(args);
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(
"{ 'isBatman' : \"?#{ T(" + this.getClass().getName() + ").isBatman() ? '?0' : '?1' }\" }",
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
assertThat(target).isEqualTo(new Document("isBatman", "nooo"));
}
private static Document parse(String json, Object... args) {
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json, args);
return new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
}
// DATAMONGO-2545
public static boolean isBatman() {
return false;
}
}