diff --git a/src/main/java/org/springframework/data/repository/support/Repositories.java b/src/main/java/org/springframework/data/repository/support/Repositories.java index 2dd89f6c3..3516b3d29 100644 --- a/src/main/java/org/springframework/data/repository/support/Repositories.java +++ b/src/main/java/org/springframework/data/repository/support/Repositories.java @@ -27,6 +27,8 @@ import java.util.Set; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.repository.core.EntityInformation; @@ -91,7 +93,7 @@ public class Repositories implements Iterable> { } } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings("rawtypes") private synchronized void cacheRepositoryFactory(String name) { RepositoryFactoryInformation repositoryFactoryInformation = beanFactory.get().getBean(name, @@ -101,15 +103,13 @@ public class Repositories implements Iterable> { RepositoryInformation information = repositoryFactoryInformation.getRepositoryInformation(); Set> alternativeDomainTypes = information.getAlternativeDomainTypes(); - String beanName = BeanFactoryUtils.transformedBeanName(name); Set> typesToRegister = new HashSet<>(alternativeDomainTypes.size() + 1); typesToRegister.add(domainType); typesToRegister.addAll(alternativeDomainTypes); for (Class type : typesToRegister) { - this.repositoryFactoryInfos.put(type, repositoryFactoryInformation); - this.repositoryBeanNames.put(type, beanName); + cacheFirstOrPrimary(type, repositoryFactoryInformation, BeanFactoryUtils.transformedBeanName(name)); } } @@ -263,6 +263,35 @@ public class Repositories implements Iterable> { return repositoryFactoryInfos.keySet().iterator(); } + /** + * Caches the repository information for the given domain type or overrides existing information in case the bean name + * points to a primary bean definition. + * + * @param type must not be {@literal null}. + * @param information must not be {@literal null}. + * @param name must not be {@literal null}. + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private void cacheFirstOrPrimary(Class type, RepositoryFactoryInformation information, String name) { + + if (repositoryBeanNames.containsKey(type)) { + + Boolean presentAndPrimary = beanFactory // + .filter(ConfigurableListableBeanFactory.class::isInstance) // + .map(ConfigurableListableBeanFactory.class::cast) // + .map(it -> it.getBeanDefinition(name)) // + .map(BeanDefinition::isPrimary) // + .orElse(false); + + if (!presentAndPrimary) { + return; + } + } + + this.repositoryFactoryInfos.put(type, information); + this.repositoryBeanNames.put(type, name); + } + /** * Null-object to avoid nasty {@literal null} checks in cache lookups. * diff --git a/src/test/java/org/springframework/data/repository/support/RepositoriesUnitTests.java b/src/test/java/org/springframework/data/repository/support/RepositoriesUnitTests.java index 93a6fe6ee..4b5f2aceb 100755 --- a/src/test/java/org/springframework/data/repository/support/RepositoriesUnitTests.java +++ b/src/test/java/org/springframework/data/repository/support/RepositoriesUnitTests.java @@ -33,6 +33,7 @@ import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.annotation.Primary; import org.springframework.context.support.GenericApplicationContext; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.context.SampleMappingContext; @@ -158,6 +159,28 @@ public class RepositoriesUnitTests { assertThat(repositories.getRepositoryFor(proxy.getClass())).isNotEmpty(); } + @Test // DATACMNS-1448 + public void keepsPrimaryRepositoryInCaseOfMultipleOnes() { + + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + beanFactory.registerBeanDefinition("first", getRepositoryBeanDefinition(FirstRepository.class)); + + AbstractBeanDefinition definition = getRepositoryBeanDefinition(PrimaryRepository.class); + definition.setPrimary(true); + + beanFactory.registerBeanDefinition("primary", definition); + beanFactory.registerBeanDefinition("third", getRepositoryBeanDefinition(ThirdRepository.class)); + + context = new GenericApplicationContext(beanFactory); + context.refresh(); + + Repositories repositories = new Repositories(beanFactory); + + assertThat(repositories.getRepositoryFor(SomeEntity.class)).hasValueSatisfying(it -> { + assertThat(it).isInstanceOf(PrimaryRepository.class); + }); + } + class Person {} class Address {} @@ -244,4 +267,13 @@ public class RepositoriesUnitTests { static class SampleEntity implements Sample {} interface SampleRepository extends Repository {} + + interface SomeEntity {} + + interface FirstRepository extends Repository {} + + @Primary + interface PrimaryRepository extends Repository {} + + interface ThirdRepository extends Repository {} }