Skip to content

Commit fac2430

Browse files
committed
Merge branch 'gh-30358'
2 parents 95c8d7f + dbc5905 commit fac2430

File tree

8 files changed

+196
-7
lines changed

8 files changed

+196
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.web.context;
18+
19+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
20+
import org.springframework.boot.WebApplicationType;
21+
import org.springframework.boot.web.server.WebServerFactory;
22+
23+
/**
24+
* Exception thrown when there is no {@link WebServerFactory} bean of the required type
25+
* defined in a {@link WebServerApplicationContext}.
26+
*
27+
* @author Guirong Hu
28+
* @author Andy Wilkinson
29+
* @since 2.7.0
30+
*/
31+
public class MissingWebServerFactoryBeanException extends NoSuchBeanDefinitionException {
32+
33+
private final WebApplicationType webApplicationType;
34+
35+
/**
36+
* Create a new {@code MissingWebServerFactoryBeanException}.
37+
* @param webServerApplicationContextClass the class of the
38+
* WebServerApplicationContext that required the WebServerFactory
39+
* @param webServerFactoryClass the class of the WebServerFactory that was missing
40+
* @param webApplicationType the type of the web application
41+
*/
42+
public MissingWebServerFactoryBeanException(
43+
Class<? extends WebServerApplicationContext> webServerApplicationContextClass,
44+
Class<? extends WebServerFactory> webServerFactoryClass, WebApplicationType webApplicationType) {
45+
super(webServerFactoryClass, String.format("Unable to start %s due to missing %s bean",
46+
webServerApplicationContextClass.getSimpleName(), webServerFactoryClass.getSimpleName()));
47+
this.webApplicationType = webApplicationType;
48+
}
49+
50+
/**
51+
* Returns the type of web application for which a {@link WebServerFactory} bean was
52+
* missing.
53+
* @return the type of web application
54+
*/
55+
public WebApplicationType getWebApplicationType() {
56+
return this.webApplicationType;
57+
}
58+
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.web.context;
18+
19+
import java.util.Locale;
20+
21+
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
22+
import org.springframework.boot.diagnostics.FailureAnalysis;
23+
import org.springframework.boot.diagnostics.FailureAnalyzer;
24+
import org.springframework.core.annotation.Order;
25+
26+
/**
27+
* A {@link FailureAnalyzer} that performs analysis of failures caused by an
28+
* {@link MissingWebServerFactoryBeanException}.
29+
*
30+
* @author Guirong Hu
31+
* @author Andy Wilkinson
32+
*/
33+
@Order(0)
34+
class MissingWebServerFactoryBeanFailureAnalyzer extends AbstractFailureAnalyzer<MissingWebServerFactoryBeanException> {
35+
36+
@Override
37+
protected FailureAnalysis analyze(Throwable rootFailure, MissingWebServerFactoryBeanException cause) {
38+
return new FailureAnalysis(
39+
"Web application could not be started as there was no " + cause.getBeanType().getName()
40+
+ " bean defined in the context.",
41+
"Check your application's dependencies for a supported "
42+
+ cause.getWebApplicationType().name().toLowerCase(Locale.ENGLISH) + " web server.\n"
43+
+ "Check the configured web application type.",
44+
cause);
45+
}
46+
47+
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContext.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,9 +18,11 @@
1818

1919
import org.springframework.beans.BeansException;
2020
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
21+
import org.springframework.boot.WebApplicationType;
2122
import org.springframework.boot.availability.AvailabilityChangeEvent;
2223
import org.springframework.boot.availability.ReadinessState;
2324
import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext;
25+
import org.springframework.boot.web.context.MissingWebServerFactoryBeanException;
2426
import org.springframework.boot.web.context.WebServerGracefulShutdownLifecycle;
2527
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
2628
import org.springframework.boot.web.server.WebServer;
@@ -105,8 +107,8 @@ protected String getWebServerFactoryBeanName() {
105107
// Use bean names so that we don't consider the hierarchy
106108
String[] beanNames = getBeanFactory().getBeanNamesForType(ReactiveWebServerFactory.class);
107109
if (beanNames.length == 0) {
108-
throw new ApplicationContextException(
109-
"Unable to start ReactiveWebApplicationContext due to missing ReactiveWebServerFactory bean.");
110+
throw new MissingWebServerFactoryBeanException(this.getClass(), ReactiveWebServerFactory.class,
111+
WebApplicationType.REACTIVE);
110112
}
111113
if (beanNames.length > 1) {
112114
throw new ApplicationContextException("Unable to start ReactiveWebApplicationContext due to multiple "

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@
3636
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3737
import org.springframework.beans.factory.config.Scope;
3838
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
39+
import org.springframework.boot.WebApplicationType;
3940
import org.springframework.boot.availability.AvailabilityChangeEvent;
4041
import org.springframework.boot.availability.ReadinessState;
4142
import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext;
43+
import org.springframework.boot.web.context.MissingWebServerFactoryBeanException;
4244
import org.springframework.boot.web.context.WebServerGracefulShutdownLifecycle;
4345
import org.springframework.boot.web.server.WebServer;
4446
import org.springframework.boot.web.servlet.FilterRegistrationBean;
@@ -206,8 +208,8 @@ protected ServletWebServerFactory getWebServerFactory() {
206208
// Use bean names so that we don't consider the hierarchy
207209
String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
208210
if (beanNames.length == 0) {
209-
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
210-
+ "ServletWebServerFactory bean.");
211+
throw new MissingWebServerFactoryBeanException(this.getClass(), ServletWebServerFactory.class,
212+
WebApplicationType.SERVLET);
211213
}
212214
if (beanNames.length > 1) {
213215
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "

spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFa
7474
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\
7575
org.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer,\
7676
org.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer,\
77-
org.springframework.boot.web.embedded.tomcat.ConnectorStartFailureAnalyzer
77+
org.springframework.boot.web.context.MissingWebServerFactoryBeanFailureAnalyzer,\
78+
org.springframework.boot.web.embedded.tomcat.ConnectorStartFailureAnalyzer,\
7879

7980
# Failure Analysis Reporters
8081
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2012-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.web.context;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.boot.diagnostics.FailureAnalysis;
22+
import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext;
23+
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
24+
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
25+
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
26+
import org.springframework.context.ApplicationContextException;
27+
import org.springframework.context.ConfigurableApplicationContext;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
31+
/**
32+
* Tests for {@link MissingWebServerFactoryBeanFailureAnalyzer}.
33+
*
34+
* @author Guirong Hu
35+
* @author Andy Wilkinson
36+
*/
37+
class MissingWebServerFactoryBeanFailureAnalyzerTests {
38+
39+
@Test
40+
void missingServletWebServerFactoryBeanFailure() {
41+
ApplicationContextException failure = createFailure(new ServletWebServerApplicationContext());
42+
assertThat(failure).isNotNull();
43+
FailureAnalysis analysis = new MissingWebServerFactoryBeanFailureAnalyzer().analyze(failure);
44+
assertThat(analysis).isNotNull();
45+
assertThat(analysis.getDescription()).isEqualTo("Web application could not be started as there was no "
46+
+ ServletWebServerFactory.class.getName() + " bean defined in the context.");
47+
assertThat(analysis.getAction()).isEqualTo(
48+
"Check your application's dependencies for a supported servlet web server.\nCheck the configured web "
49+
+ "application type.");
50+
}
51+
52+
@Test
53+
void missingReactiveWebServerFactoryBeanFailure() {
54+
ApplicationContextException failure = createFailure(new ReactiveWebServerApplicationContext());
55+
FailureAnalysis analysis = new MissingWebServerFactoryBeanFailureAnalyzer().analyze(failure);
56+
assertThat(analysis).isNotNull();
57+
assertThat(analysis.getDescription()).isEqualTo("Web application could not be started as there was no "
58+
+ ReactiveWebServerFactory.class.getName() + " bean defined in the context.");
59+
assertThat(analysis.getAction()).isEqualTo(
60+
"Check your application's dependencies for a supported reactive web server.\nCheck the configured web "
61+
+ "application type.");
62+
}
63+
64+
private ApplicationContextException createFailure(ConfigurableApplicationContext context) {
65+
try {
66+
context.refresh();
67+
context.close();
68+
return null;
69+
}
70+
catch (ApplicationContextException ex) {
71+
return ex;
72+
}
73+
}
74+
75+
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContextTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ void cleanUp() {
6161
void whenThereIsNoWebServerFactoryBeanThenContextRefreshWillFail() {
6262
assertThatExceptionOfType(ApplicationContextException.class).isThrownBy(() -> this.context.refresh())
6363
.withMessageContaining(
64-
"Unable to start ReactiveWebApplicationContext due to missing ReactiveWebServerFactory bean");
64+
"Unable to start ReactiveWebServerApplicationContext due to missing ReactiveWebServerFactory bean");
6565
}
6666

6767
@Test

src/checkstyle/import-control.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@
9393
</subpackage>
9494
<subpackage name="server">
9595
<disallow pkg="org.springframework.context" />
96+
<subpackage name="context">
97+
<allow pkg="org.springframework.context" />
98+
</subpackage>
9699
</subpackage>
97100
<subpackage name="context">
98101
<allow pkg="org.springframework.boot.web.server" />

0 commit comments

Comments
 (0)