From 27b0d796f9a82e36e9ea26d1dfd7976119c3e944 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 22 Oct 2021 11:10:28 +0200 Subject: [PATCH 1/4] Prepare issue branch. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 75f26f703f..23d7707b15 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.springframework.data spring-data-commons - 3.0.0-SNAPSHOT + 3.0.0-GH-2487-SNAPSHOT Spring Data Core Core Spring concepts underpinning every Spring Data module. From d9b12c8ad8849db8ecba752e9455013c9be331e0 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 20 Oct 2021 14:00:42 +0200 Subject: [PATCH 2/4] Consider derived custom implementation bean name from the repository bean name. We now consider the repository bean name when checking for existing bean definitions of default custom implementation beans. Previously, we used the repository interface name without considering the repository bean name. Closes #2487. --- ...aultImplementationLookupConfiguration.java | 15 +--- .../DefaultRepositoryConfiguration.java | 10 ++- .../ImplementationDetectionConfiguration.java | 6 +- .../config/RepositoryConfiguration.java | 16 ++++ ...sitoryImplementationDetectorUnitTests.java | 16 +++- ...mentationLookupConfigurationUnitTests.java | 34 +++++--- ...ositoryConfigurationDelegateUnitTests.java | 86 ++++++++++++++++++- .../stereotype/MyStereotypeRepository.java | 26 ++++++ .../MyStereotypeRepositoryImpl.java | 24 ++++++ 9 files changed, 204 insertions(+), 29 deletions(-) create mode 100644 src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepository.java create mode 100644 src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepositoryImpl.java 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 9c7eff7c42..4b5b3e512e 100644 --- a/src/main/java/org/springframework/data/repository/config/DefaultImplementationLookupConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/DefaultImplementationLookupConfiguration.java @@ -15,7 +15,6 @@ */ package org.springframework.data.repository.config; -import java.beans.Introspector; import java.io.IOException; import org.springframework.beans.factory.config.BeanDefinition; @@ -42,22 +41,16 @@ class DefaultImplementationLookupConfiguration implements ImplementationLookupCo private final String interfaceName; private final String beanName; - /** - * Creates a new {@link DefaultImplementationLookupConfiguration} for the given - * {@link ImplementationDetectionConfiguration} and interface name. - * - * @param config must not be {@literal null}. - * @param interfaceName must not be {@literal null} or empty. - */ - DefaultImplementationLookupConfiguration(ImplementationDetectionConfiguration config, String interfaceName) { + DefaultImplementationLookupConfiguration(ImplementationDetectionConfiguration config, String interfaceName, + String beanName) { Assert.notNull(config, "ImplementationDetectionConfiguration must not be null"); Assert.hasText(interfaceName, "Interface name must not be null or empty"); + Assert.hasText(beanName, "Bean name must not be null or empty!"); this.config = config; this.interfaceName = interfaceName; - this.beanName = Introspector - .decapitalize(ClassUtils.getShortName(interfaceName).concat(config.getImplementationPostfix())); + this.beanName = beanName; } @Override diff --git a/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java b/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java index 623c94f2f8..7e66b3f3c3 100644 --- a/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java @@ -22,6 +22,7 @@ import org.springframework.core.type.filter.TypeFilter; import org.springframework.data.config.ConfigurationUtils; import org.springframework.data.repository.query.QueryLookupStrategy.Key; +import org.springframework.data.util.Lazy; import org.springframework.data.util.Streamable; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -45,6 +46,7 @@ public class DefaultRepositoryConfiguration beanName; public DefaultRepositoryConfiguration(T configurationSource, BeanDefinition definition, RepositoryConfigurationExtension extension) { @@ -52,6 +54,7 @@ public DefaultRepositoryConfiguration(T configurationSource, BeanDefinition defi this.configurationSource = configurationSource; this.definition = definition; this.extension = extension; + this.beanName = Lazy.of(() -> configurationSource.generateBeanName(definition)); } public String getBeanId() { @@ -90,7 +93,7 @@ public String getImplementationClassName() { } public String getImplementationBeanName() { - return configurationSource.generateBeanName(definition) + return beanName.get() + configurationSource.getRepositoryImplementationPostfix().orElse("Impl"); } @@ -117,6 +120,11 @@ public String getRepositoryFactoryBeanClassName() { .orElseGet(extension::getRepositoryFactoryBeanClassName); } + @Override + public String getRepositoryBeanName() { + return beanName.get(); + } + @Override public boolean isLazyInit() { return definition.isLazyInit() || !configurationSource.getBootstrapMode().equals(BootstrapMode.DEFAULT); diff --git a/src/main/java/org/springframework/data/repository/config/ImplementationDetectionConfiguration.java b/src/main/java/org/springframework/data/repository/config/ImplementationDetectionConfiguration.java index f95323b946..3063a53a84 100644 --- a/src/main/java/org/springframework/data/repository/config/ImplementationDetectionConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/ImplementationDetectionConfiguration.java @@ -90,7 +90,8 @@ default ImplementationLookupConfiguration forFragment(String fragmentInterfaceNa Assert.hasText(fragmentInterfaceName, "Fragment interface name must not be null or empty"); - return new DefaultImplementationLookupConfiguration(this, fragmentInterfaceName); + return new DefaultImplementationLookupConfiguration(this, fragmentInterfaceName, + Introspector.decapitalize(ClassUtils.getShortName(fragmentInterfaceName).concat(getImplementationPostfix()))); } /** @@ -103,7 +104,8 @@ default ImplementationLookupConfiguration forRepositoryConfiguration(RepositoryC Assert.notNull(config, "RepositoryConfiguration must not be null"); - return new DefaultImplementationLookupConfiguration(this, config.getRepositoryInterface()) { + return new DefaultImplementationLookupConfiguration(this, config.getRepositoryInterface(), + config.getImplementationBeanName()) { @Override public Streamable getBasePackages() { diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java index 48bda60916..6ba17d5e1f 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java @@ -84,6 +84,22 @@ public interface RepositoryConfiguration mock = mock(RepositoryConfiguration.class); + when(mock.getImplementationBeanName()).thenReturn("NoImplementationRepositoryImpl"); var lookup = configuration .forRepositoryConfiguration(configFor(NoImplementationRepository.class)); @@ -91,6 +98,7 @@ void returnsBeanDefinitionMatchingByNameWhenMultipleImplementationAreFound() { return className.contains("$First$") ? "canonicalSampleRepositoryTestImpl" : "otherBeanName"; }); + var lookup = configuration .forRepositoryConfiguration(configFor(CanonicalSampleRepository.class)); @@ -113,11 +121,13 @@ void throwsExceptionWhenMultipleImplementationAreFound() { }); } - private RepositoryConfiguration configFor(Class type) { + private RepositoryConfiguration configFor(Class type) { RepositoryConfiguration configuration = mock(RepositoryConfiguration.class); when(configuration.getRepositoryInterface()).thenReturn(type.getSimpleName()); + when(configuration.getImplementationBeanName()) + .thenReturn(Introspector.decapitalize(type.getSimpleName()) + "TestImpl"); when(configuration.getImplementationBasePackages()) .thenReturn(Streamable.of(this.getClass().getPackage().getName())); 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 4da5c73f62..443a68a602 100644 --- a/src/test/java/org/springframework/data/repository/config/DefaultImplementationLookupConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/DefaultImplementationLookupConfigurationUnitTests.java @@ -18,8 +18,14 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import java.beans.Introspector; + +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.util.ClassUtils; + /** * Unit tests for {@link DefaultImplementationLookupConfigurationUnitTests}. * @@ -28,11 +34,17 @@ */ class DefaultImplementationLookupConfigurationUnitTests { - @Test // DATACMNS-1439 - void shouldConsiderBeanNameDecapitalization() { + ImplementationDetectionConfiguration idcMock = mock(ImplementationDetectionConfiguration.class); - var idcMock = mock(ImplementationDetectionConfiguration.class); + @BeforeEach + void setUp() { when(idcMock.getImplementationPostfix()).thenReturn("Impl"); + when(idcMock.forRepositoryConfiguration(any())).thenCallRealMethod(); + when(idcMock.forFragment(any())).thenCallRealMethod(); + } + + @Test // DATACMNS-1439 + void shouldConsiderBeanNameDecapitalization() { assertThat(getImplementationBeanName(idcMock, "com.acme.UDPRepository")).isEqualTo("UDPRepositoryImpl"); assertThat(getImplementationBeanName(idcMock, "com.acme.UdpRepository")).isEqualTo("udpRepositoryImpl"); @@ -41,19 +53,21 @@ void shouldConsiderBeanNameDecapitalization() { @Test // DATACMNS-1754 void shouldUseSimpleClassNameWhenDefiningImplementationNames() { - var idcMock = mock(ImplementationDetectionConfiguration.class); - when(idcMock.getImplementationPostfix()).thenReturn("Impl"); - - var lookupConfiguration = new DefaultImplementationLookupConfiguration(idcMock, - "com.acme.Repositories$NestedRepository"); + ImplementationLookupConfiguration lookupConfiguration = idcMock + .forFragment("com.acme.Repositories$NestedRepository"); assertThat(lookupConfiguration.getImplementationBeanName()).isEqualTo("repositories.NestedRepositoryImpl"); assertThat(lookupConfiguration.getImplementationClassName()).isEqualTo("NestedRepositoryImpl"); } private static String getImplementationBeanName(ImplementationDetectionConfiguration idcMock, String interfaceName) { - var configuration = new DefaultImplementationLookupConfiguration(idcMock, - interfaceName); + RepositoryConfigurationSource source = mock(RepositoryConfigurationSource.class); + when(source.generateBeanName(any())).thenReturn(Introspector.decapitalize(ClassUtils.getShortName(interfaceName))); + + RepositoryConfiguration repoConfig = new DefaultRepositoryConfiguration<>(source, + BeanDefinitionBuilder.rootBeanDefinition(interfaceName).getBeanDefinition(), null); + + ImplementationLookupConfiguration configuration = idcMock.forRepositoryConfiguration(repoConfig); return configuration.getImplementationBeanName(); } } diff --git a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java index 32747be852..6763d18875 100644 --- a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java @@ -19,7 +19,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; @@ -27,6 +26,9 @@ import org.springframework.aop.framework.Advised; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; @@ -34,8 +36,12 @@ import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.metrics.ApplicationStartup; +import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.StandardAnnotationMetadata; import org.springframework.data.repository.config.RepositoryConfigurationDelegate.LazyRepositoryInjectionPointResolver; +import org.springframework.data.repository.config.excluded.MyOtherRepositoryImpl; +import org.springframework.data.repository.config.stereotype.MyStereotypeRepository; +import org.springframework.data.repository.core.support.DummyRepositoryFactoryBean; import org.springframework.data.repository.sample.AddressRepository; import org.springframework.data.repository.sample.AddressRepositoryClient; import org.springframework.data.repository.sample.ProductRepository; @@ -44,13 +50,14 @@ * Unit tests for {@link RepositoryConfigurationDelegate}. * * @author Oliver Gierke + * @author Mark Paluch * @soundtrack Richard Spaven - Tribute (Whole Other*) */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) class RepositoryConfigurationDelegateUnitTests { - @Mock RepositoryConfigurationExtension extension; + RepositoryConfigurationExtension extension = new DummyConfigurationExtension(); @Test // DATACMNS-892 void registersRepositoryBeanNameAsAttribute() { @@ -126,6 +133,60 @@ void writesRepositoryScanningMetrics() { Mockito.verify(startup).start("spring.data.repository.scanning"); } + @Test // GH-2487 + void considersDefaultBeanNames() { + + StandardEnvironment environment = new StandardEnvironment(); + GenericApplicationContext context = new GenericApplicationContext(); + + RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource( + AnnotationMetadata.introspect(DefaultBeanNamesConfig.class), EnableRepositories.class, context, environment, + context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()); + + RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment); + + delegate.registerRepositoriesIn(context, extension); + + assertThat(context.getBeanFactory().getBeanDefinition("myOtherRepository")).isNotNull(); + assertThat(context.getBeanFactory().getBeanDefinition("myOtherRepositoryImpl")).isNotNull(); + } + + @Test // GH-2487 + void considersAnnotatedBeanNamesFromRepository() { + + StandardEnvironment environment = new StandardEnvironment(); + GenericApplicationContext context = new GenericApplicationContext(); + + RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource( + AnnotationMetadata.introspect(AnnotatedBeanNamesConfig.class), EnableRepositories.class, context, environment, + context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()); + + RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment); + + delegate.registerRepositoriesIn(context, extension); + + assertThat(context.getBeanFactory().getBeanDefinition("fooRepository")).isNotNull(); + assertThat(context.getBeanFactory().getBeanDefinition("fooRepositoryImpl")).isNotNull(); + } + + private static ListableBeanFactory assertLazyRepositoryBeanSetup(Class configClass) { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configClass); + + assertThat(context.getDefaultListableBeanFactory().getAutowireCandidateResolver()) + .isInstanceOf(LazyRepositoryInjectionPointResolver.class); + + AddressRepositoryClient client = context.getBean(AddressRepositoryClient.class); + AddressRepository repository = client.getRepository(); + + assertThat(Advised.class.isInstance(repository)).isTrue(); + + TargetSource targetSource = Advised.class.cast(repository).getTargetSource(); + assertThat(targetSource).isNotNull(); + + return context.getDefaultListableBeanFactory(); + } + @EnableRepositories(basePackageClasses = ProductRepository.class) static class TestConfig {} @@ -140,4 +201,25 @@ static class LazyConfig {} includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = AddressRepository.class), bootstrapMode = BootstrapMode.DEFERRED) static class DeferredConfig {} + + @EnableRepositories(basePackageClasses = MyOtherRepository.class, + includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MyOtherRepository.class), + excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MyOtherRepositoryImpl.class)) + static class DefaultBeanNamesConfig {} + + @EnableRepositories(basePackageClasses = MyStereotypeRepository.class, + includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MyStereotypeRepository.class)) + static class AnnotatedBeanNamesConfig {} + + static class DummyConfigurationExtension extends RepositoryConfigurationExtensionSupport { + + public String getRepositoryFactoryBeanClassName() { + return DummyRepositoryFactoryBean.class.getName(); + } + + @Override + protected String getModulePrefix() { + return "commons"; + } + } } diff --git a/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepository.java b/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepository.java new file mode 100644 index 0000000000..28dca49820 --- /dev/null +++ b/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2021 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.config.stereotype; + +import org.springframework.data.mapping.Person; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Component; + +/** + * @author Mark Paluch + */ +@Component("fooRepository") +public interface MyStereotypeRepository extends CrudRepository {} diff --git a/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepositoryImpl.java b/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepositoryImpl.java new file mode 100644 index 0000000000..7a3adae1bd --- /dev/null +++ b/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepositoryImpl.java @@ -0,0 +1,24 @@ +/* + * Copyright 2021 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.config.stereotype; + +import org.springframework.stereotype.Component; + +/** + * @author Mark Paluch + */ +@Component("fooRepositoryImpl") +public class MyStereotypeRepositoryImpl {} From c5900ccf1ca96c52e3a9fd1075e8b91c8c645723 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 20 Oct 2021 15:13:59 +0200 Subject: [PATCH 3/4] Consider component names for custom implementation and fragment bean registration. We now consider the actual bean name when registering custom implementations and repository fragments after falling back to component scan mode. Previously we derived the bean name either from the repository bean name or the class name. Closes #2487. --- ...ustomRepositoryImplementationDetector.java | 17 ++++- .../RepositoryBeanDefinitionBuilder.java | 66 +++++++++++++------ .../RepositoryFragmentConfiguration.java | 36 +++++++--- .../RepositoryComponentProviderUnitTests.java | 4 +- ...ositoryConfigurationDelegateUnitTests.java | 52 ++++++++++++++- .../annotated/MyAnnotatedRepository.java | 24 +++++++ .../annotated/MyAnnotatedRepositoryImpl.java | 24 +++++++ .../config/annotated/MyFragment.java | 21 ++++++ .../config/annotated/MyFragmentImpl.java | 24 +++++++ 9 files changed, 237 insertions(+), 31 deletions(-) create mode 100644 src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepository.java create mode 100644 src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepositoryImpl.java create mode 100644 src/test/java/org/springframework/data/repository/config/annotated/MyFragment.java create mode 100644 src/test/java/org/springframework/data/repository/config/annotated/MyFragmentImpl.java diff --git a/src/main/java/org/springframework/data/repository/config/CustomRepositoryImplementationDetector.java b/src/main/java/org/springframework/data/repository/config/CustomRepositoryImplementationDetector.java index 7be0197916..dc105616a4 100644 --- a/src/main/java/org/springframework/data/repository/config/CustomRepositoryImplementationDetector.java +++ b/src/main/java/org/springframework/data/repository/config/CustomRepositoryImplementationDetector.java @@ -18,6 +18,7 @@ import java.util.Collection; import java.util.Optional; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; import org.springframework.beans.factory.config.BeanDefinition; @@ -107,8 +108,22 @@ public Optional detectCustomImplementation(Implementatio .filter(lookup::matches) // .collect(StreamUtils.toUnmodifiableSet()); + return selectImplementationCandidate(lookup, definitions, () -> { + + if (definitions.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(definitions.iterator().next()); + }); + } + + private static Optional selectImplementationCandidate( + ImplementationLookupConfiguration lookup, Set definitions, + Supplier> fallback) { + return SelectionSet // - .of(definitions, c -> c.isEmpty() ? Optional.empty() : throwAmbiguousCustomImplementationException(c)) // + .of(definitions, c -> c.isEmpty() ? fallback.get() : throwAmbiguousCustomImplementationException(c)) // .filterIfNecessary(lookup::hasMatchingBeanName) // .uniqueResult() // .map(AbstractBeanDefinition.class::cast); diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java index 80695add4d..f316945606 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java @@ -30,6 +30,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; + import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; @@ -183,26 +184,42 @@ private Optional registerCustomImplementation(RepositoryConfiguration ImplementationLookupConfiguration lookup = configuration.toLookupConfiguration(metadataReaderFactory); - String beanName = lookup.getImplementationBeanName(); + String configurationBeanName = lookup.getImplementationBeanName(); // Already a bean configured? - if (registry.containsBeanDefinition(beanName)) { - return Optional.of(beanName); + if (registry.containsBeanDefinition(configurationBeanName)) { + + if (logger.isDebugEnabled()) { + logger.debug(String.format("Custom repository implementation already registered: %s", configurationBeanName)); + } + + return Optional.of(configurationBeanName); } Optional beanDefinition = implementationDetector.detectCustomImplementation(lookup); return beanDefinition.map(it -> { - if (logger.isDebugEnabled()) { - logger.debug("Registering custom repository implementation: " + lookup.getImplementationBeanName() + " " - + it.getBeanClassName()); - } - + String scannedBeanName = configuration.getConfigurationSource().generateBeanName(it); it.setSource(configuration.getSource()); - registry.registerBeanDefinition(beanName, it); - return beanName; + if (registry.containsBeanDefinition(scannedBeanName)) { + + if (logger.isDebugEnabled()) { + logger.debug(String.format("Custom repository implementation already registered: %s %s", scannedBeanName, + it.getBeanClassName())); + } + } else { + + if (logger.isDebugEnabled()) { + logger.debug(String.format("Registering custom repository implementation: %s %s", scannedBeanName, + it.getBeanClassName())); + } + + registry.registerBeanDefinition(scannedBeanName, it); + } + + return scannedBeanName; }); } @@ -232,19 +249,20 @@ private Stream registerRepositoryFragmentsImple .toImplementationDetectionConfiguration(metadataReaderFactory); return fragmentMetadata.getFragmentInterfaces(configuration.getRepositoryInterface()) // - .map(it -> detectRepositoryFragmentConfiguration(it, config)) // + .map(it -> detectRepositoryFragmentConfiguration(it, config, configuration)) // .flatMap(Optionals::toStream) // .peek(it -> potentiallyRegisterFragmentImplementation(configuration, it)) // .peek(it -> potentiallyRegisterRepositoryFragment(configuration, it)); } private Optional detectRepositoryFragmentConfiguration(String fragmentInterface, - ImplementationDetectionConfiguration config) { + ImplementationDetectionConfiguration config, RepositoryConfiguration configuration) { ImplementationLookupConfiguration lookup = config.forFragment(fragmentInterface); Optional beanDefinition = implementationDetector.detectCustomImplementation(lookup); - return beanDefinition.map(bd -> new RepositoryFragmentConfiguration(fragmentInterface, bd)); + return beanDefinition.map(bd -> new RepositoryFragmentConfiguration(fragmentInterface, bd, + configuration.getConfigurationSource().generateBeanName(bd))); } private void potentiallyRegisterFragmentImplementation(RepositoryConfiguration repositoryConfiguration, @@ -254,16 +272,21 @@ private void potentiallyRegisterFragmentImplementation(RepositoryConfiguration { + if (logger.isDebugEnabled()) { + logger.debug(String.format("Registering repository fragment implementation: %s %s", beanName, + fragmentConfiguration.getClassName())); + } + bd.setSource(repositoryConfiguration.getSource()); registry.registerBeanDefinition(beanName, bd); }); @@ -276,11 +299,16 @@ private void potentiallyRegisterRepositoryFragment(RepositoryConfiguration co // Already a bean configured? if (registry.containsBeanDefinition(beanName)) { + + if (logger.isDebugEnabled()) { + logger.debug(String.format("RepositoryFragment already registered: %s", beanName)); + } + return; } if (logger.isDebugEnabled()) { - logger.debug("Registering repository fragment: " + beanName); + logger.debug(String.format("Registering RepositoryFragment: %s", beanName)); } BeanDefinitionBuilder fragmentBuilder = BeanDefinitionBuilder.rootBeanDefinition(RepositoryFragment.class, diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfiguration.java b/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfiguration.java index 6816708553..6e704685ef 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryFragmentConfiguration.java @@ -36,6 +36,7 @@ public final class RepositoryFragmentConfiguration { private final String interfaceName; private final String className; private final Optional beanDefinition; + private final String beanName; /** * Creates a {@link RepositoryFragmentConfiguration} given {@code interfaceName} and {@code className} of the @@ -45,13 +46,7 @@ public final class RepositoryFragmentConfiguration { * @param className must not be {@literal null} or empty. */ public RepositoryFragmentConfiguration(String interfaceName, String className) { - - Assert.hasText(interfaceName, "Interface name must not be null or empty"); - Assert.hasText(className, "Class name must not be null or empty"); - - this.interfaceName = interfaceName; - this.className = className; - this.beanDefinition = Optional.empty(); + this(interfaceName, className, null, generateBeanName(className)); } /** @@ -69,20 +64,45 @@ public RepositoryFragmentConfiguration(String interfaceName, AbstractBeanDefinit this.interfaceName = interfaceName; this.className = ConfigurationUtils.getRequiredBeanClassName(beanDefinition); this.beanDefinition = Optional.of(beanDefinition); + this.beanName = generateBeanName(); } public RepositoryFragmentConfiguration(String interfaceName, String className, Optional beanDefinition) { + this(interfaceName, className, beanDefinition, generateBeanName(className)); + } + + RepositoryFragmentConfiguration(String interfaceName, AbstractBeanDefinition beanDefinition, String beanName) { + this(interfaceName, ConfigurationUtils.getRequiredBeanClassName(beanDefinition), Optional.of(beanDefinition), + beanName); + } + + private RepositoryFragmentConfiguration(String interfaceName, String className, + Optional beanDefinition, String beanName) { + + Assert.hasText(interfaceName, "Interface name must not be null or empty!"); + Assert.notNull(beanDefinition, "Bean definition must not be null!"); + Assert.notNull(beanName, "Bean name must not be null!"); + this.interfaceName = interfaceName; this.className = className; this.beanDefinition = beanDefinition; + this.beanName = beanName; + } + + private String generateBeanName() { + return generateBeanName(getClassName()); + } + + private static String generateBeanName(String className) { + return Introspector.decapitalize(ClassUtils.getShortName(className)); } /** * @return name of the implementation bean. */ public String getImplementationBeanName() { - return Introspector.decapitalize(ClassUtils.getShortName(getClassName())); + return this.beanName; } /** diff --git a/src/test/java/org/springframework/data/repository/config/RepositoryComponentProviderUnitTests.java b/src/test/java/org/springframework/data/repository/config/RepositoryComponentProviderUnitTests.java index a2a1f73e8e..bfbc6ea5e2 100755 --- a/src/test/java/org/springframework/data/repository/config/RepositoryComponentProviderUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/RepositoryComponentProviderUnitTests.java @@ -71,7 +71,7 @@ void shouldConsiderNestedRepositoryInterfacesIfEnabled() { provider.setConsiderNestedRepositoryInterfaces(true); var components = provider.findCandidateComponents("org.springframework.data.repository.config"); - var nestedRepositoryClassName = "org.springframework.data.repository.config.RepositoryComponentProviderUnitTests$MyNestedRepository"; + var nestedRepositoryClassName = "org.springframework.data.repository.config.RepositoryComponentProviderUnitTests$MyNestedRepositoryDefinition"; assertThat(components.size()).isGreaterThanOrEqualTo(1); assertThat(components).extracting(BeanDefinition::getBeanClassName).contains(nestedRepositoryClassName); @@ -91,5 +91,5 @@ void exposesBeanDefinitionRegistry() { assertThat(provider.getRegistry()).isEqualTo(registry); } - interface MyNestedRepository extends Repository {} + interface MyNestedRepositoryDefinition extends Repository {} } diff --git a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java index 6763d18875..3b53c4662d 100644 --- a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java @@ -39,6 +39,9 @@ import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.StandardAnnotationMetadata; import org.springframework.data.repository.config.RepositoryConfigurationDelegate.LazyRepositoryInjectionPointResolver; +import org.springframework.data.repository.config.annotated.MyAnnotatedRepository; +import org.springframework.data.repository.config.annotated.MyAnnotatedRepositoryImpl; +import org.springframework.data.repository.config.annotated.MyFragmentImpl; import org.springframework.data.repository.config.excluded.MyOtherRepositoryImpl; import org.springframework.data.repository.config.stereotype.MyStereotypeRepository; import org.springframework.data.repository.core.support.DummyRepositoryFactoryBean; @@ -158,7 +161,8 @@ void considersAnnotatedBeanNamesFromRepository() { GenericApplicationContext context = new GenericApplicationContext(); RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource( - AnnotationMetadata.introspect(AnnotatedBeanNamesConfig.class), EnableRepositories.class, context, environment, + AnnotationMetadata.introspect(AnnotatedDerivedBeanNamesConfig.class), EnableRepositories.class, context, + environment, context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()); RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment); @@ -169,6 +173,49 @@ void considersAnnotatedBeanNamesFromRepository() { assertThat(context.getBeanFactory().getBeanDefinition("fooRepositoryImpl")).isNotNull(); } + @Test // GH-2487 + void considersAnnotatedBeanNamesFromAtComponent() { + + StandardEnvironment environment = new StandardEnvironment(); + GenericApplicationContext context = new GenericApplicationContext(); + + RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource( + AnnotationMetadata.introspect(AnnotatedBeanNamesConfig.class), EnableRepositories.class, context, environment, + context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()); + + RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment); + + delegate.registerRepositoriesIn(context, extension); + + assertThat(context.getBeanFactory().getBeanDefinition("myAnnotatedRepository")).isNotNull(); + assertThat(context.getBeanFactory().getBeanDefinition("anotherBeanName")).isNotNull(); + assertThat(context.getBeanFactory().getBeanDefinition("fragment")).isNotNull(); + assertThat(context.getBeanFactory().getBeanDefinition("fragmentFragment")).isNotNull(); + } + + @Test // GH-2487 + void skipsRegistrationOnAlreadyRegisteredBeansUsingAtComponentNames() { + + StandardEnvironment environment = new StandardEnvironment(); + GenericApplicationContext context = new GenericApplicationContext(); + context.setAllowBeanDefinitionOverriding(false); + context.registerBean("fragment", MyFragmentImpl.class); + context.registerBean("anotherBeanName", MyAnnotatedRepositoryImpl.class); + + RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource( + AnnotationMetadata.introspect(AnnotatedBeanNamesConfig.class), EnableRepositories.class, context, environment, + context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()); + + RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment); + + delegate.registerRepositoriesIn(context, extension); + + assertThat(context.getBeanFactory().getBeanDefinition("myAnnotatedRepository")).isNotNull(); + assertThat(context.getBeanFactory().getBeanDefinition("anotherBeanName")).isNotNull(); + assertThat(context.getBeanFactory().getBeanDefinition("fragment")).isNotNull(); + assertThat(context.getBeanFactory().getBeanDefinition("fragmentFragment")).isNotNull(); + } + private static ListableBeanFactory assertLazyRepositoryBeanSetup(Class configClass) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configClass); @@ -209,6 +256,9 @@ static class DefaultBeanNamesConfig {} @EnableRepositories(basePackageClasses = MyStereotypeRepository.class, includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MyStereotypeRepository.class)) + static class AnnotatedDerivedBeanNamesConfig {} + + @EnableRepositories(basePackageClasses = MyAnnotatedRepository.class) static class AnnotatedBeanNamesConfig {} static class DummyConfigurationExtension extends RepositoryConfigurationExtensionSupport { diff --git a/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepository.java b/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepository.java new file mode 100644 index 0000000000..e4fb37191d --- /dev/null +++ b/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepository.java @@ -0,0 +1,24 @@ +/* + * Copyright 2021 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.config.annotated; + +import org.springframework.data.mapping.Person; +import org.springframework.data.repository.CrudRepository; + +/** + * @author Mark Paluch + */ +public interface MyAnnotatedRepository extends CrudRepository, MyFragment {} diff --git a/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepositoryImpl.java b/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepositoryImpl.java new file mode 100644 index 0000000000..5f491467ee --- /dev/null +++ b/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepositoryImpl.java @@ -0,0 +1,24 @@ +/* + * Copyright 2021 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.config.annotated; + +import org.springframework.stereotype.Component; + +/** + * @author Mark Paluch + */ +@Component("anotherBeanName") +public class MyAnnotatedRepositoryImpl {} diff --git a/src/test/java/org/springframework/data/repository/config/annotated/MyFragment.java b/src/test/java/org/springframework/data/repository/config/annotated/MyFragment.java new file mode 100644 index 0000000000..dde58166f9 --- /dev/null +++ b/src/test/java/org/springframework/data/repository/config/annotated/MyFragment.java @@ -0,0 +1,21 @@ +/* + * Copyright 2021 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.config.annotated; + +/** + * @author Mark Paluch + */ +interface MyFragment {} diff --git a/src/test/java/org/springframework/data/repository/config/annotated/MyFragmentImpl.java b/src/test/java/org/springframework/data/repository/config/annotated/MyFragmentImpl.java new file mode 100644 index 0000000000..d4d87da08a --- /dev/null +++ b/src/test/java/org/springframework/data/repository/config/annotated/MyFragmentImpl.java @@ -0,0 +1,24 @@ +/* + * Copyright 2021 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.config.annotated; + +import org.springframework.stereotype.Component; + +/** + * @author Mark Paluch + */ +@Component("fragment") +public class MyFragmentImpl implements MyFragment {} From 8cb86e9306585852b373d4839aceb69170b66232 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 11 Oct 2022 15:21:40 +0200 Subject: [PATCH 4/4] Rebase. --- .../DefaultRepositoryConfiguration.java | 3 +- .../RepositoryBeanDefinitionBuilder.java | 3 +- .../config/RepositoryConfiguration.java | 4 +- .../RepositoryConfigurationAdapter.java | 10 ++++ .../RepositoryFragmentConfiguration.java | 7 +-- ...sitoryImplementationDetectorUnitTests.java | 11 +--- ...mentationLookupConfigurationUnitTests.java | 7 +-- ...ositoryConfigurationDelegateUnitTests.java | 60 ++++++------------- .../annotated/MyAnnotatedRepository.java | 2 +- .../annotated/MyAnnotatedRepositoryImpl.java | 2 +- .../config/annotated/MyFragment.java | 2 +- .../config/annotated/MyFragmentImpl.java | 2 +- .../stereotype/MyStereotypeRepository.java | 2 +- .../MyStereotypeRepositoryImpl.java | 2 +- 14 files changed, 46 insertions(+), 71 deletions(-) diff --git a/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java b/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java index 7e66b3f3c3..bf13ab9d71 100644 --- a/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/DefaultRepositoryConfiguration.java @@ -93,8 +93,7 @@ public String getImplementationClassName() { } public String getImplementationBeanName() { - return beanName.get() - + configurationSource.getRepositoryImplementationPostfix().orElse("Impl"); + return beanName.get() + configurationSource.getRepositoryImplementationPostfix().orElse("Impl"); } @Nullable diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java index f316945606..4af5ae4add 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionBuilder.java @@ -30,7 +30,6 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; - import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; @@ -148,7 +147,7 @@ RepositoryConfigurationAdapter buildMetadata(RepositoryConfiguration confi List repositoryFragmentConfigurationStream = fragmentMetadata .getFragmentInterfaces(configuration.getRepositoryInterface()) // - .map(it -> detectRepositoryFragmentConfiguration(it, config)) // + .map(it -> detectRepositoryFragmentConfiguration(it, config, configuration)) // .flatMap(Optionals::toStream).toList(); if (repositoryFragmentConfigurationStream.isEmpty()) { diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java index 6ba17d5e1f..35d81f0bde 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfiguration.java @@ -88,7 +88,7 @@ public interface RepositoryConfiguration beanDefinition) { - this(interfaceName, className, beanDefinition, generateBeanName(className)); - } - RepositoryFragmentConfiguration(String interfaceName, AbstractBeanDefinition beanDefinition, String beanName) { this(interfaceName, ConfigurationUtils.getRequiredBeanClassName(beanDefinition), Optional.of(beanDefinition), beanName); diff --git a/src/test/java/org/springframework/data/repository/config/CustomRepositoryImplementationDetectorUnitTests.java b/src/test/java/org/springframework/data/repository/config/CustomRepositoryImplementationDetectorUnitTests.java index e1498d71c7..6e65c5ce68 100644 --- a/src/test/java/org/springframework/data/repository/config/CustomRepositoryImplementationDetectorUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/CustomRepositoryImplementationDetectorUnitTests.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.*; import java.beans.Introspector; -import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -67,8 +66,7 @@ void returnsNullWhenNoImplementationFound() { RepositoryConfiguration mock = mock(RepositoryConfiguration.class); when(mock.getImplementationBeanName()).thenReturn("NoImplementationRepositoryImpl"); - var lookup = configuration - .forRepositoryConfiguration(configFor(NoImplementationRepository.class)); + var lookup = configuration.forRepositoryConfiguration(configFor(NoImplementationRepository.class)); var beanDefinition = detector.detectCustomImplementation(lookup); @@ -78,8 +76,7 @@ void returnsNullWhenNoImplementationFound() { @Test // DATACMNS-764, DATACMNS-1371 void returnsBeanDefinitionWhenOneImplementationIsFound() { - var lookup = configuration - .forRepositoryConfiguration(configFor(SingleSampleRepository.class)); + var lookup = configuration.forRepositoryConfiguration(configFor(SingleSampleRepository.class)); var beanDefinition = detector.detectCustomImplementation(lookup); @@ -98,9 +95,7 @@ void returnsBeanDefinitionMatchingByNameWhenMultipleImplementationAreFound() { return className.contains("$First$") ? "canonicalSampleRepositoryTestImpl" : "otherBeanName"; }); - - var lookup = configuration - .forRepositoryConfiguration(configFor(CanonicalSampleRepository.class)); + var lookup = configuration.forRepositoryConfiguration(configFor(CanonicalSampleRepository.class)); assertThat(detector.detectCustomImplementation(lookup)) // .hasValueSatisfying( 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 443a68a602..c2eee8dc0e 100644 --- a/src/test/java/org/springframework/data/repository/config/DefaultImplementationLookupConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/DefaultImplementationLookupConfigurationUnitTests.java @@ -53,21 +53,20 @@ void shouldConsiderBeanNameDecapitalization() { @Test // DATACMNS-1754 void shouldUseSimpleClassNameWhenDefiningImplementationNames() { - ImplementationLookupConfiguration lookupConfiguration = idcMock - .forFragment("com.acme.Repositories$NestedRepository"); + var lookupConfiguration = idcMock.forFragment("com.acme.Repositories$NestedRepository"); assertThat(lookupConfiguration.getImplementationBeanName()).isEqualTo("repositories.NestedRepositoryImpl"); assertThat(lookupConfiguration.getImplementationClassName()).isEqualTo("NestedRepositoryImpl"); } private static String getImplementationBeanName(ImplementationDetectionConfiguration idcMock, String interfaceName) { - RepositoryConfigurationSource source = mock(RepositoryConfigurationSource.class); + var source = mock(RepositoryConfigurationSource.class); when(source.generateBeanName(any())).thenReturn(Introspector.decapitalize(ClassUtils.getShortName(interfaceName))); RepositoryConfiguration repoConfig = new DefaultRepositoryConfiguration<>(source, BeanDefinitionBuilder.rootBeanDefinition(interfaceName).getBeanDefinition(), null); - ImplementationLookupConfiguration configuration = idcMock.forRepositoryConfiguration(repoConfig); + var configuration = idcMock.forRepositoryConfiguration(repoConfig); return configuration.getImplementationBeanName(); } } diff --git a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java index 3b53c4662d..2c5da8ef5b 100644 --- a/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java @@ -23,11 +23,10 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; + import org.springframework.aop.framework.Advised; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.context.annotation.AnnotationBeanNameGenerator; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; @@ -78,8 +77,7 @@ void registersRepositoryBeanNameAsAttribute() { var beanDefinition = definition.getBeanDefinition(); - assertThat(beanDefinition.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE).toString()) - .endsWith("Repository"); + assertThat(beanDefinition.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE).toString()).endsWith("Repository"); } } @@ -97,25 +95,6 @@ void registersDeferredRepositoryInitializationListener() { } - private static ListableBeanFactory assertLazyRepositoryBeanSetup(Class configClass) { - - var environment = new StandardEnvironment(); - var context = new AnnotationConfigApplicationContext(configClass); - - assertThat(context.getDefaultListableBeanFactory().getAutowireCandidateResolver()) - .isInstanceOf(LazyRepositoryInjectionPointResolver.class); - - var client = context.getBean(AddressRepositoryClient.class); - var repository = client.getRepository(); - - assertThat(Advised.class.isInstance(repository)).isTrue(); - - var targetSource = Advised.class.cast(repository).getTargetSource(); - assertThat(targetSource).isNotNull(); - - return context.getDefaultListableBeanFactory(); - } - @Test // DATACMNS-1832 void writesRepositoryScanningMetrics() { @@ -139,14 +118,14 @@ void writesRepositoryScanningMetrics() { @Test // GH-2487 void considersDefaultBeanNames() { - StandardEnvironment environment = new StandardEnvironment(); - GenericApplicationContext context = new GenericApplicationContext(); + var environment = new StandardEnvironment(); + var context = new GenericApplicationContext(); RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource( AnnotationMetadata.introspect(DefaultBeanNamesConfig.class), EnableRepositories.class, context, environment, context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()); - RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment); + var delegate = new RepositoryConfigurationDelegate(configSource, context, environment); delegate.registerRepositoriesIn(context, extension); @@ -157,15 +136,14 @@ void considersDefaultBeanNames() { @Test // GH-2487 void considersAnnotatedBeanNamesFromRepository() { - StandardEnvironment environment = new StandardEnvironment(); - GenericApplicationContext context = new GenericApplicationContext(); + var environment = new StandardEnvironment(); + var context = new GenericApplicationContext(); RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource( AnnotationMetadata.introspect(AnnotatedDerivedBeanNamesConfig.class), EnableRepositories.class, context, - environment, - context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()); + environment, context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()); - RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment); + var delegate = new RepositoryConfigurationDelegate(configSource, context, environment); delegate.registerRepositoriesIn(context, extension); @@ -176,14 +154,14 @@ void considersAnnotatedBeanNamesFromRepository() { @Test // GH-2487 void considersAnnotatedBeanNamesFromAtComponent() { - StandardEnvironment environment = new StandardEnvironment(); - GenericApplicationContext context = new GenericApplicationContext(); + var environment = new StandardEnvironment(); + var context = new GenericApplicationContext(); RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource( AnnotationMetadata.introspect(AnnotatedBeanNamesConfig.class), EnableRepositories.class, context, environment, context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()); - RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment); + var delegate = new RepositoryConfigurationDelegate(configSource, context, environment); delegate.registerRepositoriesIn(context, extension); @@ -196,8 +174,8 @@ void considersAnnotatedBeanNamesFromAtComponent() { @Test // GH-2487 void skipsRegistrationOnAlreadyRegisteredBeansUsingAtComponentNames() { - StandardEnvironment environment = new StandardEnvironment(); - GenericApplicationContext context = new GenericApplicationContext(); + var environment = new StandardEnvironment(); + var context = new GenericApplicationContext(); context.setAllowBeanDefinitionOverriding(false); context.registerBean("fragment", MyFragmentImpl.class); context.registerBean("anotherBeanName", MyAnnotatedRepositoryImpl.class); @@ -206,7 +184,7 @@ void skipsRegistrationOnAlreadyRegisteredBeansUsingAtComponentNames() { AnnotationMetadata.introspect(AnnotatedBeanNamesConfig.class), EnableRepositories.class, context, environment, context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()); - RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment); + var delegate = new RepositoryConfigurationDelegate(configSource, context, environment); delegate.registerRepositoriesIn(context, extension); @@ -218,17 +196,17 @@ void skipsRegistrationOnAlreadyRegisteredBeansUsingAtComponentNames() { private static ListableBeanFactory assertLazyRepositoryBeanSetup(Class configClass) { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configClass); + var context = new AnnotationConfigApplicationContext(configClass); assertThat(context.getDefaultListableBeanFactory().getAutowireCandidateResolver()) .isInstanceOf(LazyRepositoryInjectionPointResolver.class); - AddressRepositoryClient client = context.getBean(AddressRepositoryClient.class); - AddressRepository repository = client.getRepository(); + var client = context.getBean(AddressRepositoryClient.class); + var repository = client.getRepository(); assertThat(Advised.class.isInstance(repository)).isTrue(); - TargetSource targetSource = Advised.class.cast(repository).getTargetSource(); + var targetSource = Advised.class.cast(repository).getTargetSource(); assertThat(targetSource).isNotNull(); return context.getDefaultListableBeanFactory(); diff --git a/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepository.java b/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepository.java index e4fb37191d..973743628c 100644 --- a/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepository.java +++ b/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 the original author or authors. + * Copyright 2022 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. diff --git a/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepositoryImpl.java b/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepositoryImpl.java index 5f491467ee..d424ecc3f8 100644 --- a/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepositoryImpl.java +++ b/src/test/java/org/springframework/data/repository/config/annotated/MyAnnotatedRepositoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 the original author or authors. + * Copyright 2022 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. diff --git a/src/test/java/org/springframework/data/repository/config/annotated/MyFragment.java b/src/test/java/org/springframework/data/repository/config/annotated/MyFragment.java index dde58166f9..87be1eccc3 100644 --- a/src/test/java/org/springframework/data/repository/config/annotated/MyFragment.java +++ b/src/test/java/org/springframework/data/repository/config/annotated/MyFragment.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 the original author or authors. + * Copyright 2022 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. diff --git a/src/test/java/org/springframework/data/repository/config/annotated/MyFragmentImpl.java b/src/test/java/org/springframework/data/repository/config/annotated/MyFragmentImpl.java index d4d87da08a..2493dd9e33 100644 --- a/src/test/java/org/springframework/data/repository/config/annotated/MyFragmentImpl.java +++ b/src/test/java/org/springframework/data/repository/config/annotated/MyFragmentImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 the original author or authors. + * Copyright 2022 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. diff --git a/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepository.java b/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepository.java index 28dca49820..d5fb567711 100644 --- a/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepository.java +++ b/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 the original author or authors. + * Copyright 2022 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. diff --git a/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepositoryImpl.java b/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepositoryImpl.java index 7a3adae1bd..9e5321fdbf 100644 --- a/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepositoryImpl.java +++ b/src/test/java/org/springframework/data/repository/config/stereotype/MyStereotypeRepositoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 the original author or authors. + * Copyright 2022 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.