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 18f8b269be..a3928e40ae 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
@@ -33,6 +33,7 @@
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
+ * @author Jorge Rodríguez
*/
@Collation
@Retention(RetentionPolicy.RUNTIME)
@@ -40,6 +41,7 @@
@Documented
@QueryAnnotation
@Hint
+@ReadPreference
public @interface Query {
/**
@@ -147,4 +149,21 @@
*/
@AliasFor(annotation = Hint.class, attribute = "indexName")
String hint() default "";
+
+ /**
+ * The mode of the read preference to use.
+ * {@code @Query(value = "...", readPreference = "secondary")} can be used as shortcut for:
+ *
+ *
+ * @Query(...) + * @ReadPreference("secondary") + * List<User> findAllByLastname(String collation); + *+ * + * @return the index name. + * @since 4.2 + * @see ReadPreference#value() + */ + @AliasFor(annotation = ReadPreference.class, attribute = "value") + String readPreference() default ""; } 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 new file mode 100644 index 0000000000..2ba4e32fd7 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreference.java @@ -0,0 +1,53 @@ +/* + * Copyright 2011-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to declare read preference for repository and query. + * + * @author Jorge Rodríguez + * @since 4.2 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) +@Documented +public @interface ReadPreference { + + /** + * Configure read preference mode + * @return read preference mode + */ + String value() default ""; + + /** + * Set read preference tags + * @return read preference tags + */ + ReadPreferenceTag[] tags() default {}; + + /** + * Set read preference maxStalenessSeconds + * @return read preference maxStalenessSeconds + */ + long maxStalenessSeconds() default -1; +} + diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreferenceTag.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreferenceTag.java new file mode 100644 index 0000000000..5fae877ee2 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreferenceTag.java @@ -0,0 +1,37 @@ +/* + * Copyright 2011-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mongodb.repository; + +/** + * Annotation used by {@link ReadPreference} for define {@link com.mongodb.Tag} + * + * @author Jorge Rodríguez + * @since 4.2 + */ +public @interface ReadPreferenceTag { + + /** + * Set the name of tag + * @return name of tag + */ + String name(); + + /** + * Set the value of tag + * @return value of tag + */ + String value(); +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java index e8d69504d7..0913a9fb4b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java @@ -62,6 +62,7 @@ * @author Thomas Darimont * @author Christoph Strobl * @author Mark Paluch + * @author Jorge Rodríguez */ public abstract class AbstractMongoQuery implements RepositoryQuery { @@ -137,6 +138,7 @@ protected Object doExecute(MongoQueryMethod method, ResultProcessor processor, C query = applyAnnotatedDefaultSortIfPresent(query); query = applyAnnotatedCollationIfPresent(query, accessor); query = applyHintIfPresent(query); + query = applyAnnotatedReadPreferenceIfPresent(query); FindWithQuery> find = typeToRead == null // ? executableFind // @@ -145,6 +147,22 @@ protected Object doExecute(MongoQueryMethod method, ResultProcessor processor, C return getExecution(accessor, find).execute(query); } + /** + * If present apply the {@link com.mongodb.ReadPreference} from the {@link org.springframework.data.mongodb.repository.ReadPreference} annotation. + * + * @param query must not be {@literal null}. + * @return never {@literal null}. + * @since 4.2 + */ + private Query applyAnnotatedReadPreferenceIfPresent(Query query) { + + if (!method.hasAnnotatedReadPreference()) { + return query; + } + + return query.withReadPreference(method.getAnnotatedReadPreference()); + } + private MongoQueryExecution getExecution(ConvertingParameterAccessor accessor, FindWithQuery> operation) { if (isDeleteQuery()) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java index fb430a1517..51301697e5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java @@ -66,6 +66,7 @@ * * @author Mark Paluch * @author Christoph Strobl + * @author Jorge Rodríguez * @since 2.0 */ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { @@ -161,6 +162,8 @@ protected Publisher