From 74b07e5d2198a69e9460265c247c1744ecac3a2f Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 9 Oct 2023 10:39:57 +0200 Subject: [PATCH] Polishing. Tweak documentation wording. Refine constructor nullability rules. Fix javadoc references. Original Pull Request: #4503 --- .../data/mongodb/repository/Aggregation.java | 8 +-- .../data/mongodb/repository/Query.java | 12 ++--- .../mongodb/repository/ReadPreference.java | 9 ++-- .../repository/query/MongoQueryMethod.java | 26 +++++----- .../support/SimpleMongoRepository.java | 39 ++++++++------ .../SimpleReactiveMongoRepository.java | 52 +++++++++++-------- 6 files changed, 79 insertions(+), 67 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Aggregation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Aggregation.java index 42cd40c75..62dca82c5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Aggregation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Aggregation.java @@ -28,11 +28,11 @@ import org.springframework.data.mongodb.core.annotation.Collation; /** * The {@link Aggregation} annotation can be used to annotate a {@link org.springframework.data.repository.Repository} * query method so that it runs the {@link Aggregation#pipeline()} on invocation. - *
+ *

* Pipeline stages are mapped against the {@link org.springframework.data.repository.Repository} domain type to consider * {@link org.springframework.data.mongodb.core.mapping.Field field} mappings and may contain simple placeholders * {@code ?0} as well as {@link org.springframework.expression.spel.standard.SpelExpression SpelExpressions}. - *
+ *

* Query method {@link org.springframework.data.domain.Sort} and {@link org.springframework.data.domain.Pageable} * arguments are applied at the end of the pipeline or can be defined manually as part of it. * @@ -130,8 +130,8 @@ public @interface Aggregation { String collation() default ""; /** - * The mode of the read preference to use.
- * {@code @Aggregation(pipeline = { ... }, readPreference = "secondary")} can be used as shortcut for: + * The mode of the read preference to use. This attribute ({@code @Aggregation(pipeline = { ... }, readPreference = + * "secondary")}) is an alias for: * *

 	 * @@Aggregation(pipeline = { ... })
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java
index 05d741ddd..f5a603d66 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java
@@ -85,9 +85,8 @@ public @interface Query {
 	boolean delete() default false;
 
 	/**
-	 * Defines a default sort order for the given query.
- * NOTE: The so set defaults can be altered / overwritten using an explicit - * {@link org.springframework.data.domain.Sort} argument of the query method. + * Defines a default sort order for the given query. NOTE: The so set defaults can be altered / + * overwritten using an explicit {@link org.springframework.data.domain.Sort} argument of the query method. * *
 	 * 
@@ -134,8 +133,7 @@ public @interface Query {
 	String collation() default "";
 
 	/**
-	 * The name of the index to use. 
- * {@code @Query(value = "...", hint = "lastname-idx")} can be used as shortcut for: + * The name of the index to use. {@code @Query(value = "...", hint = "lastname-idx")} can be used as shortcut for: * *
 	 * @Query(...)
@@ -151,8 +149,8 @@ public @interface Query {
 	String hint() default "";
 
 	/**
-	 * The mode of the read preference to use. 
- * {@code @Query(value = "...", readPreference = "secondary")} can be used as shortcut for: + * The mode of the read preference to use. This attribute + * ({@code @Query(value = "...", readPreference = "secondary")}) is an alias for: * *
 	 * @Query(...)
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreference.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreference.java
index 0def67a22..8fabf9570 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreference.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreference.java
@@ -27,17 +27,18 @@ import java.lang.annotation.Target;
  * @author Jorge Rodríguez
  * @author Christoph Strobl
  * @since 4.2
+ * @see com.mongodb.ReadPreference
  */
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
+@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
 @Documented
 public @interface ReadPreference {
 
 	/**
-	 * Configure read preference mode
-	 * @return read preference mode
+	 * Configure the read preference mode.
+	 *
+	 * @return read preference mode.
 	 */
 	String value() default "";
 
 }
-
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java
index 68ba0a742..426e393d8 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryMethod.java
@@ -293,9 +293,9 @@ public class MongoQueryMethod extends QueryMethod {
 	}
 
 	/**
-	 * Check if the query method is decorated with an non empty {@link Query#sort()}.
+	 * Check if the query method is decorated with a non-empty {@link Query#sort()}.
 	 *
-	 * @return true if method annotated with {@link Query} having an non empty sort attribute.
+	 * @return true if method annotated with {@link Query} having a non-empty sort attribute.
 	 * @since 2.1
 	 */
 	public boolean hasAnnotatedSort() {
@@ -316,9 +316,8 @@ public class MongoQueryMethod extends QueryMethod {
 				"Expected to find @Query annotation but did not; Make sure to check hasAnnotatedSort() before."));
 	}
 
-
 	/**
-	 * Check if the query method is decorated with an non empty {@link ReadPreference}.
+	 * Check if the query method is decorated with a non-empty {@link ReadPreference}.
 	 *
 	 * @return true if method annotated with {@link Query} or {@link Aggregation} having a non-empty collation attribute.
 	 * @since 4.2
@@ -332,18 +331,20 @@ public class MongoQueryMethod extends QueryMethod {
 	 *
 	 * @return the name of the {@link ReadPreference()}.
 	 * @throws IllegalStateException if method not annotated with {@link Query}. Make sure to check
-	 *                               {@link #hasAnnotatedQuery()} first.
+	 *           {@link #hasAnnotatedReadPreference()} first.
 	 * @since 4.2
 	 */
 	public String getAnnotatedReadPreference() {
 
 		return doFindReadPreferenceAnnotation().map(ReadPreference::value).orElseThrow(() -> new IllegalStateException(
-						"Expected to find @ReadPreference annotation but did not; Make sure to check hasAnnotatedReadPreference() before."));
+				"Expected to find @ReadPreference annotation but did not; Make sure to check hasAnnotatedReadPreference() before."));
 	}
 
 	/**
-	 * Get {@link com.mongodb.ReadPreference#getName() name} from query. First check if the method is annotated. If not, check if the class is annotated.
-	 * So if the method and the class are annotated with @ReadPreference, the method annotation takes precedence.
+	 * Get {@link com.mongodb.ReadPreference#getName() name} from query. First check if the method is annotated. If not,
+	 * check if the class is annotated. So if the method and the class are annotated with @ReadPreference, the method
+	 * annotation takes precedence.
+	 *
 	 * @return the {@link ReadPreference}
 	 * @since 4.2
 	 */
@@ -352,7 +353,7 @@ public class MongoQueryMethod extends QueryMethod {
 	}
 
 	/**
-	 * Check if the query method is decorated with an non empty {@link Query#collation()} or or
+	 * Check if the query method is decorated with a non-empty {@link Query#collation()} or
 	 * {@link Aggregation#collation()}.
 	 *
 	 * @return true if method annotated with {@link Query} or {@link Aggregation} having a non-empty collation attribute.
@@ -365,7 +366,7 @@ public class MongoQueryMethod extends QueryMethod {
 	/**
 	 * Get the collation value extracted from the {@link Query} or {@link Aggregation} annotation.
 	 *
-	 * @return the {@link Query#collation()} or or {@link Aggregation#collation()} value.
+	 * @return the {@link Query#collation()} or {@link Aggregation#collation()} value.
 	 * @throws IllegalStateException if method not annotated with {@link Query} or {@link Aggregation}. Make sure to check
 	 *           {@link #hasAnnotatedQuery()} first.
 	 * @since 2.2
@@ -443,9 +444,10 @@ public class MongoQueryMethod extends QueryMethod {
 	}
 
 	@SuppressWarnings("unchecked")
-	private  Optional  doFindAnnotationInClass(Class annotationType) {
+	private  Optional doFindAnnotationInClass(Class annotationType) {
 
-		Optional mergedAnnotation = Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), annotationType));
+		Optional mergedAnnotation = Optional
+				.ofNullable(AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), annotationType));
 		annotationCache.put(annotationType, mergedAnnotation);
 
 		return (Optional) mergedAnnotation;
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java
index 077c84291..4b236a6c9 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java
@@ -27,23 +27,22 @@ import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import com.mongodb.ReadPreference;
 import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.dao.OptimisticLockingFailureException;
 import org.springframework.data.domain.Example;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Window;
 import org.springframework.data.domain.ScrollPosition;
 import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Window;
 import org.springframework.data.mongodb.core.ExecutableFindOperation;
 import org.springframework.data.mongodb.core.MongoOperations;
 import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.mongodb.core.ReadPreferenceAware;
 import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.Query;
 import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.mongodb.repository.ReadPreference;
 import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
 import org.springframework.data.repository.core.RepositoryMetadata;
 import org.springframework.data.support.PageableExecutionUtils;
@@ -67,10 +66,10 @@ import com.mongodb.client.result.DeleteResult;
  */
 public class SimpleMongoRepository implements MongoRepository {
 
-	private final @Nullable RepositoryMetadata repositoryMetadata;
 	private final MongoEntityInformation entityInformation;
 	private final MongoOperations mongoOperations;
-	private final Lazy readPreference;
+	private final Lazy readPreference;
+
 	/**
 	 * Creates a new {@link SimpleMongoRepository} for the given {@link MongoEntityInformation} and {@link MongoTemplate}.
 	 *
@@ -78,34 +77,40 @@ public class SimpleMongoRepository implements MongoRepository {
 	 * @param mongoOperations must not be {@literal null}.
 	 */
 	public SimpleMongoRepository(MongoEntityInformation metadata, MongoOperations mongoOperations) {
-		this(null, metadata, mongoOperations);
+		this(null, metadata, mongoOperations, null);
 	}
 
 	/**
 	 * Creates a new {@link SimpleMongoRepository} for the given {@link MongoEntityInformation} and {@link MongoTemplate}.
 	 *
-	 * @param repositoryMetadata
+	 * @param repositoryMetadata must not be {@literal null}.
 	 * @param metadata must not be {@literal null}.
 	 * @param mongoOperations must not be {@literal null}.
 	 * @since 4.2
 	 */
-	public SimpleMongoRepository(@Nullable RepositoryMetadata repositoryMetadata, MongoEntityInformation metadata, MongoOperations mongoOperations) {
+	public SimpleMongoRepository(RepositoryMetadata repositoryMetadata, MongoEntityInformation metadata,
+			MongoOperations mongoOperations) {
+		this(repositoryMetadata, metadata, mongoOperations, null);
+	}
+
+	private SimpleMongoRepository(@Nullable RepositoryMetadata repositoryMetadata, MongoEntityInformation metadata,
+			MongoOperations mongoOperations, @Nullable Object marker) {
 
 		Assert.notNull(metadata, "MongoEntityInformation must not be null");
 		Assert.notNull(mongoOperations, "MongoOperations must not be null");
 
-		this.repositoryMetadata = repositoryMetadata;
 		this.entityInformation = metadata;
 		this.mongoOperations = mongoOperations;
 
-		this.readPreference = repositoryMetadata == null ? Lazy.empty() :  Lazy.of(() -> {
-					org.springframework.data.mongodb.repository.ReadPreference preference = AnnotatedElementUtils.findMergedAnnotation(repositoryMetadata.getRepositoryInterface(), org.springframework.data.mongodb.repository.ReadPreference.class);
-					if (preference == null) {
-						return null;
-					}
-					return ReadPreference.valueOf(preference.value());
-				}
-		);
+		this.readPreference = repositoryMetadata == null ? Lazy.empty() : Lazy.of(() -> {
+			ReadPreference preference = AnnotatedElementUtils
+					.findMergedAnnotation(repositoryMetadata.getRepositoryInterface(), ReadPreference.class);
+
+			if (preference == null) {
+				return null;
+			}
+			return com.mongodb.ReadPreference.valueOf(preference.value());
+		});
 	}
 
 	// -------------------------------------------------------------------------
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.java
index f1db095f1..698aec3e1 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.java
@@ -17,12 +17,6 @@ package org.springframework.data.mongodb.repository.support;
 
 import static org.springframework.data.mongodb.core.query.Criteria.*;
 
-import com.mongodb.ReadPreference;
-import org.springframework.core.annotation.AnnotatedElementUtils;
-import org.springframework.data.mongodb.core.MongoTemplate;
-import org.springframework.data.repository.core.RepositoryMetadata;
-import org.springframework.data.util.Lazy;
-import org.springframework.lang.Nullable;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
@@ -35,23 +29,29 @@ import java.util.function.UnaryOperator;
 import java.util.stream.Collectors;
 
 import org.reactivestreams.Publisher;
+import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.dao.IncorrectResultSizeDataAccessException;
 import org.springframework.dao.OptimisticLockingFailureException;
 import org.springframework.data.domain.Example;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Window;
 import org.springframework.data.domain.ScrollPosition;
 import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Window;
+import org.springframework.data.mongodb.core.MongoTemplate;
 import org.springframework.data.mongodb.core.ReactiveFindOperation;
 import org.springframework.data.mongodb.core.ReactiveMongoOperations;
 import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.Query;
 import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
+import org.springframework.data.mongodb.repository.ReadPreference;
 import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
+import org.springframework.data.repository.core.RepositoryMetadata;
 import org.springframework.data.repository.query.FluentQuery;
+import org.springframework.data.util.Lazy;
 import org.springframework.data.util.StreamUtils;
 import org.springframework.data.util.Streamable;
+import org.springframework.lang.Nullable;
 import org.springframework.util.Assert;
 
 import com.mongodb.client.result.DeleteResult;
@@ -69,42 +69,48 @@ import com.mongodb.client.result.DeleteResult;
  */
 public class SimpleReactiveMongoRepository implements ReactiveMongoRepository {
 
-	private final @Nullable RepositoryMetadata repositoryMetadata;
 	private final MongoEntityInformation entityInformation;
 	private final ReactiveMongoOperations mongoOperations;
-	private final Lazy readPreference;
+	private final Lazy readPreference;
 
 	public SimpleReactiveMongoRepository(MongoEntityInformation entityInformation,
 			ReactiveMongoOperations mongoOperations) {
-		this(null, entityInformation, mongoOperations);
+		this(null, entityInformation, mongoOperations, null);
 	}
 
 	/**
-	 * Creates a new {@link SimpleReactiveMongoRepository} for the given {@link MongoEntityInformation} and {@link MongoTemplate}.
+	 * Creates a new {@link SimpleReactiveMongoRepository} for the given {@link MongoEntityInformation} and
+	 * {@link MongoTemplate}.
 	 *
-	 * @param repositoryMetadata
+	 * @param repositoryMetadata must not be {@literal null}.
 	 * @param entityInformation must not be {@literal null}.
 	 * @param mongoOperations must not be {@literal null}.
 	 * @since 4.2
 	 */
-	public SimpleReactiveMongoRepository(@Nullable RepositoryMetadata repositoryMetadata, MongoEntityInformation entityInformation,
-			ReactiveMongoOperations mongoOperations) {
+	public SimpleReactiveMongoRepository(RepositoryMetadata repositoryMetadata,
+			MongoEntityInformation entityInformation, ReactiveMongoOperations mongoOperations) {
+		this(repositoryMetadata, entityInformation, mongoOperations, null);
+	}
+
+	private SimpleReactiveMongoRepository(@Nullable RepositoryMetadata repositoryMetadata,
+			MongoEntityInformation entityInformation, ReactiveMongoOperations mongoOperations,
+			@Nullable Object marker) {
 
 		Assert.notNull(entityInformation, "EntityInformation must not be null");
 		Assert.notNull(mongoOperations, "MongoOperations must not be null");
 
-		this.repositoryMetadata = repositoryMetadata;
 		this.entityInformation = entityInformation;
 		this.mongoOperations = mongoOperations;
 
-		this.readPreference = repositoryMetadata == null ? Lazy.empty() :  Lazy.of(() -> {
-					org.springframework.data.mongodb.repository.ReadPreference preference = AnnotatedElementUtils.findMergedAnnotation(repositoryMetadata.getRepositoryInterface(), org.springframework.data.mongodb.repository.ReadPreference.class);
-					if (preference == null) {
-						return null;
-					}
-					return ReadPreference.valueOf(preference.value());
-				}
-		);
+		this.readPreference = repositoryMetadata == null ? Lazy.empty() : Lazy.of(() -> {
+
+			ReadPreference preference = AnnotatedElementUtils
+					.findMergedAnnotation(repositoryMetadata.getRepositoryInterface(), ReadPreference.class);
+			if (preference == null) {
+				return null;
+			}
+			return com.mongodb.ReadPreference.valueOf(preference.value());
+		});
 	}
 
 	// -------------------------------------------------------------------------