Skip to content

Commit

Permalink
DATACMNS-1098 - RepositoryComponentScanner now exposes BeanDefinition…
Browse files Browse the repository at this point in the history
…Registry.

We now override ClassPathScanningCandidateComponentProvider's getRegistry() to make sure custom conditions on repository candidates can use the currently available BeanDefinitionRegistry in their implementations. To achieve that we forward the BeanDefinitionRegistry at hand through the configuration infrastructure (both XML and annotation side of things).
  • Loading branch information
odrotbohm committed Jun 26, 2017
1 parent 6cd5f7c commit fce40e9
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.regex.Pattern;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
Expand Down Expand Up @@ -76,9 +77,9 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
* @param environment
*/
public AnnotationRepositoryConfigurationSource(AnnotationMetadata metadata, Class<? extends Annotation> annotation,
ResourceLoader resourceLoader, Environment environment) {
ResourceLoader resourceLoader, Environment environment, BeanDefinitionRegistry registry) {

super(environment, resourceLoader.getClassLoader());
super(environment, resourceLoader.getClassLoader(), registry);

Assert.notNull(metadata, "Metadata must not be null!");
Assert.notNull(annotation, "Annotation must not be null!");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2017 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.
Expand Down Expand Up @@ -32,8 +32,8 @@
*
* @author Oliver Gierke
*/
public abstract class RepositoryBeanDefinitionRegistrarSupport implements ImportBeanDefinitionRegistrar,
ResourceLoaderAware, EnvironmentAware {
public abstract class RepositoryBeanDefinitionRegistrarSupport
implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {

private ResourceLoader resourceLoader;
private Environment environment;
Expand Down Expand Up @@ -72,7 +72,7 @@ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanD
}

AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(
annotationMetadata, getAnnotation(), resourceLoader, environment);
annotationMetadata, getAnnotation(), resourceLoader, environment, registry);

RepositoryConfigurationExtension extension = getExtension();
RepositoryConfigurationUtils.exposeRegistration(extension, registry, configurationSource);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2017 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.
Expand All @@ -22,6 +22,7 @@

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.classreading.MetadataReader;
Expand All @@ -47,6 +48,7 @@ class RepositoryComponentProvider extends ClassPathScanningCandidateComponentPro
private static final String METHOD_NOT_PUBLIC = "AnnotationConfigUtils.processCommonDefinitionAnnotations(…) is not public! Make sure you're using Spring 3.2.5 or better. The class was loaded from %s.";

private boolean considerNestedRepositoryInterfaces;
private BeanDefinitionRegistry registry;

/**
* Creates a new {@link RepositoryComponentProvider} using the given {@link TypeFilter} to include components to be
Expand All @@ -55,13 +57,16 @@ class RepositoryComponentProvider extends ClassPathScanningCandidateComponentPro
* @param includeFilters the {@link TypeFilter}s to select repository interfaces to consider, must not be
* {@literal null}.
*/
public RepositoryComponentProvider(Iterable<? extends TypeFilter> includeFilters) {
public RepositoryComponentProvider(Iterable<? extends TypeFilter> includeFilters, BeanDefinitionRegistry registry) {

super(false);

assertRequiredSpringVersionPresent();

Assert.notNull(includeFilters, "Include filters must not be null!");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");

this.registry = registry;

if (includeFilters.iterator().hasNext()) {
for (TypeFilter filter : includeFilters) {
Expand Down Expand Up @@ -129,6 +134,15 @@ public Set<BeanDefinition> findCandidateComponents(String basePackage) {
return candidates;
}

/*
* (non-Javadoc)
* @see org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#getRegistry()
*/
@Override
protected BeanDefinitionRegistry getRegistry() {
return registry;
}

/**
* @return the considerNestedRepositoryInterfaces
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Collections;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.TypeFilter;
Expand All @@ -38,20 +39,24 @@ public abstract class RepositoryConfigurationSourceSupport implements Repository

private final Environment environment;
private final RepositoryBeanNameGenerator beanNameGenerator;
private final BeanDefinitionRegistry registry;

/**
* Creates a new {@link RepositoryConfigurationSourceSupport} with the given environment.
*
* @param environment must not be {@literal null}.
* @param classLoader must not be {@literal null}.
*/
public RepositoryConfigurationSourceSupport(Environment environment, ClassLoader classLoader) {
public RepositoryConfigurationSourceSupport(Environment environment, ClassLoader classLoader,
BeanDefinitionRegistry registry) {

Assert.notNull(environment, "Environment must not be null!");
Assert.notNull(classLoader, "ClassLoader must not be null!");
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");

this.environment = environment;
this.beanNameGenerator = new RepositoryBeanNameGenerator(classLoader);
this.registry = registry;
}

/*
Expand All @@ -61,10 +66,10 @@ public RepositoryConfigurationSourceSupport(Environment environment, ClassLoader
@Override
public Streamable<BeanDefinition> getCandidates(ResourceLoader loader) {

RepositoryComponentProvider scanner = new RepositoryComponentProvider(getIncludeFilters());
RepositoryComponentProvider scanner = new RepositoryComponentProvider(getIncludeFilters(), registry);
scanner.setConsiderNestedRepositoryInterfaces(shouldConsiderNestedRepositories());
scanner.setResourceLoader(loader);
scanner.setEnvironment(environment);
scanner.setResourceLoader(loader);

getExcludeFilters().forEach(it -> scanner.addExcludeFilter(it));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public class XmlRepositoryConfigurationSource extends RepositoryConfigurationSou
*/
public XmlRepositoryConfigurationSource(Element element, ParserContext context, Environment environment) {

super(environment, context.getReaderContext().getResourceLoader().getClassLoader());
super(environment, context.getReaderContext().getResourceLoader().getClassLoader(), context.getRegistry());

Assert.notNull(element, "Element must not be null!");
Assert.notNull(context, "Context must not be null!");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
package org.springframework.data.repository.config;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
Expand All @@ -45,15 +47,18 @@ public class AnnotationRepositoryConfigurationSourceUnitTests {
RepositoryConfigurationSource source;
Environment environment;
ResourceLoader resourceLoader;
BeanDefinitionRegistry registry;

@Before
public void setUp() {

AnnotationMetadata annotationMetadata = new StandardAnnotationMetadata(SampleConfiguration.class, true);
environment = new StandardEnvironment();
resourceLoader = new DefaultResourceLoader();
registry = mock(BeanDefinitionRegistry.class);

source = new AnnotationRepositoryConfigurationSource(annotationMetadata, EnableRepositories.class, resourceLoader,
environment);
environment, registry);
}

@Test // DATACMNS-47
Expand Down Expand Up @@ -110,7 +115,7 @@ public void returnsEmptyStringForBasePackage() throws Exception {
StandardAnnotationMetadata metadata = new StandardAnnotationMetadata(
getClass().getClassLoader().loadClass("TypeInDefaultPackage"), true);
RepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(metadata,
EnableRepositories.class, resourceLoader, environment);
EnableRepositories.class, resourceLoader, environment, registry);

assertThat(configurationSource.getBasePackages()).contains("");
}
Expand All @@ -127,15 +132,16 @@ public void ignoresMissingRepositoryBaseClassNameAttribute() {

AnnotationMetadata metadata = new StandardAnnotationMetadata(ConfigWithSampleAnnotation.class, true);
RepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource(metadata,
SampleAnnotation.class, resourceLoader, environment);
SampleAnnotation.class, resourceLoader, environment, registry);

assertThat(configurationSource.getRepositoryBaseClassName()).isNotPresent();
}

private AnnotationRepositoryConfigurationSource getConfigSource(Class<?> type) {

AnnotationMetadata metadata = new StandardAnnotationMetadata(type, true);
return new AnnotationRepositoryConfigurationSource(metadata, EnableRepositories.class, resourceLoader, environment);
return new AnnotationRepositoryConfigurationSource(metadata, EnableRepositories.class, resourceLoader, environment,
registry);
}

public static class Person {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
package org.springframework.data.repository.config;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
Expand All @@ -26,6 +26,7 @@
import org.hamcrest.Description;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.data.repository.Repository;
Expand All @@ -40,10 +41,12 @@
*/
public class RepositoryComponentProviderUnitTests {

BeanDefinitionRegistry registry = mock(BeanDefinitionRegistry.class);

@Test
public void findsAnnotatedRepositoryInterface() {

RepositoryComponentProvider provider = new RepositoryComponentProvider(Collections.emptyList());
RepositoryComponentProvider provider = new RepositoryComponentProvider(Collections.emptyList(), registry);
Set<BeanDefinition> components = provider.findCandidateComponents("org.springframework.data.repository.sample");

assertThat(components).hasSize(3);
Expand All @@ -56,7 +59,7 @@ public void limitsFoundRepositoriesToIncludeFiltersOnly() {

List<? extends TypeFilter> filters = Collections.singletonList(new AssignableTypeFilter(MyOtherRepository.class));

RepositoryComponentProvider provider = new RepositoryComponentProvider(filters);
RepositoryComponentProvider provider = new RepositoryComponentProvider(filters, registry);
Set<BeanDefinition> components = provider.findCandidateComponents("org.springframework.data.repository");

assertThat(components).hasSize(1);
Expand All @@ -66,7 +69,7 @@ public void limitsFoundRepositoriesToIncludeFiltersOnly() {
@Test // DATACMNS-90
public void shouldConsiderNestedRepositoryInterfacesIfEnabled() {

RepositoryComponentProvider provider = new RepositoryComponentProvider(Collections.emptyList());
RepositoryComponentProvider provider = new RepositoryComponentProvider(Collections.emptyList(), registry);
provider.setConsiderNestedRepositoryInterfaces(true);

Set<BeanDefinition> components = provider.findCandidateComponents("org.springframework.data.repository.config");
Expand All @@ -76,6 +79,19 @@ public void shouldConsiderNestedRepositoryInterfacesIfEnabled() {
assertThat(components).extracting(BeanDefinition::getBeanClassName).contains(nestedRepositoryClassName);
}

@Test(expected = IllegalArgumentException.class) // DATACMNS-1098
public void rejectsNullBeanDefinitionRegistry() {
new RepositoryComponentProvider(Collections.emptyList(), null);
}

@Test // DATACMNS-1098
public void exposesBeanDefinitionRegistry() {

RepositoryComponentProvider provider = new RepositoryComponentProvider(Collections.emptyList(), registry);

assertThat(provider.getRegistry()).isEqualTo(registry);
}

static class BeanDefinitionOfTypeMatcher extends BaseMatcher<BeanDefinition> {

private final Class<?> expectedType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ public void registersRepositoryBeanNameAsAttribute() {

StandardEnvironment environment = new StandardEnvironment();
GenericApplicationContext context = new GenericApplicationContext();

RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource(
new StandardAnnotationMetadata(TestConfig.class, true), EnableRepositories.class, context, environment);
new StandardAnnotationMetadata(TestConfig.class, true), EnableRepositories.class, context, environment,
context.getDefaultListableBeanFactory());

RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, context, environment);

Expand Down

0 comments on commit fce40e9

Please sign in to comment.