Use more flexible SpringFactoriesLoader

Closes gh-30235

Co-authored-by: Madhura Bhave <bhavem@vmware.com>
Co-authored-by: Stephane Nicoll <snicoll@vmware.com>
This commit is contained in:
Andy Wilkinson 2022-05-09 14:13:04 +01:00
parent 0fbfb8ef09
commit 770cb840c3
33 changed files with 440 additions and 311 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2022 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.
@ -64,7 +64,7 @@ public class ConditionEvaluationReportLoggingListener
this(LogLevel.DEBUG);
}
public ConditionEvaluationReportLoggingListener(LogLevel logLevelForReport) {
private ConditionEvaluationReportLoggingListener(LogLevel logLevelForReport) {
Assert.isTrue(isInfoOrDebug(logLevelForReport), "LogLevel must be INFO or DEBUG");
this.logLevelForReport = logLevelForReport;
}
@ -73,6 +73,18 @@ public class ConditionEvaluationReportLoggingListener
return LogLevel.INFO.equals(logLevelForReport) || LogLevel.DEBUG.equals(logLevelForReport);
}
/**
* Static factory method that creates a
* {@link ConditionEvaluationReportLoggingListener} which logs the report at the
* specified log level.
* @param logLevelForReport the log level to log the report at
* @return a {@link ConditionEvaluationReportLoggingListener} instance.
* @since 3.0.0
*/
public static ConditionEvaluationReportLoggingListener forLogLevel(LogLevel logLevelForReport) {
return new ConditionEvaluationReportLoggingListener(logLevelForReport);
}
public LogLevel getLogLevelForReport() {
return this.logLevelForReport;
}

View File

@ -54,7 +54,7 @@ class BatchAutoConfigurationWithoutJpaTests {
void jdbcWithDefaultSettings() {
this.contextRunner.withUserConfiguration(DefaultConfiguration.class, EmbeddedDataSourceConfiguration.class)
.withPropertyValues("spring.datasource.generate-unique-name=true")
.withInitializer(new ConditionEvaluationReportLoggingListener(LogLevel.INFO)).run((context) -> {
.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO)).run((context) -> {
assertThat(context).hasSingleBean(JobLauncher.class);
assertThat(context).hasSingleBean(JobExplorer.class);
assertThat(context).hasSingleBean(JobRepository.class);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 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.
@ -123,8 +123,8 @@ class ConditionEvaluationReportLoggingListenerTests {
@Test
void listenerWithInfoLevelShouldLogAtInfo(CapturedOutput output) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
ConditionEvaluationReportLoggingListener initializer = new ConditionEvaluationReportLoggingListener(
LogLevel.INFO);
ConditionEvaluationReportLoggingListener initializer = ConditionEvaluationReportLoggingListener
.forLogLevel(LogLevel.INFO);
initializer.initialize(context);
context.register(Config.class);
context.refresh();
@ -135,7 +135,7 @@ class ConditionEvaluationReportLoggingListenerTests {
@Test
void listenerSupportsOnlyInfoAndDebug() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ConditionEvaluationReportLoggingListener(LogLevel.TRACE))
.isThrownBy(() -> ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.TRACE))
.withMessageContaining("LogLevel must be INFO or DEBUG");
}

View File

@ -70,7 +70,7 @@ class SqlInitializationAutoConfigurationTests {
@Test
void whenConnectionFactoryIsAvailableAndModeIsNeverThenInitializerIsNotAutoConfigured() {
this.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))
.withInitializer(new ConditionEvaluationReportLoggingListener(LogLevel.INFO))
.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))
.withPropertyValues("spring.sql.init.mode:never")
.run((context) -> assertThat(context).doesNotHaveBean(AbstractScriptDatabaseInitializer.class));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2022 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.
@ -72,8 +72,8 @@ public final class RemoteSpringApplication {
private Collection<ApplicationListener<?>> getListeners() {
List<ApplicationListener<?>> listeners = new ArrayList<>();
listeners.add(new AnsiOutputApplicationListener());
listeners.add(new EnvironmentPostProcessorApplicationListener(
EnvironmentPostProcessorsFactory.of(ConfigDataEnvironmentPostProcessor.class)));
listeners.add(EnvironmentPostProcessorApplicationListener
.with(EnvironmentPostProcessorsFactory.of(ConfigDataEnvironmentPostProcessor.class)));
listeners.add(new LoggingApplicationListener());
listeners.add(new RemoteUrlPropertyExtractor());
return listeners;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -28,7 +28,7 @@ class MyConditionEvaluationReportingTests {
void autoConfigTest() {
// @formatter:off
new ApplicationContextRunner()
.withInitializer(new ConditionEvaluationReportLoggingListener(LogLevel.INFO))
.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))
.run((context) -> {
// Test something...
});

View File

@ -28,7 +28,7 @@ class MyConditionEvaluationReportingTests {
@Test
fun autoConfigTest() {
ApplicationContextRunner()
.withInitializer(ConditionEvaluationReportLoggingListener(LogLevel.INFO))
.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))
.run { context: AssertableApplicationContext? -> }
}

View File

@ -0,0 +1,130 @@
/*
* Copyright 2012-2022 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.boot.testsupport.mock;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.core.io.support.SpringFactoriesLoader;
/**
* Simple mock {@link SpringFactoriesLoader} implementation that can be used for testing
* purposes.
*
* @author Phillip Webb
* @since 3.0.0
*/
public class MockSpringFactoriesLoader extends SpringFactoriesLoader {
private final AtomicInteger sequence = new AtomicInteger();
private final Map<String, List<String>> factories;
private final Map<String, Object> implementations = new HashMap<>();
/**
* Create a new {@link MockSpringFactoriesLoader} instance with the default
* classloader.
*/
public MockSpringFactoriesLoader() {
this(null);
}
/**
* Create a new {@link MockSpringFactoriesLoader} instance with the given classloader.
* @param classLoader the classloader to use
*/
public MockSpringFactoriesLoader(ClassLoader classLoader) {
this(classLoader, new LinkedHashMap<>());
}
protected MockSpringFactoriesLoader(ClassLoader classLoader, Map<String, List<String>> factories) {
super(classLoader, factories);
this.factories = factories;
}
@Override
@SuppressWarnings("unchecked")
protected <T> T instantiateFactory(String implementationName, Class<T> type, ArgumentResolver argumentResolver,
FailureHandler failureHandler) {
if (implementationName.startsWith("!")) {
Object implementation = this.implementations.get(implementationName);
if (implementation != null) {
return (T) implementation;
}
}
return super.instantiateFactory(implementationName, type, argumentResolver, failureHandler);
}
/**
* Add factory implementations to this instance.
* @param factoryType the factory type class
* @param factoryImplementations the implementation classes
* @param <T> the factory type
*/
@SafeVarargs
public final <T> void add(Class<T> factoryType, Class<? extends T>... factoryImplementations) {
for (Class<? extends T> factoryImplementation : factoryImplementations) {
add(factoryType.getName(), factoryImplementation.getName());
}
}
/**
* Add factory implementations to this instance.
* @param factoryType the factory type class name
* @param factoryImplementations the implementation class names
*/
public void add(String factoryType, String... factoryImplementations) {
List<String> implementations = this.factories.computeIfAbsent(factoryType, (key) -> new ArrayList<>());
for (String factoryImplementation : factoryImplementations) {
implementations.add(factoryImplementation);
}
}
/**
* Add factory instances to this instance.
* @param factoryType the factory type class
* @param factoryInstances the implementation instances to add
* @param <T> the factory type
*/
@SuppressWarnings("unchecked")
public <T> void addInstance(Class<T> factoryType, T... factoryInstances) {
addInstance(factoryType.getName(), factoryInstances);
}
/**
* Add factory instances to this instance.
* @param factoryType the factory type class name
* @param factoryInstance the implementation instances to add
* @param <T> the factory instance type
*/
@SuppressWarnings("unchecked")
public <T> void addInstance(String factoryType, T... factoryInstance) {
List<String> implementations = this.factories.computeIfAbsent(factoryType, (key) -> new ArrayList<>());
for (T factoryImplementation : factoryInstance) {
String reference = "!" + factoryType + ":" + factoryImplementation.getClass().getName()
+ this.sequence.getAndIncrement();
implementations.add(reference);
this.implementations.put(reference, factoryImplementation);
}
}
}

View File

@ -16,7 +16,6 @@
package org.springframework.boot;
import java.lang.reflect.Constructor;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
@ -33,7 +32,6 @@ import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.CachedIntrospectionResults;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@ -420,42 +418,21 @@ public class SpringApplication {
}
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
SpringFactoriesLoader.ArgumentResolver argumentResolver = SpringFactoriesLoader.ArgumentResolver
.of(SpringApplication.class, this).and(String[].class, args);
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
getSpringFactoriesInstances(SpringApplicationRunListener.class, argumentResolver),
this.applicationStartup);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
return getSpringFactoriesInstances(type, null);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
SpringFactoriesLoader.ArgumentResolver argumentResolver) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
return SpringFactoriesLoader.forDefaultResourceLocation(classLoader).load(type, argumentResolver);
}
private ConfigurableEnvironment getOrCreateEnvironment() {
@ -806,8 +783,9 @@ public class SpringApplication {
private Collection<SpringBootExceptionReporter> getExceptionReporters(ConfigurableApplicationContext context) {
try {
return getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class<?>[] { ConfigurableApplicationContext.class }, context);
SpringFactoriesLoader.ArgumentResolver argumentResolver = SpringFactoriesLoader.ArgumentResolver
.of(ConfigurableApplicationContext.class, context);
return getSpringFactoriesInstances(SpringBootExceptionReporter.class, argumentResolver);
}
catch (Throwable ex) {
return Collections.emptyList();

View File

@ -29,6 +29,7 @@ import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcesso
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.json.JsonParser;
import org.springframework.boot.json.JsonParserFactory;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.Ordered;
import org.springframework.core.env.CommandLinePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
@ -101,10 +102,11 @@ public class CloudFoundryVcapEnvironmentPostProcessor implements EnvironmentPost
/**
* Create a new {@link CloudFoundryVcapEnvironmentPostProcessor} instance.
* @param logger the logger to use
* @param logFactory the log factory to use
* @since 3.0
*/
public CloudFoundryVcapEnvironmentPostProcessor(Log logger) {
this.logger = logger;
public CloudFoundryVcapEnvironmentPostProcessor(DeferredLogFactory logFactory) {
this.logger = logFactory.getLog(CloudFoundryVcapEnvironmentPostProcessor.class);
}
public void setOrder(int order) {

View File

@ -41,6 +41,7 @@ import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.log.LogMessage;
import org.springframework.util.StringUtils;
@ -148,13 +149,15 @@ class ConfigDataEnvironment {
this.additionalProfiles = additionalProfiles;
this.environmentUpdateListener = (environmentUpdateListener != null) ? environmentUpdateListener
: ConfigDataEnvironmentUpdateListener.NONE;
this.loaders = new ConfigDataLoaders(logFactory, bootstrapContext, resourceLoader.getClassLoader());
this.loaders = new ConfigDataLoaders(logFactory, bootstrapContext,
SpringFactoriesLoader.forDefaultResourceLocation());
this.contributors = createContributors(binder);
}
protected ConfigDataLocationResolvers createConfigDataLocationResolvers(DeferredLogFactory logFactory,
ConfigurableBootstrapContext bootstrapContext, Binder binder, ResourceLoader resourceLoader) {
return new ConfigDataLocationResolvers(logFactory, bootstrapContext, binder, resourceLoader);
return new ConfigDataLocationResolvers(logFactory, bootstrapContext, binder, resourceLoader,
SpringFactoriesLoader.forDefaultResourceLocation(resourceLoader.getClassLoader()));
}
private ConfigDataEnvironmentContributors createContributors(Binder binder) {

View File

@ -70,7 +70,7 @@ public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProces
this(logFactory, bootstrapContext, null);
}
public ConfigDataEnvironmentPostProcessor(DeferredLogFactory logFactory,
private ConfigDataEnvironmentPostProcessor(DeferredLogFactory logFactory,
ConfigurableBootstrapContext bootstrapContext,
ConfigDataEnvironmentUpdateListener environmentUpdateListener) {
this.logFactory = logFactory;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -18,8 +18,6 @@ package org.springframework.boot.context.config;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.springframework.boot.BootstrapContext;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.ConfigurableBootstrapContext;
@ -30,8 +28,7 @@ import org.springframework.boot.logging.DeferredLogFactory;
* {@link ConfigDataResource}. Implementations should be added as {@code spring.factories}
* entries. The following constructor parameter types are supported:
* <ul>
* <li>{@link Log} or {@link DeferredLogFactory} - if the loader needs deferred
* logging</li>
* <li>{@link DeferredLogFactory} - if the loader needs deferred logging</li>
* <li>{@link ConfigurableBootstrapContext} - A bootstrap context that can be used to
* store objects that may be expensive to create, or need to be shared
* ({@link BootstrapContext} or {@link BootstrapRegistry} may also be used).</li>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -27,7 +27,6 @@ import org.springframework.boot.BootstrapContext;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.boot.util.Instantiator;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.log.LogMessage;
@ -43,7 +42,8 @@ class ConfigDataLoaders {
private final Log logger;
private final List<ConfigDataLoader<?>> loaders;
@SuppressWarnings("rawtypes")
private final List<ConfigDataLoader> loaders;
private final List<Class<?>> resourceTypes;
@ -51,37 +51,20 @@ class ConfigDataLoaders {
* Create a new {@link ConfigDataLoaders} instance.
* @param logFactory the deferred log factory
* @param bootstrapContext the bootstrap context
* @param classLoader the class loader used when loading
* @param springFactoriesLoader the loader to use
*/
ConfigDataLoaders(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,
ClassLoader classLoader) {
this(logFactory, bootstrapContext, classLoader,
SpringFactoriesLoader.loadFactoryNames(ConfigDataLoader.class, classLoader));
}
/**
* Create a new {@link ConfigDataLoaders} instance.
* @param logFactory the deferred log factory
* @param bootstrapContext the bootstrap context
* @param classLoader the class loader used when loading
* @param names the {@link ConfigDataLoader} class names instantiate
*/
ConfigDataLoaders(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,
ClassLoader classLoader, List<String> names) {
SpringFactoriesLoader springFactoriesLoader) {
this.logger = logFactory.getLog(getClass());
Instantiator<ConfigDataLoader<?>> instantiator = new Instantiator<>(ConfigDataLoader.class,
(availableParameters) -> {
availableParameters.add(Log.class, logFactory::getLog);
availableParameters.add(DeferredLogFactory.class, logFactory);
availableParameters.add(ConfigurableBootstrapContext.class, bootstrapContext);
availableParameters.add(BootstrapContext.class, bootstrapContext);
availableParameters.add(BootstrapRegistry.class, bootstrapContext);
});
this.loaders = instantiator.instantiate(classLoader, names);
SpringFactoriesLoader.ArgumentResolver argumentResolver = SpringFactoriesLoader.ArgumentResolver
.of(DeferredLogFactory.class, logFactory).and(ConfigurableBootstrapContext.class, bootstrapContext)
.and(BootstrapContext.class, bootstrapContext).and(BootstrapRegistry.class, bootstrapContext);
this.loaders = springFactoriesLoader.load(ConfigDataLoader.class, argumentResolver);
this.resourceTypes = getResourceTypes(this.loaders);
}
private List<Class<?>> getResourceTypes(List<ConfigDataLoader<?>> loaders) {
@SuppressWarnings("rawtypes")
private List<Class<?>> getResourceTypes(List<ConfigDataLoader> loaders) {
List<Class<?>> resourceTypes = new ArrayList<>(loaders.size());
for (ConfigDataLoader<?> loader : loaders) {
resourceTypes.add(getResourceType(loader));

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -19,8 +19,6 @@ package org.springframework.boot.context.config;
import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
import org.springframework.boot.BootstrapContext;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.ConfigurableBootstrapContext;
@ -37,8 +35,7 @@ import org.springframework.core.io.ResourceLoader;
* {@code spring.factories} entries. The following constructor parameter types are
* supported:
* <ul>
* <li>{@link Log} or {@link DeferredLogFactory} - if the resolver needs deferred
* logging</li>
* <li>{@link DeferredLogFactory} - if the resolver needs deferred logging</li>
* <li>{@link Binder} - if the resolver needs to obtain values from the initial
* {@link Environment}</li>
* <li>{@link ResourceLoader} - if the resolver needs a resource loader</li>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -28,7 +28,6 @@ import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.boot.util.Instantiator;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
@ -50,37 +49,19 @@ class ConfigDataLocationResolvers {
* @param bootstrapContext the bootstrap context
* @param binder a binder providing values from the initial {@link Environment}
* @param resourceLoader {@link ResourceLoader} to load resource locations
* @param springFactoriesLoader to load {@link ConfigDataLocationResolver} instances
*/
ConfigDataLocationResolvers(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,
Binder binder, ResourceLoader resourceLoader) {
this(logFactory, bootstrapContext, binder, resourceLoader, SpringFactoriesLoader
.loadFactoryNames(ConfigDataLocationResolver.class, resourceLoader.getClassLoader()));
Binder binder, ResourceLoader resourceLoader, SpringFactoriesLoader springFactoriesLoader) {
SpringFactoriesLoader.ArgumentResolver argumentResolver = SpringFactoriesLoader.ArgumentResolver
.of(DeferredLogFactory.class, logFactory).and(Binder.class, binder)
.and(ResourceLoader.class, resourceLoader).and(ConfigurableBootstrapContext.class, bootstrapContext)
.and(BootstrapContext.class, bootstrapContext).and(BootstrapRegistry.class, bootstrapContext);
this.resolvers = reorder(springFactoriesLoader.load(ConfigDataLocationResolver.class, argumentResolver));
}
/**
* Create a new {@link ConfigDataLocationResolvers} instance.
* @param logFactory a {@link DeferredLogFactory} used to inject {@link Log} instances
* @param bootstrapContext the bootstrap context
* @param binder {@link Binder} providing values from the initial {@link Environment}
* @param resourceLoader {@link ResourceLoader} to load resource locations
* @param names the {@link ConfigDataLocationResolver} class names
*/
ConfigDataLocationResolvers(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,
Binder binder, ResourceLoader resourceLoader, List<String> names) {
Instantiator<ConfigDataLocationResolver<?>> instantiator = new Instantiator<>(ConfigDataLocationResolver.class,
(availableParameters) -> {
availableParameters.add(Log.class, logFactory::getLog);
availableParameters.add(DeferredLogFactory.class, logFactory);
availableParameters.add(Binder.class, binder);
availableParameters.add(ResourceLoader.class, resourceLoader);
availableParameters.add(ConfigurableBootstrapContext.class, bootstrapContext);
availableParameters.add(BootstrapContext.class, bootstrapContext);
availableParameters.add(BootstrapRegistry.class, bootstrapContext);
});
this.resolvers = reorder(instantiator.instantiate(resourceLoader.getClassLoader(), names));
}
private List<ConfigDataLocationResolver<?>> reorder(List<ConfigDataLocationResolver<?>> resolvers) {
@SuppressWarnings("rawtypes")
private List<ConfigDataLocationResolver<?>> reorder(List<ConfigDataLocationResolver> resolvers) {
List<ConfigDataLocationResolver<?>> reordered = new ArrayList<>(resolvers.size());
StandardConfigDataLocationResolver resourceResolver = null;
for (ConfigDataLocationResolver<?> resolver : resolvers) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -35,6 +35,7 @@ import org.apache.commons.logging.Log;
import org.springframework.boot.context.config.LocationResourceLoader.ResourceType;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
@ -79,12 +80,13 @@ public class StandardConfigDataLocationResolver
/**
* Create a new {@link StandardConfigDataLocationResolver} instance.
* @param logger the logger to use
* @param logFactory the factory for loggers to use
* @param binder a binder backed by the initial {@link Environment}
* @param resourceLoader a {@link ResourceLoader} used to load resources
*/
public StandardConfigDataLocationResolver(Log logger, Binder binder, ResourceLoader resourceLoader) {
this.logger = logger;
public StandardConfigDataLocationResolver(DeferredLogFactory logFactory, Binder binder,
ResourceLoader resourceLoader) {
this.logger = logFactory.getLog(StandardConfigDataLocationResolver.class);
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
getClass().getClassLoader());
this.configNames = getConfigNames(binder);

View File

@ -25,12 +25,12 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.boot.SpringBootExceptionReporter;
import org.springframework.boot.util.Instantiator;
import org.springframework.boot.util.Instantiator.FailureHandler;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;
import org.springframework.core.io.support.SpringFactoriesLoader.FailureHandler;
import org.springframework.core.log.LogMessage;
import org.springframework.util.StringUtils;
@ -51,41 +51,30 @@ final class FailureAnalyzers implements SpringBootExceptionReporter {
private static final Log logger = LogFactory.getLog(FailureAnalyzers.class);
private final ClassLoader classLoader;
private final SpringFactoriesLoader springFactoriesLoader;
private final List<FailureAnalyzer> analyzers;
FailureAnalyzers(ConfigurableApplicationContext context) {
this(context, SpringFactoriesLoader.loadFactoryNames(FailureAnalyzer.class, getClassLoader(context)));
public FailureAnalyzers(ConfigurableApplicationContext context) {
this(context,
SpringFactoriesLoader.forDefaultResourceLocation((context != null) ? context.getClassLoader() : null));
}
FailureAnalyzers(ConfigurableApplicationContext context, List<String> classNames) {
this.classLoader = getClassLoader(context);
this.analyzers = loadFailureAnalyzers(classNames, context);
FailureAnalyzers(ConfigurableApplicationContext context, SpringFactoriesLoader springFactoriesLoader) {
this.springFactoriesLoader = springFactoriesLoader;
this.analyzers = loadFailureAnalyzers(context, this.springFactoriesLoader);
}
private static ClassLoader getClassLoader(ConfigurableApplicationContext context) {
return (context != null) ? context.getClassLoader() : null;
}
private List<FailureAnalyzer> loadFailureAnalyzers(List<String> classNames,
ConfigurableApplicationContext context) {
Instantiator<FailureAnalyzer> instantiator = new Instantiator<>(FailureAnalyzer.class,
(availableParameters) -> {
if (context != null) {
availableParameters.add(BeanFactory.class, context.getBeanFactory());
availableParameters.add(Environment.class, context.getEnvironment());
}
}, new LoggingInstantiationFailureHandler());
List<FailureAnalyzer> analyzers = instantiator.instantiate(this.classLoader, classNames);
return handleAwareAnalyzers(analyzers, context);
}
private List<FailureAnalyzer> handleAwareAnalyzers(List<FailureAnalyzer> analyzers,
ConfigurableApplicationContext context) {
private static List<FailureAnalyzer> loadFailureAnalyzers(ConfigurableApplicationContext context,
SpringFactoriesLoader springFactoriesLoader) {
ArgumentResolver argumentResolver = (context != null) ? ArgumentResolver
.of(BeanFactory.class, context.getBeanFactory()).and(Environment.class, context.getEnvironment())
: null;
List<FailureAnalyzer> analyzers = springFactoriesLoader.load(FailureAnalyzer.class, argumentResolver,
FailureHandler.logging(logger));
List<FailureAnalyzer> awareAnalyzers = analyzers.stream()
.filter((analyzer) -> analyzer instanceof BeanFactoryAware || analyzer instanceof EnvironmentAware)
.collect(Collectors.toList());
.toList();
if (!awareAnalyzers.isEmpty()) {
String awareAnalyzerNames = StringUtils.collectionToCommaDelimitedString(awareAnalyzers.stream()
.map((analyzer) -> analyzer.getClass().getName()).collect(Collectors.toList()));
@ -115,7 +104,7 @@ final class FailureAnalyzers implements SpringBootExceptionReporter {
@Override
public boolean reportException(Throwable failure) {
FailureAnalysis analysis = analyze(failure, this.analyzers);
return report(analysis, this.classLoader);
return report(analysis);
}
private FailureAnalysis analyze(Throwable failure, List<FailureAnalyzer> analyzers) {
@ -133,9 +122,8 @@ final class FailureAnalyzers implements SpringBootExceptionReporter {
return null;
}
private boolean report(FailureAnalysis analysis, ClassLoader classLoader) {
List<FailureAnalysisReporter> reporters = SpringFactoriesLoader.loadFactories(FailureAnalysisReporter.class,
classLoader);
private boolean report(FailureAnalysis analysis) {
List<FailureAnalysisReporter> reporters = this.springFactoriesLoader.load(FailureAnalysisReporter.class);
if (analysis == null || reporters.isEmpty()) {
return false;
}
@ -145,13 +133,4 @@ final class FailureAnalyzers implements SpringBootExceptionReporter {
return true;
}
static class LoggingInstantiationFailureHandler implements FailureHandler {
@Override
public void handleFailure(Class<?> type, String implementationName, Throwable failure) {
logger.trace(LogMessage.format("Skipping %s: %s", implementationName, failure.getMessage()));
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -16,8 +16,6 @@
package org.springframework.boot.env;
import org.apache.commons.logging.Log;
import org.springframework.boot.BootstrapContext;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.ConfigurableBootstrapContext;
@ -42,8 +40,6 @@ import org.springframework.core.env.Environment;
* <li>{@link DeferredLogFactory} - A factory that can be used to create loggers with
* output deferred until the application has been fully prepared (allowing the environment
* itself to configure logging levels).</li>
* <li>{@link Log} - A log with output deferred until the application has been fully
* prepared (allowing the environment itself to configure logging levels).</li>
* <li>{@link ConfigurableBootstrapContext} - A bootstrap context that can be used to
* store objects that may be expensive to create, or need to be shared
* ({@link BootstrapContext} or {@link BootstrapRegistry} may also be used).</li>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -56,7 +56,7 @@ public class EnvironmentPostProcessorApplicationListener implements SmartApplica
* {@link EnvironmentPostProcessor} classes loaded via {@code spring.factories}.
*/
public EnvironmentPostProcessorApplicationListener() {
this((classLoader) -> EnvironmentPostProcessorsFactory.fromSpringFactories(classLoader), new DeferredLogs());
this((classLoader) -> EnvironmentPostProcessorsFactory.fromSpringFactories(classLoader));
}
/**
@ -64,14 +64,21 @@ public class EnvironmentPostProcessorApplicationListener implements SmartApplica
* processors created by the given factory.
* @param postProcessorsFactory the post processors factory
*/
public EnvironmentPostProcessorApplicationListener(EnvironmentPostProcessorsFactory postProcessorsFactory) {
this((classloader) -> postProcessorsFactory, new DeferredLogs());
private EnvironmentPostProcessorApplicationListener(
Function<ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory) {
this.postProcessorsFactory = postProcessorsFactory;
this.deferredLogs = new DeferredLogs();
}
EnvironmentPostProcessorApplicationListener(
Function<ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory, DeferredLogs deferredLogs) {
this.postProcessorsFactory = postProcessorsFactory;
this.deferredLogs = deferredLogs;
/**
* Factory method that creates an {@link EnvironmentPostProcessorApplicationListener}
* with a specific {@link EnvironmentPostProcessorsFactory}.
* @param postProcessorsFactory the environment post processor factory
* @return an {@link EnvironmentPostProcessorApplicationListener} instance
*/
public static EnvironmentPostProcessorApplicationListener with(
EnvironmentPostProcessorsFactory postProcessorsFactory) {
return new EnvironmentPostProcessorApplicationListener((classloader) -> postProcessorsFactory);
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -48,8 +48,8 @@ public interface EnvironmentPostProcessorsFactory {
* @return an {@link EnvironmentPostProcessorsFactory} instance
*/
static EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) {
return new ReflectionEnvironmentPostProcessorsFactory(classLoader,
SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, classLoader));
return new SpringFactoriesEnvironmentPostProcessorsFactory(
SpringFactoriesLoader.forDefaultResourceLocation(classLoader));
}
/**

View File

@ -19,6 +19,7 @@ package org.springframework.boot.env;
import org.apache.commons.logging.Log;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
@ -39,10 +40,11 @@ public class RandomValuePropertySourceEnvironmentPostProcessor implements Enviro
/**
* Create a new {@link RandomValuePropertySourceEnvironmentPostProcessor} instance.
* @param logger the logger to use
* @param logFactory the log factory to use
* @since 3.0.0
*/
public RandomValuePropertySourceEnvironmentPostProcessor(Log logger) {
this.logger = logger;
public RandomValuePropertySourceEnvironmentPostProcessor(DeferredLogFactory logFactory) {
this.logger = logFactory.getLog(RandomValuePropertySourceEnvironmentPostProcessor.class);
}
@Override

View File

@ -0,0 +1,49 @@
/*
* Copyright 2012-2022 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.boot.env;
import java.util.List;
import org.springframework.boot.BootstrapContext;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.io.support.SpringFactoriesLoader;
/**
* An {@link EnvironmentPostProcessorsFactory} that uses {@link SpringFactoriesLoader}.
*
* @author Andy Wilkinson
*/
class SpringFactoriesEnvironmentPostProcessorsFactory implements EnvironmentPostProcessorsFactory {
private final SpringFactoriesLoader loader;
SpringFactoriesEnvironmentPostProcessorsFactory(SpringFactoriesLoader loader) {
this.loader = loader;
}
@Override
public List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory,
ConfigurableBootstrapContext bootstrapContext) {
SpringFactoriesLoader.ArgumentResolver argumentResolver = SpringFactoriesLoader.ArgumentResolver
.of(DeferredLogFactory.class, logFactory).and(ConfigurableBootstrapContext.class, bootstrapContext)
.and(BootstrapContext.class, bootstrapContext).and(BootstrapRegistry.class, bootstrapContext);
return this.loader.load(EnvironmentPostProcessor.class, argumentResolver);
}
}

View File

@ -33,7 +33,6 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.util.Instantiator;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
@ -151,10 +150,10 @@ public class DatabaseInitializationDependencyConfigurer implements ImportBeanDef
}
private <T> List<T> getDetectors(ConfigurableListableBeanFactory beanFactory, Class<T> type) {
List<String> names = SpringFactoriesLoader.loadFactoryNames(type, beanFactory.getBeanClassLoader());
Instantiator<T> instantiator = new Instantiator<>(type,
(availableParameters) -> availableParameters.add(Environment.class, this.environment));
return instantiator.instantiate(beanFactory.getBeanClassLoader(), names);
SpringFactoriesLoader.ArgumentResolver argumentResolver = SpringFactoriesLoader.ArgumentResolver
.of(Environment.class, this.environment);
return SpringFactoriesLoader.forDefaultResourceLocation(beanFactory.getBeanClassLoader()).load(type,
argumentResolver);
}
private static BeanDefinition getBeanDefinition(String beanName, ConfigurableListableBeanFactory beanFactory) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2022 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.
@ -16,7 +16,8 @@
package org.springframework.boot.cloud.cloudfoundry;
import org.apache.commons.logging.LogFactory;
import java.util.function.Supplier;
import org.junit.jupiter.api.Test;
import org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor;
@ -35,7 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class CloudFoundryVcapEnvironmentPostProcessorTests {
private final CloudFoundryVcapEnvironmentPostProcessor initializer = new CloudFoundryVcapEnvironmentPostProcessor(
LogFactory.getLog(getClass()));
Supplier::get);
private final ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();

View File

@ -39,6 +39,7 @@ import org.springframework.boot.context.properties.bind.BindException;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.mock.env.MockPropertySource;
@ -86,9 +87,10 @@ class ConfigDataEnvironmentContributorsTests {
this.environment = new MockEnvironment();
this.binder = Binder.get(this.environment);
ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,
this.binder, new DefaultResourceLoader(getClass().getClassLoader()));
this.binder, new DefaultResourceLoader(getClass().getClassLoader()),
SpringFactoriesLoader.forDefaultResourceLocation(getClass().getClassLoader()));
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,
getClass().getClassLoader());
SpringFactoriesLoader.forDefaultResourceLocation());
this.importer = new ConfigDataImporter(this.logFactory, ConfigDataNotFoundAction.FAIL, resolvers, loaders);
this.activationContext = new ConfigDataActivationContext(CloudPlatform.KUBERNETES, null);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -16,13 +16,14 @@
package org.springframework.boot.context.config;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.BootstrapContext;
import org.springframework.boot.BootstrapRegistry;
@ -30,6 +31,7 @@ import org.springframework.boot.BootstrapRegistry.InstanceSupplier;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.DefaultBootstrapContext;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.boot.testsupport.mock.MockSpringFactoriesLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.env.MockPropertySource;
@ -51,16 +53,15 @@ class ConfigDataLoadersTests {
private ConfigDataLoaderContext context = mock(ConfigDataLoaderContext.class);
@Test
void createWhenLoaderHasLogParameterInjectsLog() {
new ConfigDataLoaders(this.logFactory, this.bootstrapContext, null,
Arrays.asList(LoggingConfigDataLoader.class.getName()));
}
@TempDir
private File tempDir;
@Test
void createWhenLoaderHasDeferredLogFactoryParameterInjectsDeferredLogFactory() {
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext, null,
Arrays.asList(DeferredLogFactoryConfigDataLoader.class.getName()));
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLoader.class, DeferredLogFactoryConfigDataLoader.class);
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,
springFactoriesLoader);
assertThat(loaders).extracting("loaders").asList()
.satisfies(this::containsValidDeferredLogFactoryConfigDataLoader);
}
@ -73,43 +74,52 @@ class ConfigDataLoadersTests {
@Test
void createWhenLoaderHasBootstrapParametersInjectsBootstrapContext() {
new ConfigDataLoaders(this.logFactory, this.bootstrapContext, null,
Arrays.asList(BootstrappingConfigDataLoader.class.getName()));
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLoader.class, BootstrappingConfigDataLoader.class);
new ConfigDataLoaders(this.logFactory, this.bootstrapContext, springFactoriesLoader);
assertThat(this.bootstrapContext.get(String.class)).isEqualTo("boot");
}
@Test
void loadWhenSingleLoaderSupportsLocationReturnsLoadedConfigData() throws Exception {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLoader.class, TestConfigDataLoader.class);
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,
springFactoriesLoader);
TestConfigDataResource location = new TestConfigDataResource("test");
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext, null,
Arrays.asList(TestConfigDataLoader.class.getName()));
ConfigData loaded = loaders.load(this.context, location);
assertThat(getLoader(loaded)).isInstanceOf(TestConfigDataLoader.class);
}
@Test
void loadWhenMultipleLoadersSupportLocationThrowsException() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLoader.class, AnotherConfigDataLoader.class, TestConfigDataLoader.class);
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,
springFactoriesLoader);
TestConfigDataResource location = new TestConfigDataResource("test");
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext, null,
Arrays.asList(LoggingConfigDataLoader.class.getName(), TestConfigDataLoader.class.getName()));
assertThatIllegalStateException().isThrownBy(() -> loaders.load(this.context, location))
.withMessageContaining("Multiple loaders found for resource 'test'");
}
@Test
void loadWhenNoLoaderSupportsLocationThrowsException() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLoader.class, NonLoadableConfigDataLoader.class);
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,
springFactoriesLoader);
TestConfigDataResource location = new TestConfigDataResource("test");
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext, null,
Arrays.asList(NonLoadableConfigDataLoader.class.getName()));
assertThatIllegalStateException().isThrownBy(() -> loaders.load(this.context, location))
.withMessage("No loader found for resource 'test'");
}
@Test
void loadWhenGenericTypeDoesNotMatchSkipsLoader() throws Exception {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLoader.class, OtherConfigDataLoader.class, SpecificConfigDataLoader.class);
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,
springFactoriesLoader);
TestConfigDataResource location = new TestConfigDataResource("test");
ConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext, null,
Arrays.asList(OtherConfigDataLoader.class.getName(), SpecificConfigDataLoader.class.getName()));
ConfigData loaded = loaders.load(this.context, location);
assertThat(getLoader(loaded)).isInstanceOf(SpecificConfigDataLoader.class);
}
@ -145,19 +155,6 @@ class ConfigDataLoadersTests {
}
static class LoggingConfigDataLoader implements ConfigDataLoader<ConfigDataResource> {
LoggingConfigDataLoader(Log log) {
assertThat(log).isNotNull();
}
@Override
public ConfigData load(ConfigDataLoaderContext context, ConfigDataResource resource) throws IOException {
throw new AssertionError("Unexpected call");
}
}
static class DeferredLogFactoryConfigDataLoader implements ConfigDataLoader<ConfigDataResource> {
private final DeferredLogFactory logFactory;
@ -205,6 +202,15 @@ class ConfigDataLoadersTests {
}
static class AnotherConfigDataLoader implements ConfigDataLoader<ConfigDataResource> {
@Override
public ConfigData load(ConfigDataLoaderContext context, ConfigDataResource resource) throws IOException {
return createConfigData(this, resource);
}
}
static class NonLoadableConfigDataLoader extends TestConfigDataLoader {
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -16,16 +16,14 @@
package org.springframework.boot.context.config;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ -36,14 +34,13 @@ import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.DefaultBootstrapContext;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.boot.testsupport.mock.MockSpringFactoriesLoader;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link ConfigDataLocationResolvers}.
@ -67,23 +64,27 @@ class ConfigDataLocationResolversTests {
@Mock
private Profiles profiles;
private ResourceLoader resourceLoader = new DefaultResourceLoader();
@TempDir
private File tempDir;
@Test
void createWhenInjectingLogAndDeferredLogFactoryCreatesResolver() {
void createWhenInjectingDeferredLogFactoryCreatesResolver() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLocationResolver.class, TestLogResolver.class);
ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,
this.binder, this.resourceLoader, Collections.singletonList(TestLogResolver.class.getName()));
this.binder, new DefaultResourceLoader(), springFactoriesLoader);
assertThat(resolvers.getResolvers()).hasSize(1);
assertThat(resolvers.getResolvers().get(0)).isExactlyInstanceOf(TestLogResolver.class);
TestLogResolver resolver = (TestLogResolver) resolvers.getResolvers().get(0);
assertThat(resolver.getDeferredLogFactory()).isSameAs(this.logFactory);
assertThat(resolver.getLog()).isNotNull();
}
@Test
void createWhenInjectingBinderCreatesResolver() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLocationResolver.class, TestBoundResolver.class);
ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,
this.binder, this.resourceLoader, Collections.singletonList(TestBoundResolver.class.getName()));
this.binder, new DefaultResourceLoader(), springFactoriesLoader);
assertThat(resolvers.getResolvers()).hasSize(1);
assertThat(resolvers.getResolvers().get(0)).isExactlyInstanceOf(TestBoundResolver.class);
assertThat(((TestBoundResolver) resolvers.getResolvers().get(0)).getBinder()).isSameAs(this.binder);
@ -91,35 +92,30 @@ class ConfigDataLocationResolversTests {
@Test
void createWhenNotInjectingBinderCreatesResolver() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLocationResolver.class, TestResolver.class);
ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,
this.binder, this.resourceLoader, Collections.singletonList(TestResolver.class.getName()));
this.binder, new DefaultResourceLoader(), springFactoriesLoader);
assertThat(resolvers.getResolvers()).hasSize(1);
assertThat(resolvers.getResolvers().get(0)).isExactlyInstanceOf(TestResolver.class);
}
@Test
void createWhenResolverHasBootstrapParametersInjectsBootstrapContext() {
new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext, this.binder, this.resourceLoader,
Collections.singletonList(TestBootstrappingResolver.class.getName()));
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLocationResolver.class, TestBootstrappingResolver.class);
new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext, this.binder,
new DefaultResourceLoader(), springFactoriesLoader);
assertThat(this.bootstrapContext.get(String.class)).isEqualTo("boot");
}
@Test
void createWhenNameIsNotConfigDataLocationResolverThrowsException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext, this.binder,
this.resourceLoader, Collections.singletonList(InputStream.class.getName())))
.withMessageContaining("Unable to instantiate").havingCause().withMessageContaining("not assignable");
}
@Test
void createOrdersResolvers() {
List<String> names = new ArrayList<>();
names.add(TestResolver.class.getName());
names.add(LowestTestResolver.class.getName());
names.add(HighestTestResolver.class.getName());
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLocationResolver.class, TestResolver.class, LowestTestResolver.class,
HighestTestResolver.class);
ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,
this.binder, this.resourceLoader, names);
this.binder, new DefaultResourceLoader(), springFactoriesLoader);
assertThat(resolvers.getResolvers().get(0)).isExactlyInstanceOf(HighestTestResolver.class);
assertThat(resolvers.getResolvers().get(1)).isExactlyInstanceOf(TestResolver.class);
assertThat(resolvers.getResolvers().get(2)).isExactlyInstanceOf(LowestTestResolver.class);
@ -127,9 +123,11 @@ class ConfigDataLocationResolversTests {
@Test
void resolveResolvesUsingFirstSupportedResolver() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLocationResolver.class, LowestTestResolver.class,
HighestTestResolver.class);
ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,
this.binder, this.resourceLoader,
Arrays.asList(LowestTestResolver.class.getName(), HighestTestResolver.class.getName()));
this.binder, new DefaultResourceLoader(), springFactoriesLoader);
ConfigDataLocation location = ConfigDataLocation.of("LowestTestResolver:test");
List<ConfigDataResolutionResult> resolved = resolvers.resolve(this.context, location, null);
assertThat(resolved).hasSize(1);
@ -141,9 +139,11 @@ class ConfigDataLocationResolversTests {
@Test
void resolveWhenProfileMergesResolvedLocations() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLocationResolver.class, LowestTestResolver.class,
HighestTestResolver.class);
ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,
this.binder, this.resourceLoader,
Arrays.asList(LowestTestResolver.class.getName(), HighestTestResolver.class.getName()));
this.binder, new DefaultResourceLoader(), springFactoriesLoader);
ConfigDataLocation location = ConfigDataLocation.of("LowestTestResolver:test");
List<ConfigDataResolutionResult> resolved = resolvers.resolve(this.context, location, this.profiles);
assertThat(resolved).hasSize(2);
@ -159,9 +159,11 @@ class ConfigDataLocationResolversTests {
@Test
void resolveWhenNoResolverThrowsException() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLocationResolver.class, LowestTestResolver.class,
HighestTestResolver.class);
ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,
this.binder, this.resourceLoader,
Arrays.asList(LowestTestResolver.class.getName(), HighestTestResolver.class.getName()));
this.binder, new DefaultResourceLoader(), springFactoriesLoader);
ConfigDataLocation location = ConfigDataLocation.of("Missing:test");
assertThatExceptionOfType(UnsupportedConfigDataLocationException.class)
.isThrownBy(() -> resolvers.resolve(this.context, location, null))
@ -170,8 +172,10 @@ class ConfigDataLocationResolversTests {
@Test
void resolveWhenOptional() {
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();
springFactoriesLoader.add(ConfigDataLocationResolver.class, OptionalResourceTestResolver.class);
ConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,
this.binder, this.resourceLoader, Arrays.asList(OptionalResourceTestResolver.class.getName()));
this.binder, new DefaultResourceLoader(), springFactoriesLoader);
ConfigDataLocation location = ConfigDataLocation.of("OptionalResourceTestResolver:test");
List<ConfigDataResolutionResult> resolved = resolvers.resolve(this.context, location, null);
assertThat(resolved.get(0).getResource().isOptional()).isTrue();
@ -185,7 +189,7 @@ class ConfigDataLocationResolversTests {
this(false);
}
TestResolver(boolean optionalResource) {
private TestResolver(boolean optionalResource) {
this.optionalResource = optionalResource;
}
@ -214,21 +218,14 @@ class ConfigDataLocationResolversTests {
private final DeferredLogFactory deferredLogFactory;
private final Log log;
TestLogResolver(DeferredLogFactory deferredLogFactory, Log log) {
TestLogResolver(DeferredLogFactory deferredLogFactory) {
this.deferredLogFactory = deferredLogFactory;
this.log = log;
}
DeferredLogFactory getDeferredLogFactory() {
return this.deferredLogFactory;
}
Log getLog() {
return this.log;
}
}
static class TestBoundResolver extends TestResolver {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.logging.DeferredLog;
import org.springframework.boot.logging.DeferredLogs;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.DefaultResourceLoader;
@ -60,7 +60,7 @@ class StandardConfigDataLocationResolverTests {
void setup() {
this.environment = new MockEnvironment();
this.environmentBinder = Binder.get(this.environment);
this.resolver = new StandardConfigDataLocationResolver(new DeferredLog(), this.environmentBinder,
this.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
this.resourceLoader);
}
@ -115,8 +115,8 @@ class StandardConfigDataLocationResolverTests {
void createWhenConfigNameHasWildcardThrowsException() {
this.environment.setProperty("spring.config.name", "*/application");
assertThatIllegalStateException()
.isThrownBy(
() -> new StandardConfigDataLocationResolver(null, this.environmentBinder, this.resourceLoader))
.isThrownBy(() -> new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
this.resourceLoader))
.withMessageStartingWith("Config name '").withMessageEndingWith("' cannot contain '*'");
}
@ -131,7 +131,8 @@ class StandardConfigDataLocationResolverTests {
void resolveWhenLocationIsWildcardDirectoriesRestrictsToOneLevelDeep() {
ConfigDataLocation location = ConfigDataLocation.of("file:src/test/resources/config/*/");
this.environment.setProperty("spring.config.name", "testproperties");
this.resolver = new StandardConfigDataLocationResolver(null, this.environmentBinder, this.resourceLoader);
this.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
this.resourceLoader);
List<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);
assertThat(locations.size()).isEqualTo(3);
assertThat(locations).extracting(Object::toString)
@ -144,7 +145,8 @@ class StandardConfigDataLocationResolverTests {
void resolveWhenLocationIsWildcardDirectoriesSortsAlphabeticallyBasedOnAbsolutePath() {
ConfigDataLocation location = ConfigDataLocation.of("file:src/test/resources/config/*/");
this.environment.setProperty("spring.config.name", "testproperties");
this.resolver = new StandardConfigDataLocationResolver(null, this.environmentBinder, this.resourceLoader);
this.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
this.resourceLoader);
List<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);
assertThat(locations).extracting(Object::toString).containsExactly(
filePath("src", "test", "resources", "config", "0-empty", "testproperties.properties"),
@ -175,7 +177,7 @@ class StandardConfigDataLocationResolverTests {
void resolveWhenLocationIsRelativeAndFileResolves() {
this.environment.setProperty("spring.config.name", "other");
ConfigDataLocation location = ConfigDataLocation.of("other.properties");
this.resolver = new StandardConfigDataLocationResolver(new DeferredLog(), this.environmentBinder,
this.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
this.resourceLoader);
StandardConfigDataReference parentReference = new StandardConfigDataReference(
ConfigDataLocation.of("classpath:configdata/properties/application.properties"), null,
@ -194,7 +196,7 @@ class StandardConfigDataLocationResolverTests {
void resolveWhenLocationIsRelativeAndDirectoryResolves() {
this.environment.setProperty("spring.config.name", "testproperties");
ConfigDataLocation location = ConfigDataLocation.of("nested/3-third/");
this.resolver = new StandardConfigDataLocationResolver(new DeferredLog(), this.environmentBinder,
this.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,
this.resourceLoader);
StandardConfigDataReference parentReference = new StandardConfigDataReference(
ConfigDataLocation.of("optional:classpath:configdata/"), null, "classpath:config/specific", null,

View File

@ -16,14 +16,13 @@
package org.springframework.boot.diagnostics;
import java.util.Arrays;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.boot.testsupport.mock.MockSpringFactoriesLoader;
import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
import org.springframework.context.EnvironmentAware;
@ -58,15 +57,14 @@ class FailureAnalyzersTests {
@Test
void analyzersAreLoadedAndCalled() {
RuntimeException failure = new RuntimeException();
analyzeAndReport(failure, BasicFailureAnalyzer.class.getName(), BasicFailureAnalyzer.class.getName());
analyzeAndReport(failure, BasicFailureAnalyzer.class, StandardAwareFailureAnalyzer.class);
then(failureAnalyzer).should(times(2)).analyze(failure);
}
@Test
void analyzerIsConstructedWithBeanFactory(CapturedOutput output) {
RuntimeException failure = new RuntimeException();
analyzeAndReport(failure, BasicFailureAnalyzer.class.getName(),
BeanFactoryConstructorFailureAnalyzer.class.getName());
analyzeAndReport(failure, BasicFailureAnalyzer.class, BeanFactoryConstructorFailureAnalyzer.class);
then(failureAnalyzer).should(times(2)).analyze(failure);
assertThat(output).doesNotContain("implement BeanFactoryAware or EnvironmentAware");
}
@ -74,8 +72,7 @@ class FailureAnalyzersTests {
@Test
void analyzerIsConstructedWithEnvironment(CapturedOutput output) {
RuntimeException failure = new RuntimeException();
analyzeAndReport(failure, BasicFailureAnalyzer.class.getName(),
EnvironmentConstructorFailureAnalyzer.class.getName());
analyzeAndReport(failure, BasicFailureAnalyzer.class, EnvironmentConstructorFailureAnalyzer.class);
then(failureAnalyzer).should(times(2)).analyze(failure);
assertThat(output).doesNotContain("implement BeanFactoryAware or EnvironmentAware");
}
@ -83,7 +80,7 @@ class FailureAnalyzersTests {
@Test
void beanFactoryIsInjectedIntoBeanFactoryAwareFailureAnalyzers(CapturedOutput output) {
RuntimeException failure = new RuntimeException();
analyzeAndReport(failure, BasicFailureAnalyzer.class.getName(), StandardAwareFailureAnalyzer.class.getName());
analyzeAndReport(failure, BasicFailureAnalyzer.class, StandardAwareFailureAnalyzer.class);
then(failureAnalyzer).should().setBeanFactory(same(this.context.getBeanFactory()));
assertThat(output).contains("FailureAnalyzers [" + StandardAwareFailureAnalyzer.class.getName()
+ "] implement BeanFactoryAware or EnvironmentAware.");
@ -92,41 +89,37 @@ class FailureAnalyzersTests {
@Test
void environmentIsInjectedIntoEnvironmentAwareFailureAnalyzers() {
RuntimeException failure = new RuntimeException();
analyzeAndReport(failure, BasicFailureAnalyzer.class.getName(), StandardAwareFailureAnalyzer.class.getName());
analyzeAndReport(failure, BasicFailureAnalyzer.class, StandardAwareFailureAnalyzer.class);
then(failureAnalyzer).should().setEnvironment(same(this.context.getEnvironment()));
}
@Test
void analyzerThatFailsDuringInitializationDoesNotPreventOtherAnalyzersFromBeingCalled() {
RuntimeException failure = new RuntimeException();
analyzeAndReport(failure, BrokenInitializationFailureAnalyzer.class.getName(),
BasicFailureAnalyzer.class.getName());
analyzeAndReport(failure, BrokenInitializationFailureAnalyzer.class, BasicFailureAnalyzer.class);
then(failureAnalyzer).should().analyze(failure);
}
@Test
void analyzerThatFailsDuringAnalysisDoesNotPreventOtherAnalyzersFromBeingCalled() {
RuntimeException failure = new RuntimeException();
analyzeAndReport(failure, BrokenAnalysisFailureAnalyzer.class.getName(), BasicFailureAnalyzer.class.getName());
analyzeAndReport(failure, BrokenAnalysisFailureAnalyzer.class, BasicFailureAnalyzer.class);
then(failureAnalyzer).should().analyze(failure);
}
@Test
void createWithNullContextSkipsAwareAnalyzers() {
RuntimeException failure = new RuntimeException();
analyzeAndReport(failure, (AnnotationConfigApplicationContext) null, BasicFailureAnalyzer.class.getName(),
BeanFactoryConstructorFailureAnalyzer.class.getName(),
EnvironmentConstructorFailureAnalyzer.class.getName(), StandardAwareFailureAnalyzer.class.getName());
then(failureAnalyzer).should().analyze(failure);
}
private void analyzeAndReport(Throwable failure, String... factoryNames) {
analyzeAndReport(failure, this.context, factoryNames);
@SafeVarargs
private void analyzeAndReport(Throwable failure, Class<? extends FailureAnalyzer>... failureAnalyzerClasses) {
analyzeAndReport(failure, this.context, failureAnalyzerClasses);
}
@SafeVarargs
private void analyzeAndReport(Throwable failure, AnnotationConfigApplicationContext context,
String... factoryNames) {
new FailureAnalyzers(context, Arrays.asList(factoryNames)).reportException(failure);
Class<? extends FailureAnalyzer>... failureAnalyzerClasses) {
MockSpringFactoriesLoader loader = new MockSpringFactoriesLoader();
for (Class<? extends FailureAnalyzer> failureAnalyzerClass : failureAnalyzerClasses) {
loader.add(FailureAnalyzer.class, failureAnalyzerClass);
}
new FailureAnalyzers(context, loader).reportException(failure);
}
static class BasicFailureAnalyzer implements FailureAnalyzer {

View File

@ -17,7 +17,9 @@
package org.springframework.boot.env;
import java.util.List;
import java.util.function.Function;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.BootstrapRegistry;
@ -32,6 +34,7 @@ import org.springframework.boot.logging.DeferredLogs;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.then;
@ -49,9 +52,15 @@ class EnvironmentPostProcessorApplicationListenerTests {
private DefaultBootstrapContext bootstrapContext = spy(new DefaultBootstrapContext());
private EnvironmentPostProcessorApplicationListener listener = new EnvironmentPostProcessorApplicationListener(
(classLoader) -> EnvironmentPostProcessorsFactory.of(TestEnvironmentPostProcessor.class),
this.deferredLogs);
private EnvironmentPostProcessorApplicationListener listener = new EnvironmentPostProcessorApplicationListener();
@BeforeEach
void setup() {
ReflectionTestUtils.setField(this.listener, "deferredLogs", this.deferredLogs);
ReflectionTestUtils.setField(this.listener, "postProcessorsFactory",
(Function<ClassLoader, EnvironmentPostProcessorsFactory>) (
classLoader) -> EnvironmentPostProcessorsFactory.of(TestEnvironmentPostProcessor.class));
}
@Test
void createUsesSpringFactories() {
@ -61,8 +70,8 @@ class EnvironmentPostProcessorApplicationListenerTests {
@Test
void createWhenHasFactoryUsesFactory() {
EnvironmentPostProcessorApplicationListener listener = new EnvironmentPostProcessorApplicationListener(
EnvironmentPostProcessorsFactory.of(TestEnvironmentPostProcessor.class));
EnvironmentPostProcessorApplicationListener listener = EnvironmentPostProcessorApplicationListener
.with(EnvironmentPostProcessorsFactory.of(TestEnvironmentPostProcessor.class));
List<EnvironmentPostProcessor> postProcessors = listener.getEnvironmentPostProcessors(null,
this.bootstrapContext);
assertThat(postProcessors).hasSize(1);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2022 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.
@ -16,7 +16,8 @@
package org.springframework.boot.env;
import org.apache.commons.logging.LogFactory;
import java.util.function.Supplier;
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
@ -34,7 +35,7 @@ import static org.mockito.Mockito.mock;
class RandomValuePropertySourceEnvironmentPostProcessorTests {
private RandomValuePropertySourceEnvironmentPostProcessor postProcessor = new RandomValuePropertySourceEnvironmentPostProcessor(
LogFactory.getLog(getClass()));
Supplier::get);
@Test
void getOrderIsBeforeConfigData() {

View File

@ -59,4 +59,5 @@
<suppress files="DeprecatedReactiveElasticsearchRestClientProperties\.java" checks="SpringMethodVisibility" />
<suppress files="DevToolsR2dbcAutoConfigurationTests" checks="HideUtilityClassConstructor" />
<suppress files="AbstractLaunchScriptIntegrationTests" checks="IllegalImport" />
<suppress files="FailureAnalyzers\.java" checks="RedundantModifier" />
</suppressions>