|
15 | 15 | */
|
16 | 16 | package org.springframework.data.repository.config;
|
17 | 17 |
|
| 18 | +import lombok.Value; |
| 19 | + |
18 | 20 | import java.io.IOException;
|
19 | 21 | import java.util.Arrays;
|
| 22 | +import java.util.Collections; |
20 | 23 | import java.util.List;
|
21 | 24 | import java.util.Optional;
|
| 25 | +import java.util.function.Function; |
22 | 26 | import java.util.stream.Collectors;
|
23 | 27 | import java.util.stream.Stream;
|
24 | 28 |
|
25 | 29 | import org.slf4j.Logger;
|
26 | 30 | import org.slf4j.LoggerFactory;
|
27 | 31 | import org.springframework.beans.factory.BeanDefinitionStoreException;
|
| 32 | +import org.springframework.beans.factory.config.BeanDefinition; |
28 | 33 | import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
29 | 34 | import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
30 | 35 | import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
|
42 | 47 | import org.springframework.data.repository.core.support.RepositoryFragment;
|
43 | 48 | import org.springframework.data.repository.core.support.RepositoryFragmentsFactoryBean;
|
44 | 49 | import org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider;
|
| 50 | +import org.springframework.data.util.Optionals; |
45 | 51 | import org.springframework.data.util.StreamUtils;
|
46 | 52 | import org.springframework.util.Assert;
|
47 | 53 | import org.springframework.util.ClassUtils;
|
@@ -127,7 +133,6 @@ public BeanDefinitionBuilder build(RepositoryConfiguration<?> configuration) {
|
127 | 133 | .rootBeanDefinition(RepositoryFragmentsFactoryBean.class);
|
128 | 134 |
|
129 | 135 | List<String> fragmentBeanNames = registerRepositoryFragmentsImplementation(configuration) //
|
130 |
| - .stream() // |
131 | 136 | .map(RepositoryFragmentConfiguration::getFragmentBeanName) //
|
132 | 137 | .collect(Collectors.toList());
|
133 | 138 |
|
@@ -171,41 +176,29 @@ private Optional<String> registerCustomImplementation(RepositoryConfiguration<?>
|
171 | 176 | });
|
172 | 177 | }
|
173 | 178 |
|
174 |
| - private List<RepositoryFragmentConfiguration> registerRepositoryFragmentsImplementation( |
| 179 | + private Stream<RepositoryFragmentConfiguration> registerRepositoryFragmentsImplementation( |
175 | 180 | RepositoryConfiguration<?> configuration) {
|
176 | 181 |
|
177 | 182 | ClassMetadata classMetadata = getClassMetadata(configuration.getRepositoryInterface());
|
178 | 183 |
|
179 | 184 | return Arrays.stream(classMetadata.getInterfaceNames()) //
|
180 |
| - .filter(this::isFragmentInterfaceCandidate) // |
181 |
| - .map(it -> detectRepositoryFragmentConfiguration(configuration, it)) // |
182 |
| - .filter(Optional::isPresent) // |
183 |
| - .map(Optional::get) // |
| 185 | + .filter(it -> FragmentMetadata.isCandidate(it, metadataReaderFactory)) // |
| 186 | + .map(it -> FragmentMetadata.of(it, configuration)) // |
| 187 | + .map(it -> detectRepositoryFragmentConfiguration(it)) // |
| 188 | + .flatMap(it -> Optionals.toStream(it)) // |
184 | 189 | .peek(it -> potentiallyRegisterFragmentImplementation(configuration, it)) //
|
185 |
| - .peek(it -> potentiallyRegisterRepositoryFragment(configuration, it)) // |
186 |
| - .collect(Collectors.toList()); |
187 |
| - } |
188 |
| - |
189 |
| - private boolean isFragmentInterfaceCandidate(String interfaceName) { |
190 |
| - |
191 |
| - AnnotationMetadata metadata = getAnnotationMetadata(interfaceName); |
192 |
| - |
193 |
| - return !metadata.hasAnnotation(NoRepositoryBean.class.getName()); |
| 190 | + .peek(it -> potentiallyRegisterRepositoryFragment(configuration, it)); |
194 | 191 | }
|
195 | 192 |
|
196 | 193 | private Optional<RepositoryFragmentConfiguration> detectRepositoryFragmentConfiguration(
|
197 |
| - RepositoryConfiguration<?> configuration, String fragmentInterfaceName) { |
| 194 | + FragmentMetadata configuration) { |
198 | 195 |
|
199 |
| - List<TypeFilter> exclusions = getExclusions(configuration); |
200 |
| - |
201 |
| - String className = ClassUtils.getShortName(fragmentInterfaceName) |
202 |
| - .concat(configuration.getConfigurationSource().getRepositoryImplementationPostfix().orElse("Impl")); |
| 196 | + String className = configuration.getFragmentImplementationClassName(); |
203 | 197 |
|
204 | 198 | Optional<AbstractBeanDefinition> beanDefinition = implementationDetector.detectCustomImplementation(className, null,
|
205 |
| - configuration.getImplementationBasePackages(fragmentInterfaceName), exclusions, |
206 |
| - bd -> configuration.getConfigurationSource().generateBeanName(bd)); |
| 199 | + configuration.getBasePackages(), configuration.getExclusions(), configuration.getBeanNameGenerator()); |
207 | 200 |
|
208 |
| - return beanDefinition.map(bd -> new RepositoryFragmentConfiguration(fragmentInterfaceName, bd)); |
| 201 | + return beanDefinition.map(bd -> new RepositoryFragmentConfiguration(configuration.getFragmentInterfaceName(), bd)); |
209 | 202 | }
|
210 | 203 |
|
211 | 204 | private void potentiallyRegisterFragmentImplementation(RepositoryConfiguration<?> repositoryConfiguration,
|
@@ -263,19 +256,84 @@ private ClassMetadata getClassMetadata(String className) {
|
263 | 256 | }
|
264 | 257 | }
|
265 | 258 |
|
266 |
| - private AnnotationMetadata getAnnotationMetadata(String className) { |
| 259 | + @Value(staticConstructor = "of") |
| 260 | + static class FragmentMetadata { |
267 | 261 |
|
268 |
| - try { |
269 |
| - return metadataReaderFactory.getMetadataReader(className).getAnnotationMetadata(); |
270 |
| - } catch (IOException e) { |
271 |
| - throw new BeanDefinitionStoreException(String.format("Cannot parse %s metadata.", className), e); |
| 262 | + String fragmentInterfaceName; |
| 263 | + RepositoryConfiguration<?> configuration; |
| 264 | + |
| 265 | + /** |
| 266 | + * Returns whether the given interface is a fragment candidate. |
| 267 | + * |
| 268 | + * @param interfaceName must not be {@literal null} or empty. |
| 269 | + * @param factory must not be {@literal null}. |
| 270 | + * @return |
| 271 | + */ |
| 272 | + public static boolean isCandidate(String interfaceName, MetadataReaderFactory factory) { |
| 273 | + |
| 274 | + Assert.hasText(interfaceName, "Interface name must not be null or empty!"); |
| 275 | + Assert.notNull(factory, "MetadataReaderFactory must not be null!"); |
| 276 | + |
| 277 | + AnnotationMetadata metadata = getAnnotationMetadata(interfaceName, factory); |
| 278 | + |
| 279 | + return !metadata.hasAnnotation(NoRepositoryBean.class.getName()); |
272 | 280 | }
|
273 |
| - } |
274 | 281 |
|
275 |
| - private static List<TypeFilter> getExclusions(RepositoryConfiguration<?> configuration) { |
| 282 | + /** |
| 283 | + * Returns the exclusions to be used when scanning for fragment implementations. |
| 284 | + * |
| 285 | + * @return |
| 286 | + */ |
| 287 | + public List<TypeFilter> getExclusions() { |
276 | 288 |
|
277 |
| - return Stream |
278 |
| - .concat(configuration.getExcludeFilters().stream(), Stream.of(new AnnotationTypeFilter(NoRepositoryBean.class)))// |
279 |
| - .collect(StreamUtils.toUnmodifiableList()); |
| 289 | + Stream<TypeFilter> configurationExcludes = configuration.getExcludeFilters().stream(); |
| 290 | + Stream<AnnotationTypeFilter> noRepositoryBeans = Stream.of(new AnnotationTypeFilter(NoRepositoryBean.class)); |
| 291 | + |
| 292 | + return Stream.concat(configurationExcludes, noRepositoryBeans).collect(StreamUtils.toUnmodifiableList()); |
| 293 | + } |
| 294 | + |
| 295 | + /** |
| 296 | + * Returns the name of the implementation class to be detected for the fragment interface. |
| 297 | + * |
| 298 | + * @return |
| 299 | + */ |
| 300 | + public String getFragmentImplementationClassName() { |
| 301 | + |
| 302 | + RepositoryConfigurationSource configurationSource = configuration.getConfigurationSource(); |
| 303 | + String postfix = configurationSource.getRepositoryImplementationPostfix().orElse("Impl"); |
| 304 | + |
| 305 | + return ClassUtils.getShortName(fragmentInterfaceName).concat(postfix); |
| 306 | + } |
| 307 | + |
| 308 | + /** |
| 309 | + * Returns the base packages to be scanned to find implementations of the current fragment interface. |
| 310 | + * |
| 311 | + * @return |
| 312 | + */ |
| 313 | + public Iterable<String> getBasePackages() { |
| 314 | + |
| 315 | + return configuration.getConfigurationSource().shouldLimitRepositoryImplementationBasePackages() ? // |
| 316 | + Collections.singleton(ClassUtils.getPackageName(fragmentInterfaceName)) : // |
| 317 | + configuration.getImplementationBasePackages(); |
| 318 | + } |
| 319 | + |
| 320 | + /** |
| 321 | + * Returns the bean name generating function to be used for the fragment. |
| 322 | + * |
| 323 | + * @return |
| 324 | + */ |
| 325 | + public Function<BeanDefinition, String> getBeanNameGenerator() { |
| 326 | + return definition -> configuration.getConfigurationSource().generateBeanName(definition); |
| 327 | + } |
| 328 | + |
| 329 | + private static AnnotationMetadata getAnnotationMetadata(String className, |
| 330 | + MetadataReaderFactory metadataReaderFactory) { |
| 331 | + |
| 332 | + try { |
| 333 | + return metadataReaderFactory.getMetadataReader(className).getAnnotationMetadata(); |
| 334 | + } catch (IOException e) { |
| 335 | + throw new BeanDefinitionStoreException(String.format("Cannot parse %s metadata.", className), e); |
| 336 | + } |
| 337 | + } |
280 | 338 | }
|
281 | 339 | }
|
0 commit comments