From f4556406bd98f8833f34c6500cfca7360e992b62 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 18 Mar 2021 12:02:42 +0100 Subject: [PATCH] Polishing. Reorder methods. Tweak Javadoc and documentation wording. Mention projection expressions in the what's new section. Reformat code. See #3583 Original pull request: #3585. --- .../data/mongodb/BindableMongoExpression.java | 37 ++++++++++--------- .../data/mongodb/MongoExpression.java | 14 +++---- .../aggregation/AggregationExpression.java | 24 ++++++------ .../data/mongodb/core/query/Field.java | 16 ++++---- .../MongoTemplateFieldProjectionTests.java | 2 + src/main/asciidoc/new-features.adoc | 1 + src/main/asciidoc/reference/mongodb.adoc | 24 ++++++------ 7 files changed, 61 insertions(+), 57 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BindableMongoExpression.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BindableMongoExpression.java index 4ecc52ce5..982f683d5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BindableMongoExpression.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BindableMongoExpression.java @@ -15,6 +15,8 @@ */ package org.springframework.data.mongodb; +import java.util.Arrays; + import org.bson.Document; import org.bson.codecs.DocumentCodec; import org.bson.codecs.configuration.CodecRegistry; @@ -30,15 +32,15 @@ import org.springframework.util.StringUtils; * binding of placeholders like {@code ?0} is delayed upon first call on the the target {@link Document} via * {@link #toDocument()}. *

- * + * *

  * $toUpper : $name                -> { '$toUpper' : '$name' }
- * 
+ *
  * { '$toUpper' : '$name' }        -> { '$toUpper' : '$name' }
- * 
+ *
  * { '$toUpper' : '?0' }, "$name"  -> { '$toUpper' : '$name' }
  * 
- * + * * Some types might require a special {@link org.bson.codecs.Codec}. If so, make sure to provide a {@link CodecRegistry} * containing the required {@link org.bson.codecs.Codec codec} via {@link #withCodecRegistry(CodecRegistry)}. * @@ -49,11 +51,9 @@ public class BindableMongoExpression implements MongoExpression { private final String expressionString; - @Nullable // - private final CodecRegistryProvider codecRegistryProvider; + private final @Nullable CodecRegistryProvider codecRegistryProvider; - @Nullable // - private final Object[] args; + private final @Nullable Object[] args; private final Lazy target; @@ -118,16 +118,8 @@ public class BindableMongoExpression implements MongoExpression { */ @Override public String toString() { - return "BindableMongoExpression{" + "expressionString='" + expressionString + '\'' + ", args=" + args + '}'; - } - - private String wrapJsonIfNecessary(String json) { - - if (StringUtils.hasText(json) && (json.startsWith("{") && json.endsWith("}"))) { - return json; - } - - return "{" + json + "}"; + return "BindableMongoExpression{" + "expressionString='" + expressionString + '\'' + ", args=" + + Arrays.toString(args) + '}'; } private Document parse() { @@ -148,4 +140,13 @@ public class BindableMongoExpression implements MongoExpression { : new ParameterBindingDocumentCodec(codecRegistryProvider.getCodecRegistry()); return codec.decode(expression, args); } + + private static String wrapJsonIfNecessary(String json) { + + if (StringUtils.hasText(json) && (json.startsWith("{") && json.endsWith("}"))) { + return json; + } + + return "{" + json + "}"; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoExpression.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoExpression.java index c69fd97f4..541118b11 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoExpression.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoExpression.java @@ -39,13 +39,6 @@ package org.springframework.data.mongodb; @FunctionalInterface public interface MongoExpression { - /** - * Obtain the native {@link org.bson.Document} representation. - * - * @return never {@literal null}. - */ - org.bson.Document toDocument(); - /** * Create a new {@link MongoExpression} from plain {@link String} (eg. {@code $toUpper : $name}).
* The given expression will be wrapped with { ... } to match an actual MongoDB {@link org.bson.Document} @@ -70,4 +63,11 @@ public interface MongoExpression { static MongoExpression create(String expression, Object... args) { return new BindableMongoExpression(expression, args); } + + /** + * Obtain the native {@link org.bson.Document} representation. + * + * @return never {@literal null}. + */ + org.bson.Document toDocument(); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationExpression.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationExpression.java index 879751b29..b2fee4439 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationExpression.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationExpression.java @@ -28,18 +28,6 @@ import org.springframework.data.mongodb.MongoExpression; */ public interface AggregationExpression extends MongoExpression { - /** - * Obtain the as is (unmapped) representation of the {@link AggregationExpression}. Use - * {@link #toDocument(AggregationOperationContext)} with a matching {@link AggregationOperationContext context} to - * engage domain type mapping including field name resolution. - * - * @see org.springframework.data.mongodb.MongoExpression#toDocument() - */ - @Override - default Document toDocument() { - return toDocument(Aggregation.DEFAULT_CONTEXT); - } - /** * Create an {@link AggregationExpression} out of a given {@link MongoExpression} to ensure the resulting * {@link MongoExpression#toDocument() Document} is mapped against the {@link AggregationOperationContext}.
@@ -58,6 +46,18 @@ public interface AggregationExpression extends MongoExpression { return (context) -> context.getMappedObject(expression.toDocument()); } + /** + * Obtain the as is (unmapped) representation of the {@link AggregationExpression}. Use + * {@link #toDocument(AggregationOperationContext)} with a matching {@link AggregationOperationContext context} to + * engage domain type mapping including field name resolution. + * + * @see org.springframework.data.mongodb.MongoExpression#toDocument() + */ + @Override + default Document toDocument() { + return toDocument(Aggregation.DEFAULT_CONTEXT); + } + /** * Turns the {@link AggregationExpression} into a {@link Document} within the given * {@link AggregationOperationContext}. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Field.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Field.java index 711e5d81d..0561bbdca 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Field.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Field.java @@ -63,21 +63,21 @@ public class Field { * result. * *
-	 * 
+	 *
 	 * // { 'name' : { '$toUpper' : '$name' } }
-	 * 
+	 *
 	 * // native MongoDB expression
 	 * .project(MongoExpression.expressionFromString("'$toUpper' : '$name'")).as("name");
-	 * 
+	 *
 	 * // Aggregation Framework expression
 	 * .project(StringOperators.valueOf("name").toUpper()).as("name");
-	 * 
+	 *
 	 * // Aggregation Framework SpEL expression
 	 * .project(AggregationSpELExpression.expressionOf("toUpper(name)")).as("name");
 	 * 
* * @param expression must not be {@literal null}. - * @return new instance of {@link FieldProjectionExpression} - you still need to define the target field name via + * @return new instance of {@link FieldProjectionExpression}. Define the target field name through * {@link FieldProjectionExpression#as(String) as(String)}. * @since 3.2 */ @@ -277,15 +277,15 @@ public class Field { /** * Intermediate builder part for projecting a {@link MongoExpression} to a result field. - * + * * @since 3.2 * @author Christoph Strobl */ public interface FieldProjectionExpression { /** - * Set the name to be used in the result. - * + * Set the name to be used in the result and return a {@link Field}. + * * @param name must not be {@literal null}. * @return the calling instance {@link Field}. */ diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateFieldProjectionTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateFieldProjectionTests.java index d97e0afdc..144e30c4f 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateFieldProjectionTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateFieldProjectionTests.java @@ -39,6 +39,8 @@ import org.springframework.data.mongodb.test.util.MongoTestTemplate; import org.springframework.data.mongodb.test.util.Template; /** + * Integration tests for {@link org.springframework.data.mongodb.core.query.Field}. + * * @author Christoph Strobl */ @ExtendWith(MongoTemplateExtension.class) diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 9cf28cb30..829fee072 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -5,6 +5,7 @@ == What's New in Spring Data MongoDB 3.2 * Support for <> to unwrap nested objects into the parent `Document`. +* <>. [[new-features.3.1]] == What's New in Spring Data MongoDB 3.1 diff --git a/src/main/asciidoc/reference/mongodb.adoc b/src/main/asciidoc/reference/mongodb.adoc index 604dd88b8..a463689bd 100644 --- a/src/main/asciidoc/reference/mongodb.adoc +++ b/src/main/asciidoc/reference/mongodb.adoc @@ -1251,7 +1251,7 @@ The `Query` class has some additional methods that provide options for the query ==== Selecting fields MongoDB supports https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/[projecting fields] returned by a query. -A projection can in- & exclude fields (the `_id` field is always included unless explicitly excluded) based on their name. +A projection can include and exclude fields (the `_id` field is always included unless explicitly excluded) based on their name. .Selecting result fields ==== @@ -1268,13 +1268,13 @@ public class Person { Address address; } -query.fields().include("lastname"); <1> +query.fields().include("lastname"); <1> query.fields().exclude("id").include("lastname") <2> -query.fields().include("address") <3> +query.fields().include("address") <3> -query.fields().include("address.city") <4> +query.fields().include("address.city") <4> ---- @@ -1284,31 +1284,31 @@ query.fields().include("address.city") <4> <4> Result will contain the `_id` and and `address` object that only contains the `city` field via `{ "address.city" : 1 }`. ==== -Starting with MongoDB 4.4 it is possible to use the aggregation expressions syntax for field projections as shown below. +Starting with MongoDB 4.4 you can use aggregation expressions for field projections as shown below: -.Computing result fields with expressions +.Computing result fields using expressions ==== [source,java] ---- query.fields() - .project(MongoExpression.create("'$toUpper' : '$last_name'")) <1> - .as("last_name"); <2> + .project(MongoExpression.create("'$toUpper' : '$last_name'")) <1> + .as("last_name"); <2> query.fields() - .project(StringOperators.valueOf("lastname").toUpper()) <3> + .project(StringOperators.valueOf("lastname").toUpper()) <3> .as("last_name"); query.fields() .project(AggregationSpELExpression.expressionOf("toUpper(lastname)")) <4> .as("last_name"); ---- -<1> Use a native expression. The used field names must refer to the ones of the document within the database. -<2> Assign the field name that shall hold the expression result in the target document. The resulting field name will never be mapped against the domain model. +<1> Use a native expression. The used field name must refer to field names within the database document. +<2> Assign the field name to which the expression result is projected. The resulting field name is not mapped against the domain model. <3> Use an `AggregationExpression`. Other than native `MongoExpression`, field names are mapped to the ones used in the domain model. <4> Use SpEL along with an `AggregationExpression` to invoke expression functions. Field names are mapped to the ones used in the domain model. ==== -`@Query(fields='...')` allows usage of expression field projections at `Repository` level as described in <>. +`@Query(fields="…")` allows usage of expression field projections at `Repository` level as described in <>. [[mongo-template.querying]] === Methods for Querying for Documents