Register AutoConfigurations using fully qualified class name
Update `AbstractApplicationContextRunner` and `Configurations` to allow registration of beans with a specific generated bean name. By default, no name is generated, however, `AutoConfigurations` has been updated to use bean names using the fully qualified class name. The update brings `ApplicationContextRunners` closer the behavior of a standard Spring Boot application where user `@Configuration` classes are usually registered with a simple name and auto-configurations are imported (via an `ImportSelector`) using a fully qualified name. Fixes gh-17963 Co-authored-by: Stéphane Nicoll <stephane.nicoll@broadcom.com> Co-authored-by: Andy Wilkinson <andy.wilkinson@broadcom.com> Co-authored-by: Dmytro Nosan <dimanosan@gmail.com>
This commit is contained in:
@@ -25,6 +25,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -65,6 +66,8 @@ public abstract class Configurations {
|
||||
|
||||
private final Set<Class<?>> classes;
|
||||
|
||||
private final Function<Class<?>, String> beanNameGenerator;
|
||||
|
||||
/**
|
||||
* Create a new {@link Configurations} instance.
|
||||
* @param classes the configuration classes
|
||||
@@ -74,20 +77,28 @@ public abstract class Configurations {
|
||||
Collection<Class<?>> sorted = sort(classes);
|
||||
this.sorter = null;
|
||||
this.classes = Collections.unmodifiableSet(new LinkedHashSet<>(sorted));
|
||||
this.beanNameGenerator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Configurations} instance.
|
||||
* @param sorter a {@link UnaryOperator} used to sort the configurations
|
||||
* @param classes the configuration classes
|
||||
* @param beanNameGenerator an optional function used to generate the bean name
|
||||
* @since 3.4.0
|
||||
*/
|
||||
protected Configurations(UnaryOperator<Collection<Class<?>>> sorter, Collection<Class<?>> classes) {
|
||||
Assert.notNull(sorter, "Sorter must not be null");
|
||||
protected Configurations(UnaryOperator<Collection<Class<?>>> sorter, Collection<Class<?>> classes,
|
||||
Function<Class<?>, String> beanNameGenerator) {
|
||||
Assert.notNull(classes, "Classes must not be null");
|
||||
sorter = (sorter != null) ? sorter : UnaryOperator.identity();
|
||||
Collection<Class<?>> sorted = sorter.apply(classes);
|
||||
this.sorter = sorter;
|
||||
this.sorter = (sorter != null) ? sorter : UnaryOperator.identity();
|
||||
this.classes = Collections.unmodifiableSet(new LinkedHashSet<>(sorted));
|
||||
this.beanNameGenerator = beanNameGenerator;
|
||||
}
|
||||
|
||||
protected final Set<Class<?>> getClasses() {
|
||||
return this.classes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,17 +106,13 @@ public abstract class Configurations {
|
||||
* @param classes the classes to sort
|
||||
* @return a sorted set of classes
|
||||
* @deprecated since 3.4.0 for removal in 3.6.0 in favor of
|
||||
* {@link #Configurations(UnaryOperator, Collection)}
|
||||
* {@link #Configurations(UnaryOperator, Collection, Function)}
|
||||
*/
|
||||
@Deprecated(since = "3.4.0", forRemoval = true)
|
||||
protected Collection<Class<?>> sort(Collection<Class<?>> classes) {
|
||||
return classes;
|
||||
}
|
||||
|
||||
protected final Set<Class<?>> getClasses() {
|
||||
return this.classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge configurations from another source of the same type.
|
||||
* @param other the other {@link Configurations} (must be of the same type as this
|
||||
@@ -128,6 +135,17 @@ public abstract class Configurations {
|
||||
*/
|
||||
protected abstract Configurations merge(Set<Class<?>> mergedClasses);
|
||||
|
||||
/**
|
||||
* Return the bean name that should be used for the given configuration class or
|
||||
* {@code null} to use the default name.
|
||||
* @param beanClass the bean class
|
||||
* @return the bean name
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public String getBeanName(Class<?> beanClass) {
|
||||
return (this.beanNameGenerator != null) ? this.beanNameGenerator.apply(beanClass) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the classes from all the specified configurations in the order that they
|
||||
* would be registered.
|
||||
@@ -145,30 +163,40 @@ public abstract class Configurations {
|
||||
* @return configuration classes in registration order
|
||||
*/
|
||||
public static Class<?>[] getClasses(Collection<Configurations> configurations) {
|
||||
List<Configurations> ordered = new ArrayList<>(configurations);
|
||||
ordered.sort(COMPARATOR);
|
||||
List<Configurations> collated = collate(ordered);
|
||||
List<Configurations> collated = collate(configurations);
|
||||
LinkedHashSet<Class<?>> classes = collated.stream()
|
||||
.flatMap(Configurations::streamClasses)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
return ClassUtils.toClassArray(classes);
|
||||
}
|
||||
|
||||
private static Stream<Class<?>> streamClasses(Configurations configurations) {
|
||||
return configurations.getClasses().stream();
|
||||
}
|
||||
|
||||
private static List<Configurations> collate(List<Configurations> orderedConfigurations) {
|
||||
/**
|
||||
* Collate the given configuration by sorting and merging them.
|
||||
* @param configurations the source configuration
|
||||
* @return the collated configurations
|
||||
* @since 3.4.0
|
||||
*/
|
||||
public static List<Configurations> collate(Collection<Configurations> configurations) {
|
||||
LinkedList<Configurations> collated = new LinkedList<>();
|
||||
for (Configurations item : orderedConfigurations) {
|
||||
if (collated.isEmpty() || collated.getLast().getClass() != item.getClass()) {
|
||||
collated.add(item);
|
||||
for (Configurations configuration : sortConfigurations(configurations)) {
|
||||
if (collated.isEmpty() || collated.getLast().getClass() != configuration.getClass()) {
|
||||
collated.add(configuration);
|
||||
}
|
||||
else {
|
||||
collated.set(collated.size() - 1, collated.getLast().merge(item));
|
||||
collated.set(collated.size() - 1, collated.getLast().merge(configuration));
|
||||
}
|
||||
}
|
||||
return collated;
|
||||
}
|
||||
|
||||
private static List<Configurations> sortConfigurations(Collection<Configurations> configurations) {
|
||||
List<Configurations> sorted = new ArrayList<>(configurations);
|
||||
sorted.sort(COMPARATOR);
|
||||
return sorted;
|
||||
}
|
||||
|
||||
private static Stream<Class<?>> streamClasses(Configurations configurations) {
|
||||
return configurations.getClasses().stream();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -87,6 +89,18 @@ class ConfigurationsTests {
|
||||
OutputStream.class, String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanNameWhenNoFunctionReturnsNull() {
|
||||
Configurations configurations = new TestConfigurations(Short.class);
|
||||
assertThat(configurations.getBeanName(Short.class)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanNameWhenFunctionReturnsBeanName() {
|
||||
Configurations configurations = new TestConfigurations(Sorter.instance, List.of(Short.class), Class::getName);
|
||||
assertThat(configurations.getBeanName(Short.class)).isEqualTo(Short.class.getName());
|
||||
}
|
||||
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
static class TestConfigurations extends Configurations {
|
||||
|
||||
@@ -95,7 +109,12 @@ class ConfigurationsTests {
|
||||
}
|
||||
|
||||
TestConfigurations(UnaryOperator<Collection<Class<?>>> sorter, Class<?>... classes) {
|
||||
super(sorter, Arrays.asList(classes));
|
||||
this(sorter, Arrays.asList(classes), null);
|
||||
}
|
||||
|
||||
TestConfigurations(UnaryOperator<Collection<Class<?>>> sorter, Collection<Class<?>> classes,
|
||||
Function<Class<?>, String> beanNameGenerator) {
|
||||
super(sorter, classes, beanNameGenerator);
|
||||
}
|
||||
|
||||
TestConfigurations(Collection<Class<?>> classes) {
|
||||
@@ -117,7 +136,7 @@ class ConfigurationsTests {
|
||||
}
|
||||
|
||||
protected TestSortedConfigurations(Collection<Class<?>> classes) {
|
||||
super(Sorter.instance, classes);
|
||||
super(Sorter.instance, classes, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user