diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingDocumentCodec.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingDocumentCodec.java index baffcaf8c..72e6467b9 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingDocumentCodec.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingDocumentCodec.java @@ -38,6 +38,7 @@ import org.bson.Document; import org.bson.Transformer; import org.bson.codecs.*; import org.bson.codecs.configuration.CodecRegistry; +import org.bson.json.JsonParseException; import org.springframework.data.spel.EvaluationContextProvider; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.lang.Nullable; @@ -190,9 +191,26 @@ public class ParameterBindingDocumentCodec implements CollectibleCodec Document document = new Document(); reader.readStartDocument(); - while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) { - String fieldName = reader.readName(); - document.put(fieldName, readValue(reader, decoderContext)); + + try { + + while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) { + String fieldName = reader.readName(); + Object value = readValue(reader, decoderContext); + document.put(fieldName, value); + } + } catch (JsonParseException e) { + try { + + Object value = readValue(reader, decoderContext); + if (value instanceof Map) { + if (!((Map) value).isEmpty()) { + return new Document((Map) value); + } + } + } catch (Exception ex) { + throw e; + } } reader.readEndDocument(); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReader.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReader.java index bdc98d532..77cd05747 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReader.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReader.java @@ -25,6 +25,7 @@ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; +import java.util.Map; import java.util.TimeZone; import java.util.function.Supplier; import java.util.regex.Matcher; @@ -495,6 +496,9 @@ public class ParameterBindingJsonReader extends AbstractBsonReader { if (ClassUtils.isAssignable(Iterable.class, type)) { return BsonType.ARRAY; } + if (ClassUtils.isAssignable(Map.class, type)) { + return BsonType.DOCUMENT; + } return BsonType.UNDEFINED; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReaderUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReaderUnitTests.java index 6e6e14dbd..93d54f446 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReaderUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/ParameterBindingJsonReaderUnitTests.java @@ -17,6 +17,9 @@ package org.springframework.data.mongodb.util.json; import static org.assertj.core.api.Assertions.*; +import lombok.AllArgsConstructor; +import lombok.Data; + import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; @@ -310,6 +313,26 @@ class ParameterBindingJsonReaderUnitTests { assertThat(target).isEqualTo(new Document("isBatman", "nooo")); } + @Test // DATAMONGO-2545 + void evaluatesSpelExpressionDefiningEntireQuery() { + + Object[] args = new Object[] {}; + StandardEvaluationContext evaluationContext = (StandardEvaluationContext) EvaluationContextProvider.DEFAULT + .getEvaluationContext(args); + evaluationContext.setRootObject(new DummySecurityObject(new DummyWithId("wonderwoman"))); + + String json = "?#{ T(" + this.getClass().getName() + + ").isBatman() ? {'_class': { '$eq' : 'region' }} : { '$and' : { {'_class': { '$eq' : 'region' } }, {'user.superviser': principal.id } } } }"; + + 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("$and", Arrays.asList(new Document("_class", new Document("$eq", "region")), + new Document("user.superviser", "wonderwoman")))); + } + private static Document parse(String json, Object... args) { ParameterBindingJsonReader reader = new ParameterBindingJsonReader(json, args); @@ -321,4 +344,16 @@ class ParameterBindingJsonReaderUnitTests { return false; } + @Data + @AllArgsConstructor + public static class DummySecurityObject { + DummyWithId principal; + } + + @Data + @AllArgsConstructor + public static class DummyWithId { + String id; + } + }