Add support for deferred import selector group
This commit allows several DeferredImportSelector instances to be grouped and managed in a centralized fashion. This typically allows different instances to provide a consistent ordered set of imports to apply. Issue: SPR-16589
This commit is contained in:
@@ -51,6 +51,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReader;
|
|||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||||
import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase;
|
import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase;
|
||||||
|
import org.springframework.context.annotation.DeferredImportSelector.Group;
|
||||||
import org.springframework.core.NestedIOException;
|
import org.springframework.core.NestedIOException;
|
||||||
import org.springframework.core.OrderComparator;
|
import org.springframework.core.OrderComparator;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
@@ -100,6 +101,7 @@ import org.springframework.util.StringUtils;
|
|||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
|
* @author Stephane Nicoll
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see ConfigurationClassBeanDefinitionReader
|
* @see ConfigurationClassBeanDefinitionReader
|
||||||
*/
|
*/
|
||||||
@@ -543,21 +545,46 @@ class ConfigurationClassParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
|
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
|
||||||
|
Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
|
||||||
|
Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
|
||||||
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
|
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
|
||||||
ConfigurationClass configClass = deferredImport.getConfigurationClass();
|
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
|
||||||
try {
|
DeferredImportSelectorGrouping grouping = groupings.computeIfAbsent(
|
||||||
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
|
(group == null ? deferredImport : group),
|
||||||
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
|
(key) -> new DeferredImportSelectorGrouping(createGroup(group)));
|
||||||
}
|
grouping.add(deferredImport);
|
||||||
catch (BeanDefinitionStoreException ex) {
|
configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
|
||||||
throw ex;
|
deferredImport.getConfigurationClass());
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
throw new BeanDefinitionStoreException(
|
|
||||||
"Failed to process import candidates for configuration class [" +
|
|
||||||
configClass.getMetadata().getClassName() + "]", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
for (DeferredImportSelectorGrouping grouping : groupings.values()) {
|
||||||
|
grouping.getImports().forEach((entry) -> {
|
||||||
|
ConfigurationClass configurationClass = configurationClasses.get(
|
||||||
|
entry.getMetadata());
|
||||||
|
try {
|
||||||
|
processImports(configurationClass, asSourceClass(configurationClass),
|
||||||
|
asSourceClasses(entry.getImportClassName()), false);
|
||||||
|
}
|
||||||
|
catch (BeanDefinitionStoreException ex) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
throw new BeanDefinitionStoreException(
|
||||||
|
"Failed to process import candidates for configuration class [" +
|
||||||
|
configurationClass.getMetadata().getClassName() + "]", ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Group createGroup(@Nullable Class<? extends Group> type) {
|
||||||
|
Class<? extends Group> effectiveType = (type != null ? type
|
||||||
|
: DefaultDeferredImportSelectorGroup.class);
|
||||||
|
Group group = BeanUtils.instantiateClass(effectiveType);
|
||||||
|
ParserStrategyUtils.invokeAwareMethods(group,
|
||||||
|
ConfigurationClassParser.this.environment,
|
||||||
|
ConfigurationClassParser.this.resourceLoader,
|
||||||
|
ConfigurationClassParser.this.registry);
|
||||||
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
|
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
|
||||||
@@ -677,7 +704,7 @@ class ConfigurationClassParser {
|
|||||||
/**
|
/**
|
||||||
* Factory method to obtain {@link SourceClass}s from class names.
|
* Factory method to obtain {@link SourceClass}s from class names.
|
||||||
*/
|
*/
|
||||||
private Collection<SourceClass> asSourceClasses(String[] classNames) throws IOException {
|
private Collection<SourceClass> asSourceClasses(String... classNames) throws IOException {
|
||||||
List<SourceClass> annotatedClasses = new ArrayList<>(classNames.length);
|
List<SourceClass> annotatedClasses = new ArrayList<>(classNames.length);
|
||||||
for (String className : classNames) {
|
for (String className : classNames) {
|
||||||
annotatedClasses.add(asSourceClass(className));
|
annotatedClasses.add(asSourceClass(className));
|
||||||
@@ -777,6 +804,52 @@ class ConfigurationClassParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class DeferredImportSelectorGrouping {
|
||||||
|
|
||||||
|
private final DeferredImportSelector.Group group;
|
||||||
|
|
||||||
|
private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();
|
||||||
|
|
||||||
|
DeferredImportSelectorGrouping(Group group) {
|
||||||
|
this.group = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(DeferredImportSelectorHolder deferredImport) {
|
||||||
|
this.deferredImports.add(deferredImport);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the imports defined by the group.
|
||||||
|
* @return each import with its associated configuration class
|
||||||
|
*/
|
||||||
|
public Iterable<Group.Entry> getImports() {
|
||||||
|
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
|
||||||
|
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
|
||||||
|
deferredImport.getImportSelector());
|
||||||
|
}
|
||||||
|
return this.group.selectImports();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class DefaultDeferredImportSelectorGroup implements Group {
|
||||||
|
|
||||||
|
private final List<Entry> imports = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
|
||||||
|
for (String importClassName : selector.selectImports(metadata)) {
|
||||||
|
this.imports.add(new Entry(metadata, importClassName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<Entry> selectImports() {
|
||||||
|
return this.imports;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple wrapper that allows annotated source classes to be dealt with
|
* Simple wrapper that allows annotated source classes to be dealt with
|
||||||
* in a uniform manner, regardless of how they are loaded.
|
* in a uniform manner, regardless of how they are loaded.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,6 +16,11 @@
|
|||||||
|
|
||||||
package org.springframework.context.annotation;
|
package org.springframework.context.annotation;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A variation of {@link ImportSelector} that runs after all {@code @Configuration} beans
|
* A variation of {@link ImportSelector} that runs after all {@code @Configuration} beans
|
||||||
* have been processed. This type of selector can be particularly useful when the selected
|
* have been processed. This type of selector can be particularly useful when the selected
|
||||||
@@ -25,9 +30,90 @@ package org.springframework.context.annotation;
|
|||||||
* interface or use the {@link org.springframework.core.annotation.Order} annotation to
|
* interface or use the {@link org.springframework.core.annotation.Order} annotation to
|
||||||
* indicate a precedence against other {@link DeferredImportSelector}s.
|
* indicate a precedence against other {@link DeferredImportSelector}s.
|
||||||
*
|
*
|
||||||
|
* <p>Implementations may also provide an {@link #getImportGroup() import group} which
|
||||||
|
* can provide additional sorting and filtering logic across different selectors.
|
||||||
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Stephane Nicoll
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public interface DeferredImportSelector extends ImportSelector {
|
public interface DeferredImportSelector extends ImportSelector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a specific import group or {@code null} if no grouping is required.
|
||||||
|
* @return the import group class or {@code null}
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default Class<? extends Group> getImportGroup() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface used to group results from different import selectors.
|
||||||
|
*/
|
||||||
|
interface Group {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the {@link AnnotationMetadata} of the importing @{@link Configuration}
|
||||||
|
* class using the specified {@link DeferredImportSelector}.
|
||||||
|
*/
|
||||||
|
void process(AnnotationMetadata metadata, DeferredImportSelector selector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@link Entry entries} of which class(es) should be imported for this
|
||||||
|
* group.
|
||||||
|
*/
|
||||||
|
Iterable<Entry> selectImports();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entry that holds the {@link AnnotationMetadata} of the importing
|
||||||
|
* {@link Configuration} class and the class name to import.
|
||||||
|
*/
|
||||||
|
class Entry {
|
||||||
|
|
||||||
|
private final AnnotationMetadata metadata;
|
||||||
|
|
||||||
|
private final String importClassName;
|
||||||
|
|
||||||
|
public Entry(AnnotationMetadata metadata, String importClassName) {
|
||||||
|
this.metadata = metadata;
|
||||||
|
this.importClassName = importClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@link AnnotationMetadata} of the importing
|
||||||
|
* {@link Configuration} class.
|
||||||
|
*/
|
||||||
|
public AnnotationMetadata getMetadata() {
|
||||||
|
return this.metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the fully qualified name of the class to import.
|
||||||
|
*/
|
||||||
|
public String getImportClassName() {
|
||||||
|
return this.importClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Entry entry = (Entry) o;
|
||||||
|
return Objects.equals(this.metadata, entry.metadata) &&
|
||||||
|
Objects.equals(this.importClassName, entry.importClassName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(this.metadata, this.importClassName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2018 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
|
||||||
|
*
|
||||||
|
* http://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.context.annotation;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.DeferredImportSelector.Group;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link DeferredImportSelector}.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
public class DeferredImportSelectorTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void entryEqualsSameInstance() {
|
||||||
|
AnnotationMetadata metadata = mock(AnnotationMetadata.class);
|
||||||
|
Group.Entry entry = new Group.Entry(metadata, "com.example.Test");
|
||||||
|
assertEquals(entry, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void entryEqualsSameMetadataAndClassName() {
|
||||||
|
AnnotationMetadata metadata = mock(AnnotationMetadata.class);
|
||||||
|
assertEquals(new Group.Entry(metadata, "com.example.Test"),
|
||||||
|
new Group.Entry(metadata, "com.example.Test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void entryEqualDifferentMetadataAndSameClassName() {
|
||||||
|
assertNotEquals(
|
||||||
|
new Group.Entry(mock(AnnotationMetadata.class), "com.example.Test"),
|
||||||
|
new Group.Entry(mock(AnnotationMetadata.class), "com.example.Test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void entryEqualSameMetadataAnDifferentClassName() {
|
||||||
|
AnnotationMetadata metadata = mock(AnnotationMetadata.class);
|
||||||
|
assertNotEquals(new Group.Entry(metadata, "com.example.Test"),
|
||||||
|
new Group.Entry(metadata, "com.example.AnotherTest"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,13 +20,19 @@ import java.lang.annotation.ElementType;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
@@ -39,15 +45,20 @@ import org.springframework.core.annotation.Order;
|
|||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
import org.springframework.core.type.AnnotationMetadata;
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ImportSelector} and {@link DeferredImportSelector}.
|
* Tests for {@link ImportSelector} and {@link DeferredImportSelector}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("resource")
|
@SuppressWarnings("resource")
|
||||||
public class ImportSelectorTests {
|
public class ImportSelectorTests {
|
||||||
@@ -55,9 +66,11 @@ public class ImportSelectorTests {
|
|||||||
static Map<Class<?>, String> importFrom = new HashMap<>();
|
static Map<Class<?>, String> importFrom = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
@BeforeClass
|
@Before
|
||||||
public static void clearImportFrom() {
|
public void cleanup() {
|
||||||
ImportSelectorTests.importFrom.clear();
|
ImportSelectorTests.importFrom.clear();
|
||||||
|
SampleImportSelector.cleanup();
|
||||||
|
TestImportGroup.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -94,6 +107,48 @@ public class ImportSelectorTests {
|
|||||||
assertThat(importFrom.get(DeferredImportSelector2.class), isFromIndirect);
|
assertThat(importFrom.get(DeferredImportSelector2.class), isFromIndirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void importSelectorsWithGroup() {
|
||||||
|
DefaultListableBeanFactory beanFactory = spy(new DefaultListableBeanFactory());
|
||||||
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(beanFactory);
|
||||||
|
context.register(GroupedConfig.class);
|
||||||
|
context.refresh();
|
||||||
|
InOrder ordered = inOrder(beanFactory);
|
||||||
|
ordered.verify(beanFactory).registerBeanDefinition(eq("a"), any());
|
||||||
|
ordered.verify(beanFactory).registerBeanDefinition(eq("b"), any());
|
||||||
|
ordered.verify(beanFactory).registerBeanDefinition(eq("c"), any());
|
||||||
|
ordered.verify(beanFactory).registerBeanDefinition(eq("d"), any());
|
||||||
|
assertThat(TestImportGroup.instancesCount.get(), equalTo(1));
|
||||||
|
assertThat(TestImportGroup.imports.size(), equalTo(1));
|
||||||
|
assertThat(TestImportGroup.imports.values().iterator().next().size(), equalTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void importSelectorsSeparateWithGroup() {
|
||||||
|
DefaultListableBeanFactory beanFactory = spy(new DefaultListableBeanFactory());
|
||||||
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(beanFactory);
|
||||||
|
context.register(GroupedConfig1.class);
|
||||||
|
context.register(GroupedConfig2.class);
|
||||||
|
context.refresh();
|
||||||
|
InOrder ordered = inOrder(beanFactory);
|
||||||
|
ordered.verify(beanFactory).registerBeanDefinition(eq("c"), any());
|
||||||
|
ordered.verify(beanFactory).registerBeanDefinition(eq("d"), any());
|
||||||
|
assertThat(TestImportGroup.instancesCount.get(), equalTo(1));
|
||||||
|
assertThat(TestImportGroup.imports.size(), equalTo(2));
|
||||||
|
Iterator<AnnotationMetadata> iterator = TestImportGroup.imports.keySet().iterator();
|
||||||
|
assertThat(iterator.next().getClassName(), equalTo(GroupedConfig2.class.getName()));
|
||||||
|
assertThat(iterator.next().getClassName(), equalTo(GroupedConfig1.class.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invokeAwareMethodsInImportGroup() {
|
||||||
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(GroupedConfig1.class);
|
||||||
|
assertThat(TestImportGroup.beanFactory, is(context.getBeanFactory()));
|
||||||
|
assertThat(TestImportGroup.classLoader, is(context.getBeanFactory().getBeanClassLoader()));
|
||||||
|
assertThat(TestImportGroup.resourceLoader, is(notNullValue()));
|
||||||
|
assertThat(TestImportGroup.environment, is(context.getEnvironment()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Import(SampleImportSelector.class)
|
@Import(SampleImportSelector.class)
|
||||||
@@ -109,6 +164,13 @@ public class ImportSelectorTests {
|
|||||||
static BeanFactory beanFactory;
|
static BeanFactory beanFactory;
|
||||||
static Environment environment;
|
static Environment environment;
|
||||||
|
|
||||||
|
static void cleanup() {
|
||||||
|
SampleImportSelector.classLoader = null;
|
||||||
|
SampleImportSelector.beanFactory = null;
|
||||||
|
SampleImportSelector.resourceLoader = null;
|
||||||
|
SampleImportSelector.environment = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
SampleImportSelector.classLoader = classLoader;
|
SampleImportSelector.classLoader = classLoader;
|
||||||
@@ -255,4 +317,107 @@ public class ImportSelectorTests {
|
|||||||
public static class IndirectImport {
|
public static class IndirectImport {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GroupedSample
|
||||||
|
@Configuration
|
||||||
|
static class GroupedConfig {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Import({GroupedDeferredImportSelector1.class, GroupedDeferredImportSelector2.class, ImportSelector1.class, ImportSelector2.class})
|
||||||
|
public @interface GroupedSample {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(GroupedDeferredImportSelector1.class)
|
||||||
|
static class GroupedConfig1 {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(GroupedDeferredImportSelector2.class)
|
||||||
|
static class GroupedConfig2 {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class GroupedDeferredImportSelector1 extends DeferredImportSelector1 {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Class<? extends Group> getImportGroup() {
|
||||||
|
return TestImportGroup.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GroupedDeferredImportSelector2 extends DeferredImportSelector2 {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Class<? extends Group> getImportGroup() {
|
||||||
|
return TestImportGroup.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class TestImportGroup implements DeferredImportSelector.Group,
|
||||||
|
BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware {
|
||||||
|
|
||||||
|
static ClassLoader classLoader;
|
||||||
|
static ResourceLoader resourceLoader;
|
||||||
|
static BeanFactory beanFactory;
|
||||||
|
static Environment environment;
|
||||||
|
|
||||||
|
static AtomicInteger instancesCount = new AtomicInteger();
|
||||||
|
static MultiValueMap<AnnotationMetadata, String> imports = new LinkedMultiValueMap<>();
|
||||||
|
|
||||||
|
public TestImportGroup() {
|
||||||
|
TestImportGroup.instancesCount.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cleanup() {
|
||||||
|
TestImportGroup.classLoader = null;
|
||||||
|
TestImportGroup.beanFactory = null;
|
||||||
|
TestImportGroup.resourceLoader = null;
|
||||||
|
TestImportGroup.environment = null;
|
||||||
|
TestImportGroup.instancesCount = new AtomicInteger();
|
||||||
|
TestImportGroup.imports.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
|
||||||
|
TestImportGroup.imports.addAll(metadata,
|
||||||
|
Arrays.asList(selector.selectImports(metadata)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<Entry> selectImports() {
|
||||||
|
LinkedList<Entry> content = new LinkedList<>();
|
||||||
|
TestImportGroup.imports.forEach((metadata, values) ->
|
||||||
|
values.forEach(value -> content.add(new Entry(metadata, value))));
|
||||||
|
Collections.reverse(content);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
|
TestImportGroup.classLoader = classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||||
|
TestImportGroup.beanFactory = beanFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||||
|
TestImportGroup.resourceLoader = resourceLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnvironment(Environment environment) {
|
||||||
|
TestImportGroup.environment = environment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user