From d86f5f845236e599216488e306444113d51063e6 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Thu, 2 Nov 2023 14:39:17 +0100 Subject: [PATCH 1/2] Prepare issue branch. --- pom.xml | 2 +- spring-data-mongodb-benchmarks/pom.xml | 2 +- spring-data-mongodb-distribution/pom.xml | 2 +- spring-data-mongodb/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index f4eb82b8bb..e1944c4395 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 4.2.0-SNAPSHOT + 4.2.x-4542-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml index 2de4b6b635..98278be747 100644 --- a/spring-data-mongodb-benchmarks/pom.xml +++ b/spring-data-mongodb-benchmarks/pom.xml @@ -7,7 +7,7 @@ org.springframework.data spring-data-mongodb-parent - 4.2.0-SNAPSHOT + 4.2.x-4542-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index 41b81f9aa6..ee93704bbf 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -15,7 +15,7 @@ org.springframework.data spring-data-mongodb-parent - 4.2.0-SNAPSHOT + 4.2.x-4542-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index d7a9ddaa63..fcde832a09 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -13,7 +13,7 @@ org.springframework.data spring-data-mongodb-parent - 4.2.0-SNAPSHOT + 4.2.x-4542-SNAPSHOT ../pom.xml From 27d486f748659be9233a595b4527c466902ecaca Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Thu, 2 Nov 2023 15:21:08 +0100 Subject: [PATCH 2/2] Resolve ReadPreference on actual repository interface. --- .../CrudMethodMetadataPostProcessor.java | 14 +++-- .../DefaultCrudMethodMetadataUnitTests.java | 59 +++++++++++++++++++ .../SimpleMongoRepositoryUnitTests.java | 6 +- 3 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/DefaultCrudMethodMetadataUnitTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/CrudMethodMetadataPostProcessor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/CrudMethodMetadataPostProcessor.java index 22992b7335..183f427cd7 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/CrudMethodMetadataPostProcessor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/CrudMethodMetadataPostProcessor.java @@ -89,9 +89,12 @@ static class CrudMethodMetadataPopulatingMethodInterceptor implements MethodInte private final ConcurrentMap metadataCache = new ConcurrentHashMap<>(); private final Set implementations = new HashSet<>(); + private final RepositoryInformation repositoryInformation; CrudMethodMetadataPopulatingMethodInterceptor(RepositoryInformation repositoryInformation) { + this.repositoryInformation = repositoryInformation; + ReflectionUtils.doWithMethods(repositoryInformation.getRepositoryInterface(), implementations::add, method -> !repositoryInformation.isQueryMethod(method)); } @@ -140,7 +143,7 @@ public Object invoke(MethodInvocation invocation) throws Throwable { if (methodMetadata == null) { - methodMetadata = new DefaultCrudMethodMetadata(method); + methodMetadata = new DefaultCrudMethodMetadata(repositoryInformation.getRepositoryInterface(), method); CrudMethodMetadata tmp = metadataCache.putIfAbsent(method, methodMetadata); if (tmp != null) { @@ -171,23 +174,24 @@ static class DefaultCrudMethodMetadata implements CrudMethodMetadata { /** * Creates a new {@link DefaultCrudMethodMetadata} for the given {@link Method}. * + * @param repositoryInterface the target repository interface. * @param method must not be {@literal null}. */ - DefaultCrudMethodMetadata(Method method) { + DefaultCrudMethodMetadata(Class repositoryInterface, Method method) { Assert.notNull(method, "Method must not be null"); - this.readPreference = findReadPreference(method); + this.readPreference = findReadPreference(repositoryInterface, method); } - private Optional findReadPreference(Method method) { + private Optional findReadPreference(Class repositoryInterface, Method method) { org.springframework.data.mongodb.repository.ReadPreference preference = AnnotatedElementUtils .findMergedAnnotation(method, org.springframework.data.mongodb.repository.ReadPreference.class); if (preference == null) { - preference = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), + preference = AnnotatedElementUtils.findMergedAnnotation(repositoryInterface, org.springframework.data.mongodb.repository.ReadPreference.class); } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/DefaultCrudMethodMetadataUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/DefaultCrudMethodMetadataUnitTests.java new file mode 100644 index 0000000000..68e23ca9e2 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/DefaultCrudMethodMetadataUnitTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 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.support; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Optional; + +import org.junit.jupiter.api.Test; +import org.springframework.data.mongodb.repository.Person; +import org.springframework.data.mongodb.repository.ReadPreference; +import org.springframework.data.mongodb.repository.support.CrudMethodMetadataPostProcessor.DefaultCrudMethodMetadata; +import org.springframework.data.repository.CrudRepository; +import org.springframework.util.ReflectionUtils; + +/** + * @author Christoph Strobl + */ +class DefaultCrudMethodMetadataUnitTests { + + @Test // GH-4542 + void detectsReadPreferenceOnRepositoryInterface() { + + DefaultCrudMethodMetadata metadata = new DefaultCrudMethodMetadata(ReadPreferenceAnnotated.class, + ReflectionUtils.findMethod(ReadPreferenceAnnotated.class, "findAll")); + + assertThat(metadata.getReadPreference()).hasValue(com.mongodb.ReadPreference.primary()); + } + + @Test // GH-4542 + void favorsReadPreferenceOfAnnotatedMethod() { + + DefaultCrudMethodMetadata metadata = new DefaultCrudMethodMetadata(ReadPreferenceAnnotated.class, + ReflectionUtils.findMethod(ReadPreferenceAnnotated.class, "findById", Object.class)); + + assertThat(metadata.getReadPreference()).hasValue(com.mongodb.ReadPreference.secondary()); + } + + @ReadPreference("primary") + interface ReadPreferenceAnnotated extends CrudRepository { + + @Override + @ReadPreference("secondary") + Optional findById(String s); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepositoryUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepositoryUnitTests.java index 6e2d87b508..9981f72349 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepositoryUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepositoryUnitTests.java @@ -152,7 +152,7 @@ void shouldAddReadPreferenceToFindAllMethods(Consumer(entityInformation, mongoOperations); repository.setRepositoryMethodMetadata( - new DefaultCrudMethodMetadata(TestRepositoryWithReadPreference.class.getMethod("dummy"))); + new DefaultCrudMethodMetadata(TestRepositoryWithReadPreference.class, TestRepositoryWithReadPreference.class.getMethod("dummy"))); findCall.accept(repository); @@ -167,7 +167,7 @@ void shouldAddReadPreferenceToFindOne() throws NoSuchMethodException { repository = new SimpleMongoRepository<>(entityInformation, mongoOperations); repository.setRepositoryMethodMetadata( - new DefaultCrudMethodMetadata(TestRepositoryWithReadPreference.class.getMethod("dummy"))); + new DefaultCrudMethodMetadata(TestRepositoryWithReadPreference.class, TestRepositoryWithReadPreference.class.getMethod("dummy"))); repository.findOne(Example.of(new TestDummy())); @@ -188,7 +188,7 @@ void shouldAddReadPreferenceToFluentFetchable() throws NoSuchMethodException { repository = new SimpleMongoRepository<>(entityInformation, mongoOperations); repository.setRepositoryMethodMetadata( - new DefaultCrudMethodMetadata(TestRepositoryWithReadPreferenceMethod.class.getMethod("dummy"))); + new DefaultCrudMethodMetadata(TestRepositoryWithReadPreferenceMethod.class, TestRepositoryWithReadPreferenceMethod.class.getMethod("dummy"))); repository.findBy(Example.of(new TestDummy()), FetchableFluentQuery::all);