Browse Source
Introduce a strategy to `WebApplicationType` to allow modules to implement deduction logic. Prior to this commit, modules played no part in deducing the `WebApplicationType`. This meant that a user with `spring-webflux` for client purposes would deduce `REACTIVE` despite no `spring-boot-webflux` module being present. The following deduction logic order is now implemented: 1) If the `spring-boot-webmvc` module is being used and Spring MVC classes are found then `SERVLET` is used. 2) If the `spring-boot-webflux` module is being used and Spring WebFlux classes are found then `REACTIVE` is used. 3) If `spring-web` is found and servlet classes are available then `SERVLET` is used. 4) If none of the above are satisfied, `NONE` is used. This commit also updates `SpringBootTestContextBootstrapper` to use the same deduction logic. Fixes gh-48517pull/48543/head
13 changed files with 328 additions and 44 deletions
@ -0,0 +1,68 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-present 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.webflux; |
||||||
|
|
||||||
|
import org.jspecify.annotations.Nullable; |
||||||
|
|
||||||
|
import org.springframework.aot.hint.RuntimeHints; |
||||||
|
import org.springframework.aot.hint.RuntimeHintsRegistrar; |
||||||
|
import org.springframework.aot.hint.TypeReference; |
||||||
|
import org.springframework.boot.WebApplicationType; |
||||||
|
import org.springframework.core.annotation.Order; |
||||||
|
import org.springframework.util.ClassUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link WebApplicationType} deducer to ensure Spring WebFlux applications use |
||||||
|
* {@link WebApplicationType#REACTIVE}. |
||||||
|
* |
||||||
|
* @author Phillip Webb |
||||||
|
*/ |
||||||
|
@Order(20) // Ordered after MVC
|
||||||
|
class WebFluxWebApplicationTypeDeducer implements WebApplicationType.Deducer { |
||||||
|
|
||||||
|
private static final String[] INDICATOR_CLASSES = { "reactor.core.publisher.Mono", |
||||||
|
"org.springframework.web.reactive.DispatcherHandler" }; |
||||||
|
|
||||||
|
@Override |
||||||
|
public @Nullable WebApplicationType deduceWebApplicationType() { |
||||||
|
// Guard in case the classic module is being used and dependencies are excluded
|
||||||
|
for (String indicatorClass : INDICATOR_CLASSES) { |
||||||
|
if (!ClassUtils.isPresent(indicatorClass, null)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
return WebApplicationType.REACTIVE; |
||||||
|
} |
||||||
|
|
||||||
|
static class WebFluxWebApplicationTypeDeducerRuntimeHints implements RuntimeHintsRegistrar { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) { |
||||||
|
for (String servletIndicatorClass : INDICATOR_CLASSES) { |
||||||
|
registerTypeIfPresent(servletIndicatorClass, classLoader, hints); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void registerTypeIfPresent(String typeName, @Nullable ClassLoader classLoader, RuntimeHints hints) { |
||||||
|
if (ClassUtils.isPresent(typeName, classLoader)) { |
||||||
|
hints.reflection().registerType(TypeReference.of(typeName)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-present 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Core integration between Spring Boot and Spring WebFlux. |
||||||
|
*/ |
||||||
|
@NullMarked |
||||||
|
package org.springframework.boot.webflux; |
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked; |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
# WebApplicationType Deducers |
||||||
|
org.springframework.boot.WebApplicationType$Deducer=\ |
||||||
|
org.springframework.boot.webflux.WebFluxWebApplicationTypeDeducer |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
org.springframework.aot.hint.RuntimeHintsRegistrar=\ |
||||||
|
org.springframework.boot.webflux.WebFluxWebApplicationTypeDeducer$WebFluxWebApplicationTypeDeducerRuntimeHints |
||||||
@ -0,0 +1,69 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-present 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.webmvc; |
||||||
|
|
||||||
|
import org.jspecify.annotations.Nullable; |
||||||
|
|
||||||
|
import org.springframework.aot.hint.RuntimeHints; |
||||||
|
import org.springframework.aot.hint.RuntimeHintsRegistrar; |
||||||
|
import org.springframework.aot.hint.TypeReference; |
||||||
|
import org.springframework.boot.WebApplicationType; |
||||||
|
import org.springframework.core.annotation.Order; |
||||||
|
import org.springframework.util.ClassUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link WebApplicationType} deducer to ensure Spring MVC applications use |
||||||
|
* {@link WebApplicationType#SERVLET}. |
||||||
|
* |
||||||
|
* @author Phillip Webb |
||||||
|
*/ |
||||||
|
@Order(10) // Ordered after WebFlux
|
||||||
|
class WebMvcWebApplicationTypeDeducer implements WebApplicationType.Deducer { |
||||||
|
|
||||||
|
private static final String[] INDICATOR_CLASSES = { "jakarta.servlet.Servlet", |
||||||
|
"org.springframework.web.servlet.DispatcherServlet", |
||||||
|
"org.springframework.web.context.ConfigurableWebApplicationContext" }; |
||||||
|
|
||||||
|
@Override |
||||||
|
public @Nullable WebApplicationType deduceWebApplicationType() { |
||||||
|
// Guard in case the classic module is being used and dependencies are excluded
|
||||||
|
for (String indicatorClass : INDICATOR_CLASSES) { |
||||||
|
if (!ClassUtils.isPresent(indicatorClass, null)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
return WebApplicationType.SERVLET; |
||||||
|
} |
||||||
|
|
||||||
|
static class WebMvcWebApplicationTypeDeducerRuntimeHints implements RuntimeHintsRegistrar { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) { |
||||||
|
for (String servletIndicatorClass : INDICATOR_CLASSES) { |
||||||
|
registerTypeIfPresent(servletIndicatorClass, classLoader, hints); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void registerTypeIfPresent(String typeName, @Nullable ClassLoader classLoader, RuntimeHints hints) { |
||||||
|
if (ClassUtils.isPresent(typeName, classLoader)) { |
||||||
|
hints.reflection().registerType(TypeReference.of(typeName)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-present 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Core integration between Spring Boot and Spring Web MVC. |
||||||
|
*/ |
||||||
|
@NullMarked |
||||||
|
package org.springframework.boot.webmvc; |
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked; |
||||||
@ -1,3 +1,7 @@ |
|||||||
# Template Availability Providers |
# Template Availability Providers |
||||||
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ |
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ |
||||||
org.springframework.boot.webmvc.autoconfigure.JspTemplateAvailabilityProvider |
org.springframework.boot.webmvc.autoconfigure.JspTemplateAvailabilityProvider |
||||||
|
|
||||||
|
# WebApplicationType Deducers |
||||||
|
org.springframework.boot.WebApplicationType$Deducer=\ |
||||||
|
org.springframework.boot.webmvc.WebMvcWebApplicationTypeDeducer |
||||||
|
|||||||
@ -0,0 +1,2 @@ |
|||||||
|
org.springframework.aot.hint.RuntimeHintsRegistrar=\ |
||||||
|
org.springframework.boot.webmvc.WebMvcWebApplicationTypeDeducer$WebMvcWebApplicationTypeDeducerRuntimeHints |
||||||
@ -0,0 +1,92 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-present 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 smoketest.webapplicationtype; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
import org.springframework.boot.WebApplicationType; |
||||||
|
import org.springframework.boot.testsupport.classpath.ClassPathExclusions; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
/** |
||||||
|
* Integration tests for {@link WebApplicationType} deducers. |
||||||
|
* |
||||||
|
* @author Phillip Webb |
||||||
|
*/ |
||||||
|
class WebApplicationTypeIntegrationTests { |
||||||
|
|
||||||
|
@Test |
||||||
|
@ClassPathExclusions("spring-boot-webflux*") |
||||||
|
void deduceWhenNoWebFluxModuleAndWebMvcModule() { |
||||||
|
assertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.SERVLET); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@ClassPathExclusions({ "spring-boot-webflux*", "spring-web-*" }) |
||||||
|
void deduceWhenNoWebFluxModuleAndNoSpringWebAndWebMvcModule() { |
||||||
|
assertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.NONE); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@ClassPathExclusions("spring-boot-webmvc*") |
||||||
|
void deduceWhenNoWebMvcModuleAndWebFluxModule() { |
||||||
|
assertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.REACTIVE); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@ClassPathExclusions({ "spring-boot-webmvc*", "spring-webflux-*" }) |
||||||
|
void deduceWhenNoWebMvcModuleAndNoWebFluxAndWebFluxModule() { |
||||||
|
assertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.SERVLET); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@ClassPathExclusions({ "spring-boot-webmvc*", "spring-webflux-*", "spring-web-*" }) |
||||||
|
void deduceWhenNoWebMvcModuleAndNoWebFluxAndNoWebAndWebFluxModule() { |
||||||
|
assertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.NONE); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void deduceWhenWebMvcAndWebFlux() { |
||||||
|
assertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.SERVLET); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@ClassPathExclusions("spring-webmvc-*") |
||||||
|
void deduceWhenNoWebMvc() { |
||||||
|
assertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.REACTIVE); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@ClassPathExclusions({ "spring-webmvc-*", "spring-webflux-*" }) |
||||||
|
void deduceWhenNoWebMvcAndNoWebFlux() { |
||||||
|
assertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.SERVLET); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@ClassPathExclusions({ "spring-web-*" }) |
||||||
|
void deduceWhenNoWeb() { |
||||||
|
assertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.NONE); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@ClassPathExclusions(packages = "jakarta.servlet", files = "spring-webflux-*") |
||||||
|
void deduceWhenNoServletOrWebFlux() { |
||||||
|
assertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.NONE); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue