From c7327286d4aef85caecb72b8ce00c7c049845e30 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Mon, 25 Nov 2024 19:17:26 +0800 Subject: [PATCH] Register indirect fragment introduced by super interfaces Fix GH-3212 --- .../repository/config/FragmentMetadata.java | 21 +++++++++++++-- ...anDefinitionRegistrarSupportUnitTests.java | 16 +++++++++++ .../ExcludedRepository.java | 27 +++++++++++++++++++ .../indirectspifragment/PersonRepository.java | 21 +++++++++++++++ 4 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/springframework/data/repository/config/indirectspifragment/ExcludedRepository.java create mode 100644 src/test/java/org/springframework/data/repository/config/indirectspifragment/PersonRepository.java diff --git a/src/main/java/org/springframework/data/repository/config/FragmentMetadata.java b/src/main/java/org/springframework/data/repository/config/FragmentMetadata.java index c8ca604e0b..a1982adda4 100644 --- a/src/main/java/org/springframework/data/repository/config/FragmentMetadata.java +++ b/src/main/java/org/springframework/data/repository/config/FragmentMetadata.java @@ -16,7 +16,8 @@ package org.springframework.data.repository.config; import java.io.IOException; -import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; import java.util.stream.Stream; import org.springframework.beans.factory.BeanDefinitionStoreException; @@ -32,6 +33,7 @@ * @author Mark Paluch * @author Oliver Gierke * @author Johannes Englmeier + * @author Yanming Zhou * @since 2.1 */ public class FragmentMetadata { @@ -52,10 +54,25 @@ public Stream getFragmentInterfaces(String interfaceName) { Assert.hasText(interfaceName, "Interface name must not be null or empty"); - return Arrays.stream(getClassMetadata(interfaceName).getInterfaceNames()) // + return getAllSuperInterfaces(interfaceName).stream() // .filter(this::isCandidate); } + /** + * Returns all super interfaces of the given interface. + * + * @param interfaceName must not be {@literal null} or empty. + * @return + */ + private Set getAllSuperInterfaces(String interfaceName) { + Set interfaces = new LinkedHashSet<>(); + for (String ifc : getClassMetadata(interfaceName).getInterfaceNames()) { + interfaces.add(ifc); + interfaces.addAll(getAllSuperInterfaces(ifc)); + } + return interfaces; + } + /** * Returns whether the given interface is a fragment candidate. * 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 995d8a4ab7..981da6f2b1 100755 --- a/src/test/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupportUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupportUnitTests.java @@ -46,6 +46,7 @@ * * @author Oliver Gierke * @author Mark Paluch + * @author Yanming Zhou */ @ExtendWith(MockitoExtension.class) class RepositoryBeanDefinitionRegistrarSupportUnitTests { @@ -124,6 +125,18 @@ void shouldLimitImplementationBasePackages() { assertBeanDefinitionRegisteredFor("spiContribution"); } + + @Test // GH-3212 + void shouldRegisterIndirectSpiFragment() { + + AnnotationMetadata metadata = new StandardAnnotationMetadata(ExcludedWithSpiFragement.class, true); + + registrar.registerBeanDefinitions(metadata, registry); + + assertBeanDefinitionRegisteredFor("personRepository"); + assertBeanDefinitionRegisteredFor("spiFragmentImplFragment"); + } + @Test // DATACMNS-360 void registeredProfileRepositoriesIfProfileActivated() { @@ -203,6 +216,9 @@ static class FragmentExclusionConfiguration {} @EnableRepositories(basePackageClasses = FragmentImpl.class) static class LimitsImplementationBasePackages {} + @EnableRepositories(basePackageClasses = org.springframework.data.repository.config.indirectspifragment.PersonRepository.class) + static class ExcludedWithSpiFragement {} + @EnableRepositories(basePackageClasses = MyNestedRepository.class, considerNestedRepositories = true, excludeFilters = { @Filter(type = FilterType.ASSIGNABLE_TYPE, diff --git a/src/test/java/org/springframework/data/repository/config/indirectspifragment/ExcludedRepository.java b/src/test/java/org/springframework/data/repository/config/indirectspifragment/ExcludedRepository.java new file mode 100644 index 0000000000..dbec983556 --- /dev/null +++ b/src/test/java/org/springframework/data/repository/config/indirectspifragment/ExcludedRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017-2024 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.indirectspifragment; + +import org.springframework.data.mapping.Person; +import org.springframework.data.repository.NoRepositoryBean; +import org.springframework.data.repository.Repository; +import org.springframework.data.repository.config.spifragment.SpiFragment; + +/** + * @author Yanming Zhou + */ +@NoRepositoryBean +public interface ExcludedRepository extends Repository, SpiFragment {} diff --git a/src/test/java/org/springframework/data/repository/config/indirectspifragment/PersonRepository.java b/src/test/java/org/springframework/data/repository/config/indirectspifragment/PersonRepository.java new file mode 100644 index 0000000000..3c66853b28 --- /dev/null +++ b/src/test/java/org/springframework/data/repository/config/indirectspifragment/PersonRepository.java @@ -0,0 +1,21 @@ +/* + * Copyright 2017-2024 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.indirectspifragment; + +/** + * @author Yanming Zhou + */ +public interface PersonRepository extends ExcludedRepository {}