From dfafccaba56c1ec14f0491408a5b6a874ba93138 Mon Sep 17 00:00:00 2001 From: Guirong Hu Date: Tue, 22 Mar 2022 13:47:57 +0800 Subject: [PATCH 1/2] Add failure analyzer for missing web factory bean See gh-30358 --- .../ReactiveWebServerApplicationContext.java | 8 ++- .../MissingWebServerFactoryBeanException.java | 58 +++++++++++++++ ...ngWebServerFactoryBeanFailureAnalyzer.java | 49 +++++++++++++ .../boot/web/server/context/package-info.java | 21 ++++++ .../ServletWebServerApplicationContext.java | 6 +- .../main/resources/META-INF/spring.factories | 3 +- ...ctiveWebServerApplicationContextTests.java | 2 +- ...ServerFactoryBeanFailureAnalyzerTests.java | 70 +++++++++++++++++++ src/checkstyle/import-control.xml | 3 + 9 files changed, 213 insertions(+), 7 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanException.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/package-info.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContext.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContext.java index 5a088e802f..e028c84cd1 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContext.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContext.java @@ -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,12 +18,14 @@ package org.springframework.boot.web.reactive.context; import org.springframework.beans.BeansException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.boot.WebApplicationType; import org.springframework.boot.availability.AvailabilityChangeEvent; import org.springframework.boot.availability.ReadinessState; import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext; import org.springframework.boot.web.context.WebServerGracefulShutdownLifecycle; import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; import org.springframework.boot.web.server.WebServer; +import org.springframework.boot.web.server.context.MissingWebServerFactoryBeanException; import org.springframework.context.ApplicationContextException; import org.springframework.core.metrics.StartupStep; import org.springframework.http.server.reactive.HttpHandler; @@ -105,8 +107,8 @@ public class ReactiveWebServerApplicationContext extends GenericReactiveWebAppli // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory().getBeanNamesForType(ReactiveWebServerFactory.class); if (beanNames.length == 0) { - throw new ApplicationContextException( - "Unable to start ReactiveWebApplicationContext due to missing ReactiveWebServerFactory bean."); + throw new MissingWebServerFactoryBeanException(this.getClass(), ReactiveWebServerFactory.class, + WebApplicationType.REACTIVE); } if (beanNames.length > 1) { throw new ApplicationContextException("Unable to start ReactiveWebApplicationContext due to multiple " diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanException.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanException.java new file mode 100644 index 0000000000..cd9a0707da --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanException.java @@ -0,0 +1,58 @@ +/* + * 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.web.server.context; + +import org.springframework.boot.WebApplicationType; +import org.springframework.context.ApplicationContextException; +import org.springframework.lang.NonNull; + +/** + * Throws exception when web server factory bean is missing. + * + * @author Guirong Hu + * @since 2.7.0 + */ +@SuppressWarnings("serial") +public class MissingWebServerFactoryBeanException extends ApplicationContextException { + + private final WebApplicationType webApplicationType; + + /** + * Create a new {@code MissingWebServerFactoryBeanException} with the given web + * application context class and the given web server factory class and the given type + * of web application. + * @param webApplicationContextClass the web application context class + * @param webServerFactoryClass the web server factory class + * @param webApplicationType the type of web application + */ + public MissingWebServerFactoryBeanException(@NonNull Class webApplicationContextClass, + @NonNull Class webServerFactoryClass, @NonNull WebApplicationType webApplicationType) { + super(String.format("Unable to start %s due to missing %s bean.", webApplicationContextClass.getSimpleName(), + webServerFactoryClass.getSimpleName())); + this.webApplicationType = webApplicationType; + } + + /** + * Returns the type of web application that is being run. + * @return the type of web application + * @since 2.7.0 + */ + public WebApplicationType getWebApplicationType() { + return this.webApplicationType; + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java new file mode 100644 index 0000000000..164a8c7d19 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java @@ -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.web.server.context; + +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; +import org.springframework.boot.diagnostics.FailureAnalysis; +import org.springframework.boot.diagnostics.FailureAnalyzer; +import org.springframework.context.ApplicationContextException; + +/** + * A {@link FailureAnalyzer} that performs analysis of failures caused by an + * {@link MissingWebServerFactoryBeanException}. + * + * @author Guirong Hu + */ +class MissingWebServerFactoryBeanFailureAnalyzer extends AbstractFailureAnalyzer { + + private static final String ACTION = "Check your application's dependencies on supported web servers " + + "or configuration of web application type."; + + @Override + protected FailureAnalysis analyze(Throwable rootFailure, ApplicationContextException cause) { + Throwable rootCause = cause.getCause(); + if (rootCause instanceof MissingWebServerFactoryBeanException) { + WebApplicationType webApplicationType = ((MissingWebServerFactoryBeanException) rootCause) + .getWebApplicationType(); + return new FailureAnalysis(String.format( + "Reason: The running web application is of type %s, but the dependent class is missing.", + webApplicationType.name().toLowerCase()), ACTION, cause); + } + return null; + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/package-info.java new file mode 100644 index 0000000000..8381001256 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Web server integrations with Spring's + * {@link org.springframework.context.ApplicationContext ApplicationContext}. + */ +package org.springframework.boot.web.server.context; diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.java index 40dd4f99b9..c2315b6540 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.java @@ -37,11 +37,13 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.Scope; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.boot.WebApplicationType; import org.springframework.boot.availability.AvailabilityChangeEvent; import org.springframework.boot.availability.ReadinessState; import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext; import org.springframework.boot.web.context.WebServerGracefulShutdownLifecycle; import org.springframework.boot.web.server.WebServer; +import org.springframework.boot.web.server.context.MissingWebServerFactoryBeanException; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletContextInitializerBeans; @@ -207,8 +209,8 @@ public class ServletWebServerApplicationContext extends GenericWebApplicationCon // Use bean names so that we don't consider the hierarchy String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class); if (beanNames.length == 0) { - throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing " - + "ServletWebServerFactory bean."); + throw new MissingWebServerFactoryBeanException(this.getClass(), ServletWebServerFactory.class, + WebApplicationType.SERVLET); } if (beanNames.length > 1) { throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple " diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories index aab10a331b..4de66425d1 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories @@ -74,7 +74,8 @@ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFa org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer,\ org.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer,\ -org.springframework.boot.web.embedded.tomcat.ConnectorStartFailureAnalyzer +org.springframework.boot.web.embedded.tomcat.ConnectorStartFailureAnalyzer,\ +org.springframework.boot.web.server.context.MissingWebServerFactoryBeanFailureAnalyzer # Failure Analysis Reporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContextTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContextTests.java index 24ff9da399..13ae884265 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContextTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContextTests.java @@ -61,7 +61,7 @@ class ReactiveWebServerApplicationContextTests { void whenThereIsNoWebServerFactoryBeanThenContextRefreshWillFail() { assertThatExceptionOfType(ApplicationContextException.class).isThrownBy(() -> this.context.refresh()) .withMessageContaining( - "Unable to start ReactiveWebApplicationContext due to missing ReactiveWebServerFactory bean"); + "Unable to start ReactiveWebServerApplicationContext due to missing ReactiveWebServerFactory bean"); } @Test diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java new file mode 100644 index 0000000000..2583f468b3 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java @@ -0,0 +1,70 @@ +/* + * 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.web.server.context; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.diagnostics.FailureAnalysis; +import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext; +import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext; +import org.springframework.context.ApplicationContextException; +import org.springframework.context.ConfigurableApplicationContext; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link MissingWebServerFactoryBeanFailureAnalyzer}. + * + * @author Guirong Hu + */ +class MissingWebServerFactoryBeanFailureAnalyzerTests { + + @Test + void missingServletWebServerFactoryBeanFailure() { + ApplicationContextException failure = createFailure(new ServletWebServerApplicationContext()); + assertThat(failure).isNotNull(); + FailureAnalysis analysis = new MissingWebServerFactoryBeanFailureAnalyzer().analyze(failure); + assertThat(analysis).isNotNull(); + assertThat(analysis.getDescription()).isEqualTo( + "Reason: The running web application is of type servlet, but the dependent class is missing."); + assertThat(analysis.getAction()).isEqualTo( + "Check your application's dependencies on supported web servers or configuration of web application type."); + } + + @Test + void missingReactiveWebServerFactoryBeanFailure() { + ApplicationContextException failure = createFailure(new ReactiveWebServerApplicationContext()); + FailureAnalysis analysis = new MissingWebServerFactoryBeanFailureAnalyzer().analyze(failure); + assertThat(analysis).isNotNull(); + assertThat(analysis.getDescription()).isEqualTo( + "Reason: The running web application is of type reactive, but the dependent class is missing."); + assertThat(analysis.getAction()).isEqualTo( + "Check your application's dependencies on supported web servers or configuration of web application type."); + } + + private ApplicationContextException createFailure(ConfigurableApplicationContext context) { + try { + context.refresh(); + context.close(); + return null; + } + catch (ApplicationContextException ex) { + return ex; + } + } + +} diff --git a/src/checkstyle/import-control.xml b/src/checkstyle/import-control.xml index 445d18591c..b334a2ece5 100644 --- a/src/checkstyle/import-control.xml +++ b/src/checkstyle/import-control.xml @@ -93,6 +93,9 @@ + + + From dbc59052ba9741aaf1549ee3d344abe0ab7a61a8 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 7 Apr 2022 17:40:58 +0100 Subject: [PATCH 2/2] Polish "Add failure analyzer for missing web factory bean" See gh-30358 --- .../MissingWebServerFactoryBeanException.java | 59 +++++++++++++++++++ ...ngWebServerFactoryBeanFailureAnalyzer.java | 32 +++++----- .../ReactiveWebServerApplicationContext.java | 2 +- .../MissingWebServerFactoryBeanException.java | 58 ------------------ .../boot/web/server/context/package-info.java | 21 ------- .../ServletWebServerApplicationContext.java | 2 +- .../main/resources/META-INF/spring.factories | 2 +- ...ServerFactoryBeanFailureAnalyzerTests.java | 19 +++--- 8 files changed, 89 insertions(+), 106 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/MissingWebServerFactoryBeanException.java rename spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/{server => }/context/MissingWebServerFactoryBeanFailureAnalyzer.java (53%) delete mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanException.java delete mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/package-info.java rename spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/{server => }/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java (71%) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/MissingWebServerFactoryBeanException.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/MissingWebServerFactoryBeanException.java new file mode 100644 index 0000000000..5585fc49d4 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/MissingWebServerFactoryBeanException.java @@ -0,0 +1,59 @@ +/* + * 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.web.context; + +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.web.server.WebServerFactory; + +/** + * Exception thrown when there is no {@link WebServerFactory} bean of the required type + * defined in a {@link WebServerApplicationContext}. + * + * @author Guirong Hu + * @author Andy Wilkinson + * @since 2.7.0 + */ +public class MissingWebServerFactoryBeanException extends NoSuchBeanDefinitionException { + + private final WebApplicationType webApplicationType; + + /** + * Create a new {@code MissingWebServerFactoryBeanException}. + * @param webServerApplicationContextClass the class of the + * WebServerApplicationContext that required the WebServerFactory + * @param webServerFactoryClass the class of the WebServerFactory that was missing + * @param webApplicationType the type of the web application + */ + public MissingWebServerFactoryBeanException( + Class webServerApplicationContextClass, + Class webServerFactoryClass, WebApplicationType webApplicationType) { + super(webServerFactoryClass, String.format("Unable to start %s due to missing %s bean", + webServerApplicationContextClass.getSimpleName(), webServerFactoryClass.getSimpleName())); + this.webApplicationType = webApplicationType; + } + + /** + * Returns the type of web application for which a {@link WebServerFactory} bean was + * missing. + * @return the type of web application + */ + public WebApplicationType getWebApplicationType() { + return this.webApplicationType; + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/MissingWebServerFactoryBeanFailureAnalyzer.java similarity index 53% rename from spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java rename to spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/MissingWebServerFactoryBeanFailureAnalyzer.java index 164a8c7d19..bea77b2cfb 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/context/MissingWebServerFactoryBeanFailureAnalyzer.java @@ -14,36 +14,34 @@ * limitations under the License. */ -package org.springframework.boot.web.server.context; +package org.springframework.boot.web.context; + +import java.util.Locale; -import org.springframework.boot.WebApplicationType; import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.diagnostics.FailureAnalyzer; -import org.springframework.context.ApplicationContextException; +import org.springframework.core.annotation.Order; /** * A {@link FailureAnalyzer} that performs analysis of failures caused by an * {@link MissingWebServerFactoryBeanException}. * * @author Guirong Hu + * @author Andy Wilkinson */ -class MissingWebServerFactoryBeanFailureAnalyzer extends AbstractFailureAnalyzer { - - private static final String ACTION = "Check your application's dependencies on supported web servers " - + "or configuration of web application type."; +@Order(0) +class MissingWebServerFactoryBeanFailureAnalyzer extends AbstractFailureAnalyzer { @Override - protected FailureAnalysis analyze(Throwable rootFailure, ApplicationContextException cause) { - Throwable rootCause = cause.getCause(); - if (rootCause instanceof MissingWebServerFactoryBeanException) { - WebApplicationType webApplicationType = ((MissingWebServerFactoryBeanException) rootCause) - .getWebApplicationType(); - return new FailureAnalysis(String.format( - "Reason: The running web application is of type %s, but the dependent class is missing.", - webApplicationType.name().toLowerCase()), ACTION, cause); - } - return null; + protected FailureAnalysis analyze(Throwable rootFailure, MissingWebServerFactoryBeanException cause) { + return new FailureAnalysis( + "Web application could not be started as there was no " + cause.getBeanType().getName() + + " bean defined in the context.", + "Check your application's dependencies for a supported " + + cause.getWebApplicationType().name().toLowerCase(Locale.ENGLISH) + " web server.\n" + + "Check the configured web application type.", + cause); } } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContext.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContext.java index e028c84cd1..8871149c10 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContext.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContext.java @@ -22,10 +22,10 @@ import org.springframework.boot.WebApplicationType; import org.springframework.boot.availability.AvailabilityChangeEvent; import org.springframework.boot.availability.ReadinessState; import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext; +import org.springframework.boot.web.context.MissingWebServerFactoryBeanException; import org.springframework.boot.web.context.WebServerGracefulShutdownLifecycle; import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; import org.springframework.boot.web.server.WebServer; -import org.springframework.boot.web.server.context.MissingWebServerFactoryBeanException; import org.springframework.context.ApplicationContextException; import org.springframework.core.metrics.StartupStep; import org.springframework.http.server.reactive.HttpHandler; diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanException.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanException.java deleted file mode 100644 index cd9a0707da..0000000000 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanException.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.web.server.context; - -import org.springframework.boot.WebApplicationType; -import org.springframework.context.ApplicationContextException; -import org.springframework.lang.NonNull; - -/** - * Throws exception when web server factory bean is missing. - * - * @author Guirong Hu - * @since 2.7.0 - */ -@SuppressWarnings("serial") -public class MissingWebServerFactoryBeanException extends ApplicationContextException { - - private final WebApplicationType webApplicationType; - - /** - * Create a new {@code MissingWebServerFactoryBeanException} with the given web - * application context class and the given web server factory class and the given type - * of web application. - * @param webApplicationContextClass the web application context class - * @param webServerFactoryClass the web server factory class - * @param webApplicationType the type of web application - */ - public MissingWebServerFactoryBeanException(@NonNull Class webApplicationContextClass, - @NonNull Class webServerFactoryClass, @NonNull WebApplicationType webApplicationType) { - super(String.format("Unable to start %s due to missing %s bean.", webApplicationContextClass.getSimpleName(), - webServerFactoryClass.getSimpleName())); - this.webApplicationType = webApplicationType; - } - - /** - * Returns the type of web application that is being run. - * @return the type of web application - * @since 2.7.0 - */ - public WebApplicationType getWebApplicationType() { - return this.webApplicationType; - } - -} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/package-info.java deleted file mode 100644 index 8381001256..0000000000 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/context/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -/** - * Web server integrations with Spring's - * {@link org.springframework.context.ApplicationContext ApplicationContext}. - */ -package org.springframework.boot.web.server.context; diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.java index c2315b6540..0fcb28d5f5 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.java @@ -41,9 +41,9 @@ import org.springframework.boot.WebApplicationType; import org.springframework.boot.availability.AvailabilityChangeEvent; import org.springframework.boot.availability.ReadinessState; import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext; +import org.springframework.boot.web.context.MissingWebServerFactoryBeanException; import org.springframework.boot.web.context.WebServerGracefulShutdownLifecycle; import org.springframework.boot.web.server.WebServer; -import org.springframework.boot.web.server.context.MissingWebServerFactoryBeanException; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletContextInitializerBeans; diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories index 4de66425d1..6480da116e 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories @@ -74,8 +74,8 @@ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFa org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer,\ org.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer,\ +org.springframework.boot.web.context.MissingWebServerFactoryBeanFailureAnalyzer,\ org.springframework.boot.web.embedded.tomcat.ConnectorStartFailureAnalyzer,\ -org.springframework.boot.web.server.context.MissingWebServerFactoryBeanFailureAnalyzer # Failure Analysis Reporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java similarity index 71% rename from spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java rename to spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java index 2583f468b3..fb30be29ca 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java @@ -14,13 +14,15 @@ * limitations under the License. */ -package org.springframework.boot.web.server.context; +package org.springframework.boot.web.context; import org.junit.jupiter.api.Test; import org.springframework.boot.diagnostics.FailureAnalysis; import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext; +import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext; +import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.ApplicationContextException; import org.springframework.context.ConfigurableApplicationContext; @@ -30,6 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link MissingWebServerFactoryBeanFailureAnalyzer}. * * @author Guirong Hu + * @author Andy Wilkinson */ class MissingWebServerFactoryBeanFailureAnalyzerTests { @@ -39,10 +42,11 @@ class MissingWebServerFactoryBeanFailureAnalyzerTests { assertThat(failure).isNotNull(); FailureAnalysis analysis = new MissingWebServerFactoryBeanFailureAnalyzer().analyze(failure); assertThat(analysis).isNotNull(); - assertThat(analysis.getDescription()).isEqualTo( - "Reason: The running web application is of type servlet, but the dependent class is missing."); + assertThat(analysis.getDescription()).isEqualTo("Web application could not be started as there was no " + + ServletWebServerFactory.class.getName() + " bean defined in the context."); assertThat(analysis.getAction()).isEqualTo( - "Check your application's dependencies on supported web servers or configuration of web application type."); + "Check your application's dependencies for a supported servlet web server.\nCheck the configured web " + + "application type."); } @Test @@ -50,10 +54,11 @@ class MissingWebServerFactoryBeanFailureAnalyzerTests { ApplicationContextException failure = createFailure(new ReactiveWebServerApplicationContext()); FailureAnalysis analysis = new MissingWebServerFactoryBeanFailureAnalyzer().analyze(failure); assertThat(analysis).isNotNull(); - assertThat(analysis.getDescription()).isEqualTo( - "Reason: The running web application is of type reactive, but the dependent class is missing."); + assertThat(analysis.getDescription()).isEqualTo("Web application could not be started as there was no " + + ReactiveWebServerFactory.class.getName() + " bean defined in the context."); assertThat(analysis.getAction()).isEqualTo( - "Check your application's dependencies on supported web servers or configuration of web application type."); + "Check your application's dependencies for a supported reactive web server.\nCheck the configured web " + + "application type."); } private ApplicationContextException createFailure(ConfigurableApplicationContext context) {