mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Polish "Add failure analysis for missing auto-configured MailSender"
See gh-49582 Signed-off-by: Andy Wilkinson <andy.wilkinson@broadcom.com>
This commit is contained in:
+37
-12
@@ -16,18 +16,27 @@
|
||||
|
||||
package org.springframework.boot.mail.autoconfigure;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;
|
||||
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.boot.mail.autoconfigure.MailSenderAutoConfiguration.MailSenderCondition;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.mail.MailSender;
|
||||
|
||||
/**
|
||||
* An {@link AbstractFailureAnalyzer} that improves missing {@link MailSender} guidance
|
||||
* when mail auto-configuration is present but not activated.
|
||||
* when {@link MailSenderAutoConfiguration} is present but did not match.
|
||||
*
|
||||
* @author MJY (answndud)
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class NoSuchMailSenderBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchBeanDefinitionException>
|
||||
implements Ordered {
|
||||
@@ -36,18 +45,22 @@ class NoSuchMailSenderBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuch
|
||||
|
||||
private static final String MAIL_JNDI_NAME_PROPERTY = "spring.mail.jndi-name";
|
||||
|
||||
private final @Nullable Environment environment;
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
NoSuchMailSenderBeanFailureAnalyzer(@Nullable Environment environment) {
|
||||
this.environment = environment;
|
||||
NoSuchMailSenderBeanFailureAnalyzer(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause) {
|
||||
if (!isMissingMailSenderBean(cause) || hasMailConfigurationProperty()) {
|
||||
if (!isMissingMailSenderBean(cause)) {
|
||||
return null;
|
||||
}
|
||||
String description = "A MailSender bean could not be found because Spring Boot mail auto-configuration "
|
||||
ConditionAndOutcome conditionAndOutcome = findMailSenderConditionOutcome();
|
||||
if (conditionAndOutcome == null || conditionAndOutcome.getOutcome().isMatch()) {
|
||||
return null;
|
||||
}
|
||||
String description = "A MailSender bean could not be found because MailSenderAutoConfiguration "
|
||||
+ "did not match. Neither '" + MAIL_HOST_PROPERTY + "' nor '" + MAIL_JNDI_NAME_PROPERTY
|
||||
+ "' is configured.";
|
||||
String action = "Consider configuring '" + MAIL_HOST_PROPERTY + "' or '" + MAIL_JNDI_NAME_PROPERTY
|
||||
@@ -56,6 +69,23 @@ class NoSuchMailSenderBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuch
|
||||
return new FailureAnalysis(description, action, cause);
|
||||
}
|
||||
|
||||
private @Nullable ConditionAndOutcome findMailSenderConditionOutcome() {
|
||||
ConditionEvaluationReport conditionEvaluationReport = ConditionEvaluationReport.find(this.beanFactory);
|
||||
if (conditionEvaluationReport != null) {
|
||||
Map<String, ConditionAndOutcomes> conditionAndOutcomesBySource = conditionEvaluationReport
|
||||
.getConditionAndOutcomesBySource();
|
||||
ConditionAndOutcomes conditionAndOutcomes = conditionAndOutcomesBySource
|
||||
.get(MailSenderAutoConfiguration.class.getName());
|
||||
if (conditionAndOutcomes != null) {
|
||||
return conditionAndOutcomes.stream()
|
||||
.filter((candidate) -> candidate.getCondition() instanceof MailSenderCondition)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isMissingMailSenderBean(NoSuchBeanDefinitionException cause) {
|
||||
Class<?> beanType = cause.getBeanType();
|
||||
if (beanType == null && cause.getResolvableType() != null) {
|
||||
@@ -64,11 +94,6 @@ class NoSuchMailSenderBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuch
|
||||
return (beanType != null) && MailSender.class.isAssignableFrom(beanType);
|
||||
}
|
||||
|
||||
private boolean hasMailConfigurationProperty() {
|
||||
return this.environment != null && (this.environment.containsProperty(MAIL_HOST_PROPERTY)
|
||||
|| this.environment.containsProperty(MAIL_JNDI_NAME_PROPERTY));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 0;
|
||||
|
||||
+45
-37
@@ -18,65 +18,73 @@ package org.springframework.boot.mail.autoconfigure;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.mail.MailSender;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
|
||||
/**
|
||||
* Tests for {@link NoSuchMailSenderBeanFailureAnalyzer}.
|
||||
*
|
||||
* @author MJY (answndud)
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class NoSuchMailSenderBeanFailureAnalyzerTests {
|
||||
|
||||
@Test
|
||||
void analyzeWhenNotNoSuchBeanDefinitionExceptionShouldReturnNull() {
|
||||
assertThat(new NoSuchMailSenderBeanFailureAnalyzer(null).analyze(new Exception())).isNull();
|
||||
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
FailureAnalysis analysis = new NoSuchMailSenderBeanFailureAnalyzer(beanFactory)
|
||||
.analyze(new Exception());
|
||||
assertThat(analysis).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void analyzeWhenNoSuchBeanDefinitionExceptionForDifferentTypeShouldReturnNull() {
|
||||
assertThat(
|
||||
new NoSuchMailSenderBeanFailureAnalyzer(null).analyze(new NoSuchBeanDefinitionException(String.class)))
|
||||
.isNull();
|
||||
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
assertThatException().isThrownBy(() -> context.getBean(String.class)).satisfies((ex) -> {
|
||||
FailureAnalysis analysis = new NoSuchMailSenderBeanFailureAnalyzer(beanFactory).analyze(ex);
|
||||
assertThat(analysis).isNull();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void analyzeWhenMailHostPropertyIsConfiguredShouldReturnNull() {
|
||||
Environment environment = new MockEnvironment().withProperty("spring.mail.host", "smtp.example.org");
|
||||
assertThat(new NoSuchMailSenderBeanFailureAnalyzer(environment)
|
||||
.analyze(new NoSuchBeanDefinitionException(MailSender.class))).isNull();
|
||||
void analyzeWithoutMailSenderAutoConfigurationShouldReturnNull() {
|
||||
new ApplicationContextRunner().run((context) -> {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
assertThatException().isThrownBy(() -> context.getBean(MailSender.class)).satisfies((ex) -> {
|
||||
FailureAnalysis analysis = new NoSuchMailSenderBeanFailureAnalyzer(beanFactory).analyze(ex);
|
||||
assertThat(analysis).isNull();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void analyzeWhenMailJndiNamePropertyIsConfiguredShouldReturnNull() {
|
||||
Environment environment = new MockEnvironment().withProperty("spring.mail.jndi-name", "mail/Session");
|
||||
assertThat(new NoSuchMailSenderBeanFailureAnalyzer(environment)
|
||||
.analyze(new NoSuchBeanDefinitionException(MailSender.class))).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void analyzeWhenMailSenderBeanIsMissingAndNoMailPropertiesAreConfiguredShouldProvideGuidance() {
|
||||
FailureAnalysis analysis = new NoSuchMailSenderBeanFailureAnalyzer(new MockEnvironment())
|
||||
.analyze(new NoSuchBeanDefinitionException(MailSender.class));
|
||||
assertThat(analysis).isNotNull();
|
||||
assertThat(analysis.getDescription())
|
||||
.contains("A MailSender bean could not be found")
|
||||
.contains("spring.mail.host")
|
||||
.contains("spring.mail.jndi-name");
|
||||
assertThat(analysis.getAction())
|
||||
.contains("spring.mail.host")
|
||||
.contains("spring.mail.jndi-name")
|
||||
.contains("MailSender bean");
|
||||
}
|
||||
|
||||
@Test
|
||||
void analyzeWhenJavaMailSenderBeanIsMissingAndNoMailPropertiesAreConfiguredShouldProvideGuidance() {
|
||||
assertThat(new NoSuchMailSenderBeanFailureAnalyzer(new MockEnvironment())
|
||||
.analyze(new NoSuchBeanDefinitionException(JavaMailSender.class))).isNotNull();
|
||||
void analyzeWhenMailSenderBeanIsMissingAndMailSenderConditionDidNotMatchShouldProvideGuidance() {
|
||||
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
assertThatException().isThrownBy(() -> context.getBean(MailSender.class)).satisfies((ex) -> {
|
||||
FailureAnalysis analysis = new NoSuchMailSenderBeanFailureAnalyzer(beanFactory).analyze(ex);
|
||||
assertThat(analysis).isNotNull();
|
||||
assertThat(analysis.getDescription()).contains("A MailSender bean could not be found")
|
||||
.contains("spring.mail.host")
|
||||
.contains("spring.mail.jndi-name");
|
||||
assertThat(analysis.getAction()).contains("spring.mail.host")
|
||||
.contains("spring.mail.jndi-name")
|
||||
.contains("MailSender bean");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user