Merge branch '2.7.x' into main
This commit is contained in:
commit
b64a6e6229
|
|
@ -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.
|
||||
|
|
@ -20,7 +20,6 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.DataSour
|
|||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.boot.jdbc.EmbeddedDatabaseConnection;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
|
@ -33,13 +32,11 @@ import org.springframework.util.StringUtils;
|
|||
* @author Patryk Kostrzewa
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class DataSourceBeanCreationFailureAnalyzer extends AbstractFailureAnalyzer<DataSourceBeanCreationException>
|
||||
implements EnvironmentAware {
|
||||
class DataSourceBeanCreationFailureAnalyzer extends AbstractFailureAnalyzer<DataSourceBeanCreationException> {
|
||||
|
||||
private Environment environment;
|
||||
private final Environment environment;
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
DataSourceBeanCreationFailureAnalyzer(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ package org.springframework.boot.autoconfigure.jooq;
|
|||
|
||||
import org.jooq.DSLContext;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration;
|
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
|
|
@ -28,9 +26,13 @@ import org.springframework.boot.diagnostics.FailureAnalysis;
|
|||
import org.springframework.core.Ordered;
|
||||
|
||||
class NoDslContextBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchBeanDefinitionException>
|
||||
implements Ordered, BeanFactoryAware {
|
||||
implements Ordered {
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
NoDslContextBeanFailureAnalyzer(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause) {
|
||||
|
|
@ -60,10 +62,4 @@ class NoDslContextBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchBean
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -20,7 +20,6 @@ import org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryOptionsInit
|
|||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.boot.r2dbc.EmbeddedDatabaseConnection;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
|
@ -32,12 +31,11 @@ import org.springframework.util.StringUtils;
|
|||
* @author Mark Paluch
|
||||
*/
|
||||
class ConnectionFactoryBeanCreationFailureAnalyzer
|
||||
extends AbstractFailureAnalyzer<ConnectionFactoryBeanCreationException> implements EnvironmentAware {
|
||||
extends AbstractFailureAnalyzer<ConnectionFactoryBeanCreationException> {
|
||||
|
||||
private Environment environment;
|
||||
private final Environment environment;
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
ConnectionFactoryBeanCreationFailureAnalyzer(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -60,8 +60,8 @@ class DataSourceBeanCreationFailureAnalyzerTests {
|
|||
private FailureAnalysis performAnalysis(Class<?> configuration) {
|
||||
BeanCreationException failure = createFailure(configuration);
|
||||
assertThat(failure).isNotNull();
|
||||
DataSourceBeanCreationFailureAnalyzer failureAnalyzer = new DataSourceBeanCreationFailureAnalyzer();
|
||||
failureAnalyzer.setEnvironment(this.environment);
|
||||
DataSourceBeanCreationFailureAnalyzer failureAnalyzer = new DataSourceBeanCreationFailureAnalyzer(
|
||||
this.environment);
|
||||
return failureAnalyzer.analyze(failure);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,13 +33,12 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
*/
|
||||
class NoDslContextBeanFailureAnalyzerTests {
|
||||
|
||||
private final NoDslContextBeanFailureAnalyzer failureAnalyzer = new NoDslContextBeanFailureAnalyzer();
|
||||
|
||||
@Test
|
||||
void noAnalysisWithoutR2dbcAutoConfiguration() {
|
||||
new ApplicationContextRunner().run((context) -> {
|
||||
this.failureAnalyzer.setBeanFactory(context.getBeanFactory());
|
||||
assertThat(this.failureAnalyzer.analyze(new NoSuchBeanDefinitionException(DSLContext.class))).isNull();
|
||||
NoDslContextBeanFailureAnalyzer failureAnalyzer = new NoDslContextBeanFailureAnalyzer(
|
||||
context.getBeanFactory());
|
||||
assertThat(failureAnalyzer.analyze(new NoSuchBeanDefinitionException(DSLContext.class))).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -47,8 +46,9 @@ class NoDslContextBeanFailureAnalyzerTests {
|
|||
void analysisWithR2dbcAutoConfiguration() {
|
||||
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
this.failureAnalyzer.setBeanFactory(context.getBeanFactory());
|
||||
assertThat(this.failureAnalyzer.analyze(new NoSuchBeanDefinitionException(DSLContext.class)))
|
||||
NoDslContextBeanFailureAnalyzer failureAnalyzer = new NoDslContextBeanFailureAnalyzer(
|
||||
context.getBeanFactory());
|
||||
assertThat(failureAnalyzer.analyze(new NoSuchBeanDefinitionException(DSLContext.class)))
|
||||
.isNotNull();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -58,8 +58,8 @@ class ConnectionFactoryBeanCreationFailureAnalyzerTests {
|
|||
private FailureAnalysis performAnalysis(Class<?> configuration) {
|
||||
BeanCreationException failure = createFailure(configuration);
|
||||
assertThat(failure).isNotNull();
|
||||
ConnectionFactoryBeanCreationFailureAnalyzer failureAnalyzer = new ConnectionFactoryBeanCreationFailureAnalyzer();
|
||||
failureAnalyzer.setEnvironment(this.environment);
|
||||
ConnectionFactoryBeanCreationFailureAnalyzer failureAnalyzer = new ConnectionFactoryBeanCreationFailureAnalyzer(
|
||||
this.environment);
|
||||
return failureAnalyzer.analyze(failure);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,9 +16,8 @@
|
|||
|
||||
package org.springframework.boot.diagnostics;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
|
@ -26,26 +25,27 @@ 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.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility to trigger {@link FailureAnalyzer} and {@link FailureAnalysisReporter}
|
||||
* instances loaded from {@code spring.factories}.
|
||||
* <p>
|
||||
* A {@code FailureAnalyzer} that requires access to the {@link BeanFactory} in order to
|
||||
* perform its analysis can implement {@code BeanFactoryAware} to have the
|
||||
* {@code BeanFactory} injected prior to {@link FailureAnalyzer#analyze(Throwable)} being
|
||||
* called.
|
||||
* A {@code FailureAnalyzer} that requires access to the {@link BeanFactory} or
|
||||
* {@link Environment} in order to perform its analysis can implement a constructor that
|
||||
* accepts arguments of one or both of these types.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
final class FailureAnalyzers implements SpringBootExceptionReporter {
|
||||
|
||||
|
|
@ -56,54 +56,60 @@ final class FailureAnalyzers implements SpringBootExceptionReporter {
|
|||
private final List<FailureAnalyzer> analyzers;
|
||||
|
||||
FailureAnalyzers(ConfigurableApplicationContext context) {
|
||||
this(context, null);
|
||||
this(context, SpringFactoriesLoader.loadFactoryNames(FailureAnalyzer.class, getClassLoader(context)));
|
||||
}
|
||||
|
||||
FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
|
||||
this.classLoader = (classLoader != null) ? classLoader : getClassLoader(context);
|
||||
this.analyzers = loadFailureAnalyzers(context, this.classLoader);
|
||||
FailureAnalyzers(ConfigurableApplicationContext context, List<String> classNames) {
|
||||
this.classLoader = getClassLoader(context);
|
||||
this.analyzers = loadFailureAnalyzers(classNames, context);
|
||||
}
|
||||
|
||||
private ClassLoader getClassLoader(ConfigurableApplicationContext context) {
|
||||
private static ClassLoader getClassLoader(ConfigurableApplicationContext context) {
|
||||
return (context != null) ? context.getClassLoader() : null;
|
||||
}
|
||||
|
||||
private List<FailureAnalyzer> loadFailureAnalyzers(ConfigurableApplicationContext context,
|
||||
ClassLoader classLoader) {
|
||||
List<String> classNames = SpringFactoriesLoader.loadFactoryNames(FailureAnalyzer.class, classLoader);
|
||||
List<FailureAnalyzer> analyzers = new ArrayList<>();
|
||||
for (String className : classNames) {
|
||||
try {
|
||||
FailureAnalyzer analyzer = createAnalyzer(context, className);
|
||||
if (analyzer != null) {
|
||||
analyzers.add(analyzer);
|
||||
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());
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.trace(LogMessage.format("Failed to load %s", className), ex);
|
||||
}
|
||||
}
|
||||
AnnotationAwareOrderComparator.sort(analyzers);
|
||||
return analyzers;
|
||||
}, new LoggingInstantiationFailureHandler());
|
||||
List<FailureAnalyzer> analyzers = instantiator.instantiate(this.classLoader, classNames);
|
||||
return handleAwareAnalyzers(analyzers, context);
|
||||
}
|
||||
|
||||
private FailureAnalyzer createAnalyzer(ConfigurableApplicationContext context, String className) throws Exception {
|
||||
Constructor<?> constructor = ClassUtils.forName(className, this.classLoader).getDeclaredConstructor();
|
||||
ReflectionUtils.makeAccessible(constructor);
|
||||
FailureAnalyzer analyzer = (FailureAnalyzer) constructor.newInstance();
|
||||
if (analyzer instanceof BeanFactoryAware || analyzer instanceof EnvironmentAware) {
|
||||
private List<FailureAnalyzer> handleAwareAnalyzers(List<FailureAnalyzer> analyzers,
|
||||
ConfigurableApplicationContext context) {
|
||||
List<FailureAnalyzer> awareAnalyzers = analyzers.stream()
|
||||
.filter((analyzer) -> analyzer instanceof BeanFactoryAware || analyzer instanceof EnvironmentAware)
|
||||
.collect(Collectors.toList());
|
||||
if (!awareAnalyzers.isEmpty()) {
|
||||
String awareAnalyzerNames = StringUtils.collectionToCommaDelimitedString(awareAnalyzers.stream()
|
||||
.map((analyzer) -> analyzer.getClass().getName()).collect(Collectors.toList()));
|
||||
logger.warn(LogMessage.format(
|
||||
"FailureAnalyzers [%s] implement BeanFactoryAware or EnvironmentAware."
|
||||
+ "Support for these interfaces on FailureAnalyzers is deprecated, "
|
||||
+ "and will be removed in a future release."
|
||||
+ "Instead provide a constructor that accepts BeanFactory or Environment parameters.",
|
||||
awareAnalyzerNames));
|
||||
if (context == null) {
|
||||
logger.trace(LogMessage.format("Skipping %s due to missing context", className));
|
||||
return null;
|
||||
logger.trace(LogMessage.format("Skipping [%s] due to missing context", awareAnalyzerNames));
|
||||
return analyzers.stream().filter((analyzer) -> !awareAnalyzers.contains(analyzer))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
awareAnalyzers.forEach((analyzer) -> {
|
||||
if (analyzer instanceof BeanFactoryAware) {
|
||||
((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory());
|
||||
}
|
||||
if (analyzer instanceof EnvironmentAware) {
|
||||
((EnvironmentAware) analyzer).setEnvironment(context.getEnvironment());
|
||||
}
|
||||
});
|
||||
}
|
||||
return analyzer;
|
||||
return analyzers;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -139,4 +145,13 @@ 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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -40,6 +40,7 @@ import org.springframework.util.ReflectionUtils;
|
|||
*
|
||||
* @param <T> the type to instantiate
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public class Instantiator<T> {
|
||||
|
|
@ -47,18 +48,39 @@ public class Instantiator<T> {
|
|||
private static final Comparator<Constructor<?>> CONSTRUCTOR_COMPARATOR = Comparator
|
||||
.<Constructor<?>>comparingInt(Constructor::getParameterCount).reversed();
|
||||
|
||||
private static final FailureHandler throwingFailureHandler = (type, implementationName, failure) -> {
|
||||
throw new IllegalArgumentException("Unable to instantiate " + implementationName + " [" + type.getName() + "]",
|
||||
failure);
|
||||
};
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
private final Map<Class<?>, Function<Class<?>, Object>> availableParameters;
|
||||
|
||||
private final FailureHandler failureHandler;
|
||||
|
||||
/**
|
||||
* Create a new {@link Instantiator} instance for the given type.
|
||||
* @param type the type to instantiate
|
||||
* @param availableParameters consumer used to register available parameters
|
||||
*/
|
||||
public Instantiator(Class<?> type, Consumer<AvailableParameters> availableParameters) {
|
||||
this(type, availableParameters, throwingFailureHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Instantiator} instance for the given type.
|
||||
* @param type the type to instantiate
|
||||
* @param availableParameters consumer used to register available parameters
|
||||
* @param failureHandler a {@link FailureHandler} that will be called in case of
|
||||
* failure when instantiating objects
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public Instantiator(Class<?> type, Consumer<AvailableParameters> availableParameters,
|
||||
FailureHandler failureHandler) {
|
||||
this.type = type;
|
||||
this.availableParameters = getAvailableParameters(availableParameters);
|
||||
this.failureHandler = failureHandler;
|
||||
}
|
||||
|
||||
private Map<Class<?>, Function<Class<?>, Object>> getAvailableParameters(
|
||||
|
|
@ -127,8 +149,8 @@ public class Instantiator<T> {
|
|||
return instantiate(type);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to instantiate " + this.type.getName() + " [" + typeSupplier.getName() + "]", ex);
|
||||
this.failureHandler.handleFailure(this.type, typeSupplier.getName(), ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +165,7 @@ public class Instantiator<T> {
|
|||
return (T) constructor.newInstance(args);
|
||||
}
|
||||
}
|
||||
throw new IllegalAccessException("Unable to find suitable constructor");
|
||||
throw new IllegalAccessException("Class [" + type.getName() + "] has no suitable constructor");
|
||||
}
|
||||
|
||||
private Object[] getArgs(Class<?>[] parameterTypes) {
|
||||
|
|
@ -231,4 +253,22 @@ public class Instantiator<T> {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy for handling a failure that occurs when instantiating a type.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public interface FailureHandler {
|
||||
|
||||
/**
|
||||
* Handle the {@code failure} that occurred when instantiating the {@code type}
|
||||
* that was expected to be of the given {@code typeSupplier}.
|
||||
* @param type the type
|
||||
* @param implementationName the name of the implementation type
|
||||
* @param failure the failure that occurred
|
||||
*/
|
||||
void handleFailure(Class<?> type, String implementationName, Throwable failure);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,20 +16,22 @@
|
|||
|
||||
package org.springframework.boot.diagnostics;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
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.system.CapturedOutput;
|
||||
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.same;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
|
@ -39,11 +41,15 @@ import static org.mockito.Mockito.times;
|
|||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class FailureAnalyzersTests {
|
||||
|
||||
private static AwareFailureAnalyzer failureAnalyzer;
|
||||
|
||||
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
|
||||
@BeforeEach
|
||||
void configureMock() {
|
||||
failureAnalyzer = mock(AwareFailureAnalyzer.class);
|
||||
|
|
@ -52,53 +58,75 @@ class FailureAnalyzersTests {
|
|||
@Test
|
||||
void analyzersAreLoadedAndCalled() {
|
||||
RuntimeException failure = new RuntimeException();
|
||||
analyzeAndReport("basic.factories", failure);
|
||||
analyzeAndReport(failure, BasicFailureAnalyzer.class.getName(), BasicFailureAnalyzer.class.getName());
|
||||
then(failureAnalyzer).should(times(2)).analyze(failure);
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanFactoryIsInjectedIntoBeanFactoryAwareFailureAnalyzers() {
|
||||
void analyzerIsConstructedWithBeanFactory(CapturedOutput output) {
|
||||
RuntimeException failure = new RuntimeException();
|
||||
analyzeAndReport("basic.factories", failure);
|
||||
then(failureAnalyzer).should().setBeanFactory(any(BeanFactory.class));
|
||||
analyzeAndReport(failure, BasicFailureAnalyzer.class.getName(),
|
||||
BeanFactoryConstructorFailureAnalyzer.class.getName());
|
||||
then(failureAnalyzer).should(times(2)).analyze(failure);
|
||||
assertThat(output).doesNotContain("implement BeanFactoryAware or EnvironmentAware");
|
||||
}
|
||||
|
||||
@Test
|
||||
void analyzerIsConstructedWithEnvironment(CapturedOutput output) {
|
||||
RuntimeException failure = new RuntimeException();
|
||||
analyzeAndReport(failure, BasicFailureAnalyzer.class.getName(),
|
||||
EnvironmentConstructorFailureAnalyzer.class.getName());
|
||||
then(failureAnalyzer).should(times(2)).analyze(failure);
|
||||
assertThat(output).doesNotContain("implement BeanFactoryAware or EnvironmentAware");
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanFactoryIsInjectedIntoBeanFactoryAwareFailureAnalyzers(CapturedOutput output) {
|
||||
RuntimeException failure = new RuntimeException();
|
||||
analyzeAndReport(failure, BasicFailureAnalyzer.class.getName(), StandardAwareFailureAnalyzer.class.getName());
|
||||
then(failureAnalyzer).should().setBeanFactory(same(this.context.getBeanFactory()));
|
||||
assertThat(output).contains("FailureAnalyzers [" + StandardAwareFailureAnalyzer.class.getName()
|
||||
+ "] implement BeanFactoryAware or EnvironmentAware.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void environmentIsInjectedIntoEnvironmentAwareFailureAnalyzers() {
|
||||
RuntimeException failure = new RuntimeException();
|
||||
analyzeAndReport("basic.factories", failure);
|
||||
then(failureAnalyzer).should().setEnvironment(any(Environment.class));
|
||||
analyzeAndReport(failure, BasicFailureAnalyzer.class.getName(), StandardAwareFailureAnalyzer.class.getName());
|
||||
then(failureAnalyzer).should().setEnvironment(same(this.context.getEnvironment()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void analyzerThatFailsDuringInitializationDoesNotPreventOtherAnalyzersFromBeingCalled() {
|
||||
RuntimeException failure = new RuntimeException();
|
||||
analyzeAndReport("broken-initialization.factories", failure);
|
||||
analyzeAndReport(failure, BrokenInitializationFailureAnalyzer.class.getName(),
|
||||
BasicFailureAnalyzer.class.getName());
|
||||
then(failureAnalyzer).should().analyze(failure);
|
||||
}
|
||||
|
||||
@Test
|
||||
void analyzerThatFailsDuringAnalysisDoesNotPreventOtherAnalyzersFromBeingCalled() {
|
||||
RuntimeException failure = new RuntimeException();
|
||||
analyzeAndReport("broken-analysis.factories", failure);
|
||||
analyzeAndReport(failure, BrokenAnalysisFailureAnalyzer.class.getName(), BasicFailureAnalyzer.class.getName());
|
||||
then(failureAnalyzer).should().analyze(failure);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWithNullContextSkipsAwareAnalyzers() {
|
||||
RuntimeException failure = new RuntimeException();
|
||||
analyzeAndReport("basic.factories", failure, null);
|
||||
analyzeAndReport(failure, (AnnotationConfigApplicationContext) null, BasicFailureAnalyzer.class.getName(),
|
||||
BeanFactoryConstructorFailureAnalyzer.class.getName(),
|
||||
EnvironmentConstructorFailureAnalyzer.class.getName(), StandardAwareFailureAnalyzer.class.getName());
|
||||
then(failureAnalyzer).should().analyze(failure);
|
||||
}
|
||||
|
||||
private void analyzeAndReport(String factoriesName, Throwable failure) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
analyzeAndReport(factoriesName, failure, context);
|
||||
private void analyzeAndReport(Throwable failure, String... factoryNames) {
|
||||
analyzeAndReport(failure, this.context, factoryNames);
|
||||
}
|
||||
|
||||
private void analyzeAndReport(String factoriesName, Throwable failure, AnnotationConfigApplicationContext context) {
|
||||
ClassLoader classLoader = new CustomSpringFactoriesClassLoader(factoriesName);
|
||||
new FailureAnalyzers(context, classLoader).reportException(failure);
|
||||
private void analyzeAndReport(Throwable failure, AnnotationConfigApplicationContext context,
|
||||
String... factoryNames) {
|
||||
new FailureAnalyzers(context, Arrays.asList(factoryNames)).reportException(failure);
|
||||
}
|
||||
|
||||
static class BasicFailureAnalyzer implements FailureAnalyzer {
|
||||
|
|
@ -133,6 +161,22 @@ class FailureAnalyzersTests {
|
|||
|
||||
}
|
||||
|
||||
static class BeanFactoryConstructorFailureAnalyzer extends BasicFailureAnalyzer {
|
||||
|
||||
BeanFactoryConstructorFailureAnalyzer(BeanFactory beanFactory) {
|
||||
assertThat(beanFactory).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class EnvironmentConstructorFailureAnalyzer extends BasicFailureAnalyzer {
|
||||
|
||||
EnvironmentConstructorFailureAnalyzer(Environment environment) {
|
||||
assertThat(environment).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface AwareFailureAnalyzer extends BeanFactoryAware, EnvironmentAware, FailureAnalyzer {
|
||||
|
||||
}
|
||||
|
|
@ -151,23 +195,4 @@ class FailureAnalyzersTests {
|
|||
|
||||
}
|
||||
|
||||
static class CustomSpringFactoriesClassLoader extends ClassLoader {
|
||||
|
||||
private final String factoriesName;
|
||||
|
||||
CustomSpringFactoriesClassLoader(String factoriesName) {
|
||||
super(CustomSpringFactoriesClassLoader.class.getClassLoader());
|
||||
this.factoriesName = factoriesName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
if ("META-INF/spring.factories".equals(name)) {
|
||||
return super.getResources("failure-analyzers-tests/" + this.factoriesName);
|
||||
}
|
||||
return super.getResources(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -22,23 +22,26 @@ import java.util.List;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.util.Instantiator.FailureHandler;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.OverridingClassLoader;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link Instantiator}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class InstantiatorTests {
|
||||
|
||||
private ParamA paramA = new ParamA();
|
||||
private final ParamA paramA = new ParamA();
|
||||
|
||||
private ParamB paramB = new ParamB();
|
||||
private final ParamB paramB = new ParamB();
|
||||
|
||||
private ParamC paramC;
|
||||
|
||||
|
|
@ -108,6 +111,15 @@ class InstantiatorTests {
|
|||
.withMessageContaining("Unable to instantiate");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWithFailureHandlerInvokesFailureHandler() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> new Instantiator<>(WithDefaultConstructor.class, (availableParameters) -> {
|
||||
}, new CustomFailureHandler())
|
||||
.instantiate(Collections.singleton(WithAdditionalConstructor.class.getName())))
|
||||
.withMessageContaining("custom failure handler message");
|
||||
}
|
||||
|
||||
private <T> T createInstance(Class<T> type) {
|
||||
return createInstantiator(type).instantiate(Collections.singleton(type.getName())).get(0);
|
||||
}
|
||||
|
|
@ -182,4 +194,13 @@ class InstantiatorTests {
|
|||
|
||||
}
|
||||
|
||||
class CustomFailureHandler implements FailureHandler {
|
||||
|
||||
@Override
|
||||
public void handleFailure(Class<?> type, String implementationName, Throwable failure) {
|
||||
throw new IllegalStateException("custom failure handler message");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
# Failure Analyzers
|
||||
org.springframework.boot.diagnostics.FailureAnalyzer=\
|
||||
org.springframework.boot.diagnostics.FailureAnalyzersTests$BasicFailureAnalyzer,\
|
||||
org.springframework.boot.diagnostics.FailureAnalyzersTests$StandardAwareFailureAnalyzer
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
# Failure Analyzers
|
||||
org.springframework.boot.diagnostics.FailureAnalyzer=\
|
||||
org.springframework.boot.diagnostics.FailureAnalyzersTests$BrokenAnalysisFailureAnalyzer,\
|
||||
org.springframework.boot.diagnostics.FailureAnalyzersTests$BasicFailureAnalyzer
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
# Failure Analyzers
|
||||
org.springframework.boot.diagnostics.FailureAnalyzer=\
|
||||
org.springframework.boot.diagnostics.FailureAnalyzersTests$BrokenInitializationFailureAnalyzer,\
|
||||
org.springframework.boot.diagnostics.FailureAnalyzersTests$BasicFailureAnalyzer
|
||||
Loading…
Reference in New Issue