From e72470993deaac31f8f8af043e7c48aeb8af7869 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 10 Aug 2020 16:21:34 +0200 Subject: [PATCH] DATACMNS-1754 - Polishing. Revert bean name change so all nested repository interface components (repository bean, fragment bean, legacy custom implementation bean) remain prefixed with their enclosing type name. Adopt tests. Add test for RepositoryBeanDefinitionRegistrar. Extend documentation. Original pull request: #460. --- src/main/asciidoc/repositories.adoc | 12 +++++- ...aultImplementationLookupConfiguration.java | 6 +-- .../cdi/CdiRepositoryBeanUnitTests.java | 25 ++++-------- .../cdi/NestedFragmentInterfaceImpl.java | 27 ------------- .../repository/cdi/RepositoryFragments.java | 10 ++++- .../RepositoryFragmentsIntegrationTests.java | 3 +- ...mentationLookupConfigurationUnitTests.java | 2 +- ...anDefinitionRegistrarSupportUnitTests.java | 38 +++++++++++++++++++ 8 files changed, 71 insertions(+), 52 deletions(-) delete mode 100644 src/test/java/org/springframework/data/repository/cdi/NestedFragmentInterfaceImpl.java diff --git a/src/main/asciidoc/repositories.adoc b/src/main/asciidoc/repositories.adoc index 2edeb8c6f..da1170c9a 100644 --- a/src/main/asciidoc/repositories.adoc +++ b/src/main/asciidoc/repositories.adoc @@ -749,10 +749,18 @@ Each Spring Data module includes a `repositories` element that lets you define a ---- ==== -In the preceding example, Spring is instructed to scan `com.acme.repositories` and all its sub-packages for interfaces extending `Repository` or one of its sub-interfaces. For each interface found, the infrastructure registers the persistence technology-specific `FactoryBean` to create the appropriate proxies that handle invocations of the query methods. Each bean is registered under a bean name that is derived from the interface name, so an interface of `UserRepository` would be registered under `userRepository`. The `base-package` attribute allows wildcards so that you can define a pattern of scanned packages. +In the preceding example, Spring is instructed to scan `com.acme.repositories` and all its sub-packages for interfaces extending `Repository` or one of its sub-interfaces. +For each interface found, the infrastructure registers the persistence technology-specific `FactoryBean` to create the appropriate proxies that handle invocations of the query methods. +Each bean is registered under a bean name that is derived from the interface name, so an interface of `UserRepository` would be registered under `userRepository`. +Bean names for nested repository interfaces are prefixed with their enclosing type name. +The `base-package` attribute allows wildcards so that you can define a pattern of scanned packages. ==== Using filters -By default, the infrastructure picks up every interface extending the persistence technology-specific `Repository` sub-interface located under the configured base package and creates a bean instance for it. However, you might want more fine-grained control over which interfaces have bean instances created for them. To do so, use `` and `` elements inside the `` element. The semantics are exactly equivalent to the elements in Spring's context namespace. For details, see the link:{spring-framework-docs}/core.html#beans-scanning-filters[Spring reference documentation] for these elements. +By default, the infrastructure picks up every interface extending the persistence technology-specific `Repository` sub-interface located under the configured base package and creates a bean instance for it. +However, you might want more fine-grained control over which interfaces have bean instances created for them. +To do so, use `` and `` elements inside the `` element. +The semantics are exactly equivalent to the elements in Spring's context namespace. +For details, see the link:{spring-framework-docs}/core.html#beans-scanning-filters[Spring reference documentation] for these elements. For example, to exclude certain interfaces from instantiation as repository beans, you could use the following configuration: diff --git a/src/main/java/org/springframework/data/repository/config/DefaultImplementationLookupConfiguration.java b/src/main/java/org/springframework/data/repository/config/DefaultImplementationLookupConfiguration.java index dfd1dac05..c321a6d60 100644 --- a/src/main/java/org/springframework/data/repository/config/DefaultImplementationLookupConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/DefaultImplementationLookupConfiguration.java @@ -56,7 +56,8 @@ class DefaultImplementationLookupConfiguration implements ImplementationLookupCo this.config = config; this.interfaceName = interfaceName; - this.beanName = Introspector.decapitalize(getLocalName(interfaceName).concat(config.getImplementationPostfix())); + this.beanName = Introspector + .decapitalize(ClassUtils.getShortName(interfaceName).concat(config.getImplementationPostfix())); } /* @@ -144,7 +145,7 @@ class DefaultImplementationLookupConfiguration implements ImplementationLookupCo String localName = getLocalName(beanClassName); return localName.equals(getImplementationClassName()) // - && getBasePackages().stream().anyMatch(it -> beanPackage.startsWith(it)); + && getBasePackages().stream().anyMatch(beanPackage::startsWith); } private String getLocalName(String className) { @@ -159,7 +160,6 @@ class DefaultImplementationLookupConfiguration implements ImplementationLookupCo MetadataReader reader = getMetadataReaderFactory().getMetadataReader(beanClassName); return filters.stream().anyMatch(it -> matches(it, reader)); - } catch (IOException o_O) { return true; } diff --git a/src/test/java/org/springframework/data/repository/cdi/CdiRepositoryBeanUnitTests.java b/src/test/java/org/springframework/data/repository/cdi/CdiRepositoryBeanUnitTests.java index 96733586d..9193a8b98 100755 --- a/src/test/java/org/springframework/data/repository/cdi/CdiRepositoryBeanUnitTests.java +++ b/src/test/java/org/springframework/data/repository/cdi/CdiRepositoryBeanUnitTests.java @@ -131,33 +131,24 @@ class CdiRepositoryBeanUnitTests { @Test // DATACMNS-322 void createsPassivationId() { - CdiRepositoryBean bean = new DummyCdiRepositoryBean<>( // - SINGLE_ANNOTATION, // - SampleRepository.class, // - beanManager // + CdiRepositoryBean bean = new DummyCdiRepositoryBean<>(SINGLE_ANNOTATION, SampleRepository.class, + beanManager ); assertThat(bean.getId()).isEqualTo(PASSIVATION_ID); } - @Test // DATACMNS-764 + @Test // DATACMNS-764, DATACMNS-1754 void passesCorrectBeanNameToTheImplementationDetector() { CustomRepositoryImplementationDetector detector = mock(CustomRepositoryImplementationDetector.class); - CdiRepositoryBean bean = new CdiRepositoryBean( // - SINGLE_ANNOTATION, // - SampleRepository.class, // - beanManager, // - Optional.of(detector) // - ) { + CdiRepositoryBean bean = new CdiRepositoryBean(SINGLE_ANNOTATION, + SampleRepository.class, beanManager, Optional.of(detector)) { @Override - protected SampleRepository create( // - CreationalContext creationalContext, // - Class repositoryType, // - Optional customImplementation // - ) { + protected SampleRepository create(CreationalContext creationalContext, + Class repositoryType, Optional customImplementation) { return null; } }; @@ -171,7 +162,7 @@ class CdiRepositoryBeanUnitTests { ImplementationLookupConfiguration configuration = captor.getValue(); - assertThat(configuration.getImplementationBeanName()).isEqualTo("sampleRepositoryImpl"); + assertThat(configuration.getImplementationBeanName()).isEqualTo("cdiRepositoryBeanUnitTests.SampleRepositoryImpl"); assertThat(configuration.getImplementationClassName()).isEqualTo("SampleRepositoryImpl"); } diff --git a/src/test/java/org/springframework/data/repository/cdi/NestedFragmentInterfaceImpl.java b/src/test/java/org/springframework/data/repository/cdi/NestedFragmentInterfaceImpl.java deleted file mode 100644 index be5b02215..000000000 --- a/src/test/java/org/springframework/data/repository/cdi/NestedFragmentInterfaceImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018-2020 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.repository.cdi; - -/** - * @author Kyrylo Merzlikin - */ -public class NestedFragmentInterfaceImpl implements RepositoryFragments.NestedFragmentInterface { - - @Override - public String getKey() { - return "NestedFragmentImpl"; - } -} diff --git a/src/test/java/org/springframework/data/repository/cdi/RepositoryFragments.java b/src/test/java/org/springframework/data/repository/cdi/RepositoryFragments.java index 9b520e1d2..bf82faaff 100644 --- a/src/test/java/org/springframework/data/repository/cdi/RepositoryFragments.java +++ b/src/test/java/org/springframework/data/repository/cdi/RepositoryFragments.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 the original author or authors. + * Copyright 2020 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. @@ -24,4 +24,12 @@ public interface RepositoryFragments { String getKey(); } + + class NestedFragmentInterfaceImpl implements NestedFragmentInterface { + + @Override + public String getKey() { + return "NestedFragmentImpl"; + } + } } diff --git a/src/test/java/org/springframework/data/repository/cdi/RepositoryFragmentsIntegrationTests.java b/src/test/java/org/springframework/data/repository/cdi/RepositoryFragmentsIntegrationTests.java index 1962921b1..32433f7d1 100644 --- a/src/test/java/org/springframework/data/repository/cdi/RepositoryFragmentsIntegrationTests.java +++ b/src/test/java/org/springframework/data/repository/cdi/RepositoryFragmentsIntegrationTests.java @@ -82,7 +82,8 @@ class RepositoryFragmentsIntegrationTests { void shouldFindImplementationForNestedRepositoryFragment() { ComposedRepository repository = getBean(ComposedRepository.class); - NestedFragmentInterfaceImpl fragment = getBean(NestedFragmentInterfaceImpl.class); + RepositoryFragments.NestedFragmentInterfaceImpl fragment = getBean( + RepositoryFragments.NestedFragmentInterfaceImpl.class); assertThat(repository.getKey()).isEqualTo("NestedFragmentImpl"); assertThat(fragment.getKey()).isEqualTo("NestedFragmentImpl"); diff --git a/src/test/java/org/springframework/data/repository/config/DefaultImplementationLookupConfigurationUnitTests.java b/src/test/java/org/springframework/data/repository/config/DefaultImplementationLookupConfigurationUnitTests.java index 5da3df4e2..01f56c348 100644 --- a/src/test/java/org/springframework/data/repository/config/DefaultImplementationLookupConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/DefaultImplementationLookupConfigurationUnitTests.java @@ -46,7 +46,7 @@ class DefaultImplementationLookupConfigurationUnitTests { DefaultImplementationLookupConfiguration lookupConfiguration = new DefaultImplementationLookupConfiguration(idcMock, "com.acme.Repositories$NestedRepository"); - assertThat(lookupConfiguration.getImplementationBeanName()).isEqualTo("nestedRepositoryImpl"); + assertThat(lookupConfiguration.getImplementationBeanName()).isEqualTo("repositories.NestedRepositoryImpl"); assertThat(lookupConfiguration.getImplementationClassName()).isEqualTo("NestedRepositoryImpl"); } diff --git a/src/test/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupportUnitTests.java b/src/test/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupportUnitTests.java index 299f3dbd2..0ee7df39a 100755 --- a/src/test/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupportUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupportUnitTests.java @@ -36,6 +36,8 @@ import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.StandardAnnotationMetadata; +import org.springframework.data.mapping.Person; +import org.springframework.data.repository.Repository; import org.springframework.data.repository.config.basepackage.FragmentImpl; import org.springframework.data.repository.core.support.DummyRepositoryFactoryBean; @@ -76,6 +78,18 @@ class RepositoryBeanDefinitionRegistrarSupportUnitTests { assertNoBeanDefinitionRegisteredFor("profileRepository"); } + @Test // DATACMNS-1754 + void registersBeanDefinitionForNestedRepositories() { + + AnnotationMetadata metadata = AnnotationMetadata.introspect(NestedRepositoriesConfiguration.class); + + registrar.registerBeanDefinitions(metadata, registry); + + assertBeanDefinitionRegisteredFor("repositoryBeanDefinitionRegistrarSupportUnitTests.MyNestedRepository"); + assertBeanDefinitionRegisteredFor("repositoryBeanDefinitionRegistrarSupportUnitTests.NestedFragmentImpl"); + assertBeanDefinitionRegisteredFor("repositoryBeanDefinitionRegistrarSupportUnitTests.MyNestedRepositoryImpl"); + } + @Test // DATACMNS-1147 void registersBeanDefinitionWithoutFragmentImplementations() { @@ -183,4 +197,28 @@ class RepositoryBeanDefinitionRegistrarSupportUnitTests { @EnableRepositories(basePackageClasses = FragmentImpl.class) static class LimitsImplementationBasePackages {} + + @EnableRepositories(basePackageClasses = MyNestedRepository.class, considerNestedRepositories = true, + excludeFilters = { + @Filter(type = FilterType.ASSIGNABLE_TYPE, + value = RepositoryConfigurationExtensionSupportUnitTests.ReactiveRepository.class), + @Filter(type = FilterType.ASSIGNABLE_TYPE, value = MyOtherRepository.class) }) + static class NestedRepositoriesConfiguration {} + + interface MyNestedRepository extends Repository, NestedFragment { + + } + + interface NestedFragment { + + } + + static class NestedFragmentImpl implements NestedFragment { + + } + + static class MyNestedRepositoryImpl { + + } + }