Browse Source

Revert query modification in json parsing tests.

Add tests and move json string treatment into the ParameterBindingDocumentCodec.
Finally add issue references and format code.

Original Pull Request: #3907
pull/3950/head
Christoph Strobl 4 years ago
parent
commit
885d05965b
No known key found for this signature in database
GPG Key ID: 8CC1AB53391458C8
  1. 9
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingDocumentCodec.java
  2. 15
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReader.java
  3. 82
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReaderUnitTests.java

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

@ -217,8 +217,15 @@ public class ParameterBindingDocumentCodec implements CollectibleCodec<Document>
// binds just placeholder queries like: `@Query(?0)` // binds just placeholder queries like: `@Query(?0)`
if (bindingReader.currentValue instanceof org.bson.Document) { if (bindingReader.currentValue instanceof org.bson.Document) {
return (Document) bindingReader.currentValue; return (Document) bindingReader.currentValue;
} else if (bindingReader.currentValue instanceof String) {
try {
return decode((String) bindingReader.currentValue, new Object[0]);
} catch (JsonParseException jsonParseException) {
throw new IllegalArgumentException("Expression result is not a valid json document!", jsonParseException);
}
} else if (bindingReader.currentValue instanceof Map) {
return new Document((Map) bindingReader.currentValue);
} }
} }
Document document = new Document(); Document document = new Document();

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

@ -36,7 +36,6 @@ import org.bson.types.Decimal128;
import org.bson.types.MaxKey; import org.bson.types.MaxKey;
import org.bson.types.MinKey; import org.bson.types.MinKey;
import org.bson.types.ObjectId; import org.bson.types.ObjectId;
import org.springframework.data.spel.EvaluationContextProvider; import org.springframework.data.spel.EvaluationContextProvider;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
@ -120,20 +119,8 @@ public class ParameterBindingJsonReader extends AbstractBsonReader {
Matcher matcher = ENTIRE_QUERY_BINDING_PATTERN.matcher(json); Matcher matcher = ENTIRE_QUERY_BINDING_PATTERN.matcher(json);
if (matcher.find()) { if (matcher.find()) {
BindableValue bindingResult = bindableValueFor(new JsonToken(JsonTokenType.UNQUOTED_STRING, json)); BindableValue bindingResult = bindableValueFor(new JsonToken(JsonTokenType.UNQUOTED_STRING, json));
try { currentValue = bindingResult.getValue();
if (bindingResult.getValue() instanceof String) {
currentValue = Document.parse((String)bindingResult.getValue());
} else {
currentValue = bindingResult.getValue();
}
} catch (JsonParseException jsonParseException) {
throw new IllegalArgumentException(
String.format("Resulting value of expression '%s' is not a valid json query", json), jsonParseException);
}
} }
} }
// Spring Data Customization END // Spring Data Customization END

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

@ -26,6 +26,7 @@ import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.bson.BsonBinary;
import org.bson.Document; import org.bson.Document;
import org.bson.codecs.DecoderContext; import org.bson.codecs.DecoderContext;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -347,7 +348,7 @@ class ParameterBindingJsonReaderUnitTests {
evaluationContext.setRootObject(new DummySecurityObject(new DummyWithId("wonderwoman"))); evaluationContext.setRootObject(new DummySecurityObject(new DummyWithId("wonderwoman")));
String json = "?#{ T(" + this.getClass().getName() String json = "?#{ T(" + this.getClass().getName()
+ ").isBatman() ? \"{'_class': { '$eq' : 'region' }}\" : \"{ '$and' : [ {'_class': { '$eq' : 'region' } }, {'user.supervisor': '\"+ principal.id +\"' } ] }\" }"; + ").isBatman() ? {'_class': { '$eq' : 'region' }} : { '$and' : { {'_class': { '$eq' : 'region' } }, {'user.supervisor': principal.id } } } }";
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json, ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json,
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext)); new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
@ -357,11 +358,66 @@ class ParameterBindingJsonReaderUnitTests {
.isEqualTo(new Document("$and", Arrays.asList(new Document("_class", new Document("$eq", "region")), .isEqualTo(new Document("$and", Arrays.asList(new Document("_class", new Document("$eq", "region")),
new Document("user.supervisor", "wonderwoman")))); new Document("user.supervisor", "wonderwoman"))));
} }
@Test @Test // GH-3871
public void capturingExpressionDependenciesShouldNotThrowParseErrorForSpelOnlyJson() {
Object[] args = new Object[] { "1", "2" };
String json = "?#{ true ? { 'name': #name } : { 'name' : #name + 'trouble' } }";
new ParameterBindingDocumentCodec().captureExpressionDependencies(json, (index) -> args[index],
new SpelExpressionParser());
}
@Test // GH-3871
public void bindEntireQueryUsingSpelExpressionWhenEvaluationResultIsJsonString() {
Object[] args = new Object[] { "expected", "unexpected" };
String json = "?#{ true ? \"{ 'name': ?0 }\" : \"{ 'name' : ?1 }\" }";
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
.getEvaluationContext(args);
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json,
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
assertThat(target).isEqualTo(new Document("name", "expected"));
}
@Test // GH-3871
public void throwsExceptionWhenbindEntireQueryUsingSpelExpressionResultsInInvalidJsonString() {
Object[] args = new Object[] { "expected", "unexpected" };
String json = "?#{ true ? \"{ 'name': ?0 { }\" : \"{ 'name' : ?1 }\" }";
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
.getEvaluationContext(args);
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json,
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build()));
}
@Test // GH-3871
public void bindEntireQueryUsingSpelExpressionWhenEvaluationResultIsJsonStringContainingUUID() {
Object[] args = new Object[] { "UUID('cfbca728-4e39-4613-96bc-f920b5c37e16')", "unexpected" };
String json = "?#{ true ? \"{ 'name': ?0 }\" : \"{ 'name' : ?1 }\" }";
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
.getEvaluationContext(args);
ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json,
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
assertThat(target.get("name")).isInstanceOf(BsonBinary.class);
}
@Test // GH-3871
void bindEntireQueryUsingSpelExpression() { void bindEntireQueryUsingSpelExpression() {
Object[] args = new Object[] {"region"}; Object[] args = new Object[] { "region" };
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
.getEvaluationContext(args); .getEvaluationContext(args);
evaluationContext.setRootObject(new DummySecurityObject(new DummyWithId("wonderwoman"))); evaluationContext.setRootObject(new DummySecurityObject(new DummyWithId("wonderwoman")));
@ -377,10 +433,10 @@ class ParameterBindingJsonReaderUnitTests {
new Document("user.supervisor", "wonderwoman")))); new Document("user.supervisor", "wonderwoman"))));
} }
@Test @Test // GH-3871
void bindEntireQueryUsingParameter() { void bindEntireQueryUsingParameter() {
Object[] args = new Object[] {"{ 'itWorks' : true }"}; Object[] args = new Object[] { "{ 'itWorks' : true }" };
StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT
.getEvaluationContext(args); .getEvaluationContext(args);
@ -390,9 +446,7 @@ class ParameterBindingJsonReaderUnitTests {
new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext)); new ParameterBindingContext((index) -> args[index], new SpelExpressionParser(), evaluationContext));
Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build()); Document target = new ParameterBindingDocumentCodec().decode(reader, DecoderContext.builder().build());
assertThat(target) assertThat(target).isEqualTo(new Document("itWorks", true));
.isEqualTo(new Document("itWorks", true));
} }
@Test // DATAMONGO-2571 @Test // DATAMONGO-2571
@ -437,17 +491,13 @@ class ParameterBindingJsonReaderUnitTests {
public static boolean isBatman() { public static boolean isBatman() {
return false; return false;
} }
public static String applyFilterByUser(String _class, String username) { public static String applyFilterByUser(String _class, String username) {
switch (username) { switch (username) {
case "batman": case "batman":
return "{'_class': { '$eq' : '" return "{'_class': { '$eq' : '" + _class + "' }}";
+ _class
+ "' }}";
default: default:
return "{ '$and' : [ {'_class': { '$eq' : '" return "{ '$and' : [ {'_class': { '$eq' : '" + _class + "' } }, {'user.supervisor': '" + username + "' } ] }";
+ _class
+ "' } }, {'user.supervisor': '" + username + "' } ] }";
} }
} }

Loading…
Cancel
Save