Add EnvironmentPostProcessorsFactory

Update `EnvironmentPostProcessorApplicationListener` so that it can
either use values from `spring.factories` or use a factory interface.

Closes gh-22529
This commit is contained in:
Phillip Webb 2020-07-23 11:40:49 -07:00
parent 5800f1596c
commit 36a6ca6e6e
7 changed files with 537 additions and 86 deletions

View File

@ -33,6 +33,7 @@ import org.springframework.boot.devtools.restart.RestartInitializer;
import org.springframework.boot.devtools.restart.RestartScopeInitializer;
import org.springframework.boot.devtools.restart.Restarter;
import org.springframework.boot.env.EnvironmentPostProcessorApplicationListener;
import org.springframework.boot.env.EnvironmentPostProcessorsFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.core.io.ClassPathResource;
@ -72,7 +73,8 @@ public final class RemoteSpringApplication {
private Collection<ApplicationListener<?>> getListeners() {
List<ApplicationListener<?>> listeners = new ArrayList<>();
listeners.add(new AnsiOutputApplicationListener());
listeners.add(new EnvironmentPostProcessorApplicationListener(ConfigDataEnvironmentPostProcessor.class));
listeners.add(new EnvironmentPostProcessorApplicationListener(
EnvironmentPostProcessorsFactory.singleton(ConfigDataEnvironmentPostProcessor::new)));
listeners.add(new ClasspathLoggingApplicationListener());
listeners.add(new LoggingApplicationListener());
listeners.add(new RemoteUrlPropertyExtractor());

View File

@ -16,29 +16,17 @@
package org.springframework.boot.env;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.boot.logging.DeferredLogs;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* {@link SmartApplicationListener} used to trigger {@link EnvironmentPostProcessor
@ -54,46 +42,34 @@ public class EnvironmentPostProcessorApplicationListener implements SmartApplica
*/
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;
private final DeferredLogs deferredLogs = new DeferredLogs();
private final DeferredLogs deferredLogs;
private int order = DEFAULT_ORDER;
private final List<String> postProcessorClassNames;
private EnvironmentPostProcessorsFactory postProcessorsFactory;
/**
* Create a new {@link EnvironmentPostProcessorApplicationListener} with
* {@link EnvironmentPostProcessor} classes loaded via {@code spring.factories}.
*/
public EnvironmentPostProcessorApplicationListener() {
this(SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class,
EnvironmentPostProcessorApplicationListener.class.getClassLoader()));
this(EnvironmentPostProcessorsFactory
.fromSpringFactories(EnvironmentPostProcessorApplicationListener.class.getClassLoader()));
}
/**
* Create a new {@link EnvironmentPostProcessorApplicationListener} with the specified
* {@link EnvironmentPostProcessor} classes.
* @param postProcessorClasses the environment post processor classes
* Create a new {@link EnvironmentPostProcessorApplicationListener} with post
* processors created by the given factory.
* @param postProcessorsFactory the post processors factory
*/
public EnvironmentPostProcessorApplicationListener(Class<?>... postProcessorClasses) {
this(Arrays.stream(postProcessorClasses).map(Class::getName).collect(Collectors.toList()));
public EnvironmentPostProcessorApplicationListener(EnvironmentPostProcessorsFactory postProcessorsFactory) {
this(postProcessorsFactory, new DeferredLogs());
}
/**
* Create a new {@link EnvironmentPostProcessorApplicationListener} with the specified
* {@link EnvironmentPostProcessor} class names.
* @param postProcessorClassNames the environment post processor class names
*/
public EnvironmentPostProcessorApplicationListener(String... postProcessorClassNames) {
this(Arrays.asList(postProcessorClassNames));
}
/**
* Create a new {@link EnvironmentPostProcessorApplicationListener} with the specified
* {@link EnvironmentPostProcessor} class names.
* @param postProcessorClassNames the environment post processor class names
*/
public EnvironmentPostProcessorApplicationListener(List<String> postProcessorClassNames) {
this.postProcessorClassNames = postProcessorClassNames;
EnvironmentPostProcessorApplicationListener(EnvironmentPostProcessorsFactory postProcessorsFactory,
DeferredLogs deferredLogs) {
this.postProcessorsFactory = postProcessorsFactory;
this.deferredLogs = deferredLogs;
}
@Override
@ -108,64 +84,24 @@ public class EnvironmentPostProcessorApplicationListener implements SmartApplica
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
if (event instanceof ApplicationPreparedEvent || event instanceof ApplicationFailedEvent) {
onFinish();
}
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
SpringApplication application = event.getSpringApplication();
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors(event.getSpringApplication());
for (EnvironmentPostProcessor postProcessor : postProcessors) {
for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors()) {
postProcessor.postProcessEnvironment(environment, application);
}
}
private List<EnvironmentPostProcessor> loadPostProcessors(SpringApplication application) {
return loadPostProcessors(application, this.postProcessorClassNames);
List<EnvironmentPostProcessor> getEnvironmentPostProcessors() {
return this.postProcessorsFactory.getEnvironmentPostProcessors(this.deferredLogs);
}
private List<EnvironmentPostProcessor> loadPostProcessors(SpringApplication application, List<String> names) {
List<EnvironmentPostProcessor> postProcessors = new ArrayList<>(names.size());
for (String name : names) {
try {
postProcessors.add(instantiatePostProcessor(application, name));
}
catch (Throwable ex) {
throw new IllegalArgumentException("Unable to instantiate factory class [" + name
+ "] for factory type [" + EnvironmentPostProcessor.class.getName() + "]", ex);
}
}
AnnotationAwareOrderComparator.sort(postProcessors);
return postProcessors;
}
private EnvironmentPostProcessor instantiatePostProcessor(SpringApplication application, String name)
throws Exception {
Class<?> type = ClassUtils.forName(name, getClass().getClassLoader());
Assert.isAssignable(EnvironmentPostProcessor.class, type);
Constructor<?>[] constructors = type.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
if (constructor.getParameterCount() == 1) {
Class<?> cls = constructor.getParameterTypes()[0];
if (DeferredLogFactory.class.isAssignableFrom(cls)) {
return newInstance(constructor, this.deferredLogs);
}
if (Log.class.isAssignableFrom(cls)) {
return newInstance(constructor, this.deferredLogs.getLog(type));
}
}
}
return (EnvironmentPostProcessor) ReflectionUtils.accessibleConstructor(type).newInstance();
}
private EnvironmentPostProcessor newInstance(Constructor<?> constructor, Object... initargs) throws Exception {
ReflectionUtils.makeAccessible(constructor);
return (EnvironmentPostProcessor) constructor.newInstance(initargs);
}
private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
private void onFinish() {
this.deferredLogs.switchOverAll();
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2012-2020 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.Collections;
import java.util.List;
import java.util.function.Function;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.io.support.SpringFactoriesLoader;
/**
* Factory interface used by the {@link EnvironmentPostProcessorApplicationListener} to
* create the {@link EnvironmentPostProcessor} instances.
*
* @author Phillip Webb
* @since 2.4.0
*/
@FunctionalInterface
public interface EnvironmentPostProcessorsFactory {
/**
* Create all requested {@link EnvironmentPostProcessor} instances.
* @param logFactory a deferred log factory
* @return the post processor instances
*/
List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory);
/**
* Return a {@link EnvironmentPostProcessorsFactory} backed by
* {@code spring.factories}.
* @param classLoader the source class loader
* @return an {@link EnvironmentPostProcessorsFactory} instance
*/
static EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) {
return new ReflectionEnvironmentPostProcessorsFactory(
SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, classLoader));
}
/**
* Return a {@link EnvironmentPostProcessorsFactory} that reflectively creates post
* processors from the given classes.
* @param classes the post processor classes
* @return an {@link EnvironmentPostProcessorsFactory} instance
*/
static EnvironmentPostProcessorsFactory of(Class<?>... classes) {
return new ReflectionEnvironmentPostProcessorsFactory(classes);
}
/**
* Return a {@link EnvironmentPostProcessorsFactory} that reflectively creates post
* processors from the given class names.
* @param classNames the post processor class names
* @return an {@link EnvironmentPostProcessorsFactory} instance
*/
static EnvironmentPostProcessorsFactory of(String... classNames) {
return new ReflectionEnvironmentPostProcessorsFactory(classNames);
}
/**
* Create a {@link EnvironmentPostProcessorsFactory} containing only a single post
* processor.
* @param factory the factory used to create the post processor
* @return an {@link EnvironmentPostProcessorsFactory} instance
*/
static EnvironmentPostProcessorsFactory singleton(Function<DeferredLogFactory, EnvironmentPostProcessor> factory) {
return (logFactory) -> Collections.singletonList(factory.apply(logFactory));
}
}

View File

@ -0,0 +1,94 @@
/*
* Copyright 2012-2020 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.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.logging.Log;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* {@link EnvironmentPostProcessorsFactory} implementation that uses reflection to create
* instances.
*
* @author Phillip Webb
*/
class ReflectionEnvironmentPostProcessorsFactory implements EnvironmentPostProcessorsFactory {
private final List<String> classNames;
ReflectionEnvironmentPostProcessorsFactory(Class<?>... classes) {
this(Arrays.stream(classes).map(Class::getName).toArray(String[]::new));
}
ReflectionEnvironmentPostProcessorsFactory(String... classNames) {
this(Arrays.asList(classNames));
}
ReflectionEnvironmentPostProcessorsFactory(List<String> classNames) {
this.classNames = classNames;
}
@Override
public List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory) {
List<EnvironmentPostProcessor> postProcessors = new ArrayList<>(this.classNames.size());
for (String className : this.classNames) {
try {
postProcessors.add(getEnvironmentPostProcessor(className, logFactory));
}
catch (Throwable ex) {
throw new IllegalArgumentException("Unable to instantiate factory class [" + className
+ "] for factory type [" + EnvironmentPostProcessor.class.getName() + "]", ex);
}
}
AnnotationAwareOrderComparator.sort(postProcessors);
return postProcessors;
}
private EnvironmentPostProcessor getEnvironmentPostProcessor(String className, DeferredLogFactory logFactory)
throws Exception {
Class<?> type = ClassUtils.forName(className, getClass().getClassLoader());
Assert.isAssignable(EnvironmentPostProcessor.class, type);
Constructor<?>[] constructors = type.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
if (constructor.getParameterCount() == 1) {
Class<?> cls = constructor.getParameterTypes()[0];
if (DeferredLogFactory.class.isAssignableFrom(cls)) {
return newInstance(constructor, logFactory);
}
if (Log.class.isAssignableFrom(cls)) {
return newInstance(constructor, logFactory.getLog(type));
}
}
}
return (EnvironmentPostProcessor) ReflectionUtils.accessibleConstructor(type).newInstance();
}
private EnvironmentPostProcessor newInstance(Constructor<?> constructor, Object... initargs) throws Exception {
ReflectionUtils.makeAccessible(constructor);
return (EnvironmentPostProcessor) constructor.newInstance(initargs);
}
}

View File

@ -16,8 +16,26 @@
package org.springframework.boot.env;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.boot.logging.DeferredLogs;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link EnvironmentPostProcessorApplicationListener}.
*
@ -25,9 +43,85 @@ import org.junit.jupiter.api.Test;
*/
class EnvironmentPostProcessorApplicationListenerTests {
private DeferredLogs deferredLogs = spy(new DeferredLogs());
private EnvironmentPostProcessorApplicationListener listener = new EnvironmentPostProcessorApplicationListener(
EnvironmentPostProcessorsFactory.singleton(TestEnvironmentPostProcessor::new), this.deferredLogs);
@Test
void test() {
// fail("Not yet implemented");
void createUsesSpringFactories() {
EnvironmentPostProcessorApplicationListener listener = new EnvironmentPostProcessorApplicationListener();
assertThat(listener.getEnvironmentPostProcessors()).hasSizeGreaterThan(1);
}
@Test
void createWhenHasFactoryUsesFactory() {
EnvironmentPostProcessorApplicationListener listener = new EnvironmentPostProcessorApplicationListener(
EnvironmentPostProcessorsFactory.singleton(TestEnvironmentPostProcessor::new));
List<EnvironmentPostProcessor> postProcessors = listener.getEnvironmentPostProcessors();
assertThat(postProcessors).hasSize(1);
assertThat(postProcessors.get(0)).isInstanceOf(TestEnvironmentPostProcessor.class);
}
@Test
void supporteEventTypeWhenApplicationEnvironmentPreparedEventReturnsTrue() {
assertThat(this.listener.supportsEventType(ApplicationEnvironmentPreparedEvent.class)).isTrue();
}
@Test
void supporteEventTypeWhenApplicationPreparedEventReturnsTrue() {
assertThat(this.listener.supportsEventType(ApplicationPreparedEvent.class)).isTrue();
}
@Test
void supporteEventTypeWhenApplicationFailedEventReturnsTrue() {
assertThat(this.listener.supportsEventType(ApplicationFailedEvent.class)).isTrue();
}
@Test
void supporteEventTypeWhenOtherEventReturnsFalse() {
assertThat(this.listener.supportsEventType(ApplicationStartingEvent.class)).isFalse();
}
@Test
void onApplicationEventWhenApplicationEnvironmentPreparedEventCallsPostProcessors() {
SpringApplication application = mock(SpringApplication.class);
MockEnvironment environment = new MockEnvironment();
ApplicationEnvironmentPreparedEvent event = new ApplicationEnvironmentPreparedEvent(application, new String[0],
environment);
this.listener.onApplicationEvent(event);
assertThat(environment.getProperty("processed")).isEqualTo("true");
}
@Test
void onApplicationEventWhenApplicationPreparedEventSwitchesLogs() {
SpringApplication application = mock(SpringApplication.class);
ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);
ApplicationPreparedEvent event = new ApplicationPreparedEvent(application, new String[0], context);
this.listener.onApplicationEvent(event);
verify(this.deferredLogs).switchOverAll();
}
@Test
void onApplicationEventWhenApplicationFailedEventSwitchesLogs() {
SpringApplication application = mock(SpringApplication.class);
ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);
ApplicationFailedEvent event = new ApplicationFailedEvent(application, new String[0], context,
new RuntimeException());
this.listener.onApplicationEvent(event);
verify(this.deferredLogs).switchOverAll();
}
static class TestEnvironmentPostProcessor implements EnvironmentPostProcessor {
TestEnvironmentPostProcessor(DeferredLogFactory logFactory) {
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
((MockEnvironment) environment).setProperty("processed", "true");
}
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2012-2020 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 java.util.function.Supplier;
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link EnvironmentPostProcessorsFactory}.
*
* @author Phillip Webb
*/
class EnvironmentPostProcessorsFactoryTests {
private final DeferredLogFactory logFactory = Supplier::get;
@Test
void fromSpringFactoriesReturnsFactory() {
EnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory.fromSpringFactories(null);
List<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory);
assertThat(processors).hasSizeGreaterThan(1);
}
@Test
void ofClassesReturnsFactory() {
EnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory
.of(TestEnvironmentPostProcessor.class);
List<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory);
assertThat(processors).hasSize(1);
assertThat(processors.get(0)).isInstanceOf(TestEnvironmentPostProcessor.class);
}
@Test
void ofClassNamesReturnsFactory() {
EnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory
.of(TestEnvironmentPostProcessor.class.getName());
List<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory);
assertThat(processors).hasSize(1);
assertThat(processors.get(0)).isInstanceOf(TestEnvironmentPostProcessor.class);
}
@Test
void singletonReturnsFactory() {
EnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory
.singleton(TestEnvironmentPostProcessor::new);
List<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory);
assertThat(processors).hasSize(1);
assertThat(processors.get(0)).isInstanceOf(TestEnvironmentPostProcessor.class);
}
static class TestEnvironmentPostProcessor implements EnvironmentPostProcessor {
TestEnvironmentPostProcessor(DeferredLogFactory logFactory) {
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
}
}
}

View File

@ -0,0 +1,157 @@
/*
* Copyright 2012-2020 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.io.InputStream;
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.springframework.boot.SpringApplication;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link ReflectionEnvironmentPostProcessorsFactory}.
*
* @author Phillip Webb
*/
class ReflectionEnvironmentPostProcessorsFactoryTests {
private final DeferredLogFactory logFactory = Supplier::get;
@Test
void createWithClassesCreatesFactory() {
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
TestEnvironmentPostProcessor.class);
assertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);
}
@Test
void createWithClassNamesArrayCreatesFactory() {
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
TestEnvironmentPostProcessor.class.getName());
assertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);
}
@Test
void createWithClassNamesListCreatesFactory() {
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
Arrays.asList(TestEnvironmentPostProcessor.class.getName()));
assertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);
}
@Test
void getEnvironmentPostProcessorsWhenHasDefaultConstructorCreatesPostProcessors() {
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
TestEnvironmentPostProcessor.class.getName());
assertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);
}
@Test
void getEnvironmentPostProcessorsWhenHasLogFactoryConstructorCreatesPostProcessors() {
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
TestLogFactoryEnvironmentPostProcessor.class.getName());
assertThatFactory(factory).createsSinglePostProcessor(TestLogFactoryEnvironmentPostProcessor.class);
}
@Test
void getEnvironmentPostProcessorsWhenHasLogConstructorCreatesPostProcessors() {
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
TestLogEnvironmentPostProcessor.class.getName());
assertThatFactory(factory).createsSinglePostProcessor(TestLogEnvironmentPostProcessor.class);
}
@Test
void getEnvironmentPostProcessorsWhenHasNoSuitableConstructorThrowsException() {
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
BadEnvironmentPostProcessor.class.getName());
assertThatIllegalArgumentException().isThrownBy(() -> factory.getEnvironmentPostProcessors(this.logFactory))
.withMessageContaining("Unable to instantiate");
}
private EnvironmentPostProcessorsFactoryAssert assertThatFactory(EnvironmentPostProcessorsFactory factory) {
return new EnvironmentPostProcessorsFactoryAssert(factory);
}
class EnvironmentPostProcessorsFactoryAssert {
private EnvironmentPostProcessorsFactory factory;
EnvironmentPostProcessorsFactoryAssert(EnvironmentPostProcessorsFactory factory) {
this.factory = factory;
}
void createsSinglePostProcessor(Class<?> expectedType) {
List<EnvironmentPostProcessor> processors = this.factory
.getEnvironmentPostProcessors(ReflectionEnvironmentPostProcessorsFactoryTests.this.logFactory);
assertThat(processors).hasSize(1);
assertThat(processors.get(0)).isInstanceOf(expectedType);
}
}
static class TestEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
}
}
static class TestLogFactoryEnvironmentPostProcessor implements EnvironmentPostProcessor {
TestLogFactoryEnvironmentPostProcessor(DeferredLogFactory logFactory) {
assertThat(logFactory).isNotNull();
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
}
}
static class TestLogEnvironmentPostProcessor implements EnvironmentPostProcessor {
TestLogEnvironmentPostProcessor(Log log) {
assertThat(log).isNotNull();
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
}
}
static class BadEnvironmentPostProcessor implements EnvironmentPostProcessor {
BadEnvironmentPostProcessor(InputStream inputStream) {
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
}
}
}