From 4fd2056ffa55b801dcdc2291ff77f010f4b662b7 Mon Sep 17 00:00:00 2001 From: Daeho Kwon Date: Sat, 5 Apr 2025 01:59:11 +0900 Subject: [PATCH 1/6] Add initParameters and servletRegistrationBeans Signed-off-by: Daeho Kwon --- .../boot/web/servlet/FilterRegistration.java | 14 ++++++ .../ServletContextInitializerBeans.java | 16 +++++++ .../ServletContextInitializerBeansTests.java | 43 ++++++++++++++++++- 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/FilterRegistration.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/FilterRegistration.java index df3f67644560..fdb4916b8293 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/FilterRegistration.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/FilterRegistration.java @@ -24,6 +24,7 @@ import jakarta.servlet.DispatcherType; import jakarta.servlet.Filter; +import jakarta.servlet.annotation.WebInitParam; import org.springframework.core.Ordered; import org.springframework.core.annotation.AliasFor; @@ -34,6 +35,7 @@ * annotation-based alternative to {@link FilterRegistrationBean}. * * @author Moritz Halbritter + * @author Daeho Kwon * @since 3.5.0 * @see FilterRegistrationBean */ @@ -81,6 +83,12 @@ */ boolean ignoreRegistrationFailure() default false; + /** + * Init parameters to be used with the filter. + * @return the init parameters + */ + WebInitParam[] initParameters() default {}; + /** * Whether the filter mappings should be matched after any declared Filter mappings of * the ServletContext. @@ -95,6 +103,12 @@ */ String[] servletNames() default {}; + /** + * Servlet types that the filter will be registered against. + * @return the servlet types + */ + Class[] servletRegistrationBeans() default {}; + /** * URL patterns, as defined in the Servlet specification, that the filter will be * registered against. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java index b0010729ada6..3769d6166d4c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java @@ -35,6 +35,7 @@ import jakarta.servlet.Filter; import jakarta.servlet.MultipartConfigElement; import jakarta.servlet.Servlet; +import jakarta.servlet.annotation.WebInitParam; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -369,6 +370,21 @@ private void configureFromAnnotation(FilterRegistrationBean bean, Filter if (registration.urlPatterns().length > 0) { bean.setUrlPatterns(Arrays.asList(registration.urlPatterns())); } + for (WebInitParam param : registration.initParameters()) { + bean.addInitParameter(param.name(), param.value()); + } + + @SuppressWarnings("unchecked") + Map> servletRegistrationBeans = (Map>) (Map) this.beanFactory + .getBeansOfType(ServletRegistrationBean.class); + + for (Class servletClass : registration.servletRegistrationBeans()) { + for (ServletRegistrationBean registrationBean : servletRegistrationBeans.values()) { + if (servletClass.isInstance(registrationBean.getServlet())) { + bean.addServletRegistrationBeans(registrationBean); + } + } + } } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java index 605ce7f0b879..9aca63f3a75b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java @@ -23,6 +23,7 @@ import jakarta.servlet.ServletContext; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; +import jakarta.servlet.annotation.WebInitParam; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpSessionIdListener; import org.assertj.core.api.ThrowingConsumer; @@ -42,6 +43,7 @@ * * @author Andy Wilkinson * @author Moritz Halbritter + * @author Daeho Kwon */ class ServletContextInitializerBeansTests { @@ -136,6 +138,9 @@ void shouldApplyFilterRegistrationAnnotation() { assertThat(filterRegistrationBean.getServletNames()).containsExactly("test"); assertThat(filterRegistrationBean.determineDispatcherTypes()).containsExactly(DispatcherType.ERROR); assertThat(filterRegistrationBean.getUrlPatterns()).containsExactly("/test/*"); + assertThat(filterRegistrationBean.getInitParameters()).containsEntry("env", "test") + .containsEntry("debug", "true"); + }); } @@ -179,6 +184,25 @@ void shouldApplyOrderFromOrderAttribute() { .isEqualTo(ServletConfigurationWithAnnotationAndOrder.ORDER)); } + @Test + void shouldApplyServletRegistrationBeansInFilterRegistration() { + load(FilterWithServletRegistrationBeansConfiguration.class); + + ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( + this.context.getBeanFactory(), TestServletContextInitializer.class); + + FilterRegistrationBean frb = initializerBeans.stream() + .filter(FilterRegistrationBean.class::isInstance) + .map(FilterRegistrationBean.class::cast) + .filter((f) -> "testFilter".equals(f.getFilterName())) + .findFirst() + .orElseThrow(); + + assertThat(frb.getServletRegistrationBeans()).hasSize(1); + assertThat(frb.getServletRegistrationBeans().iterator().next().getServletName()) + .isEqualTo("testServletRegistrationBean"); + } + private void load(Class... configuration) { this.context = new AnnotationConfigApplicationContext(configuration); } @@ -280,7 +304,24 @@ static class FilterConfigurationWithAnnotation { @Bean @FilterRegistration(enabled = false, name = "test", asyncSupported = false, dispatcherTypes = DispatcherType.ERROR, matchAfter = true, servletNames = "test", - urlPatterns = "/test/*") + urlPatterns = "/test/*", initParameters = { @WebInitParam(name = "env", value = "test"), + @WebInitParam(name = "debug", value = "true") }) + TestFilter testFilter() { + return new TestFilter(); + } + + } + + @Configuration(proxyBeanMethods = false) + static class FilterWithServletRegistrationBeansConfiguration { + + @Bean + ServletRegistrationBean testServletRegistrationBean() { + return new ServletRegistrationBean<>(new TestServlet(), "/test"); + } + + @Bean + @FilterRegistration(name = "testFilter", servletRegistrationBeans = TestServlet.class) TestFilter testFilter() { return new TestFilter(); } From 1f2c37227547d71b1a7ab78e1b8e62e7e945cec5 Mon Sep 17 00:00:00 2001 From: Daeho Kwon Date: Mon, 7 Apr 2025 21:11:56 +0900 Subject: [PATCH 2/6] Polish Signed-off-by: Daeho Kwon --- .../ServletContextInitializerBeans.java | 14 +++---- .../ServletContextInitializerBeansTests.java | 40 ++++--------------- 2 files changed, 13 insertions(+), 41 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java index 3769d6166d4c..af801d18dedd 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java @@ -374,17 +374,13 @@ private void configureFromAnnotation(FilterRegistrationBean bean, Filter bean.addInitParameter(param.name(), param.value()); } - @SuppressWarnings("unchecked") - Map> servletRegistrationBeans = (Map>) (Map) this.beanFactory - .getBeansOfType(ServletRegistrationBean.class); - - for (Class servletClass : registration.servletRegistrationBeans()) { - for (ServletRegistrationBean registrationBean : servletRegistrationBeans.values()) { - if (servletClass.isInstance(registrationBean.getServlet())) { - bean.addServletRegistrationBeans(registrationBean); + this.beanFactory.getBeanProvider(ServletRegistrationBean.class).forEach((servletRegistrationBean) -> { + for (Class servletClass : registration.servletRegistrationBeans()) { + if (servletClass.isInstance(servletRegistrationBean.getServlet())) { + bean.addServletRegistrationBeans(servletRegistrationBean); } } - } + }); } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java index 9aca63f3a75b..d2e6e85be217 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.web.servlet; +import java.util.Collection; + import jakarta.servlet.DispatcherType; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; @@ -140,6 +142,10 @@ void shouldApplyFilterRegistrationAnnotation() { assertThat(filterRegistrationBean.getUrlPatterns()).containsExactly("/test/*"); assertThat(filterRegistrationBean.getInitParameters()).containsEntry("env", "test") .containsEntry("debug", "true"); + Collection> servletRegistrationBeans = filterRegistrationBean.getServletRegistrationBeans(); + assertThat(servletRegistrationBeans).hasSize(1); + assertThat(servletRegistrationBeans.iterator().next().getServletName()) + .isEqualTo("testServletRegistrationBean"); }); } @@ -184,25 +190,6 @@ void shouldApplyOrderFromOrderAttribute() { .isEqualTo(ServletConfigurationWithAnnotationAndOrder.ORDER)); } - @Test - void shouldApplyServletRegistrationBeansInFilterRegistration() { - load(FilterWithServletRegistrationBeansConfiguration.class); - - ServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans( - this.context.getBeanFactory(), TestServletContextInitializer.class); - - FilterRegistrationBean frb = initializerBeans.stream() - .filter(FilterRegistrationBean.class::isInstance) - .map(FilterRegistrationBean.class::cast) - .filter((f) -> "testFilter".equals(f.getFilterName())) - .findFirst() - .orElseThrow(); - - assertThat(frb.getServletRegistrationBeans()).hasSize(1); - assertThat(frb.getServletRegistrationBeans().iterator().next().getServletName()) - .isEqualTo("testServletRegistrationBean"); - } - private void load(Class... configuration) { this.context = new AnnotationConfigApplicationContext(configuration); } @@ -305,25 +292,14 @@ static class FilterConfigurationWithAnnotation { @FilterRegistration(enabled = false, name = "test", asyncSupported = false, dispatcherTypes = DispatcherType.ERROR, matchAfter = true, servletNames = "test", urlPatterns = "/test/*", initParameters = { @WebInitParam(name = "env", value = "test"), - @WebInitParam(name = "debug", value = "true") }) + @WebInitParam(name = "debug", value = "true") }, servletRegistrationBeans = { TestServlet.class }) TestFilter testFilter() { return new TestFilter(); } - } - - @Configuration(proxyBeanMethods = false) - static class FilterWithServletRegistrationBeansConfiguration { - @Bean ServletRegistrationBean testServletRegistrationBean() { - return new ServletRegistrationBean<>(new TestServlet(), "/test"); - } - - @Bean - @FilterRegistration(name = "testFilter", servletRegistrationBeans = TestServlet.class) - TestFilter testFilter() { - return new TestFilter(); + return new ServletRegistrationBean<>(new TestServlet()); } } From f8fba377d90a3d97bc1060336fdf42f6a3d28947 Mon Sep 17 00:00:00 2001 From: Daeho Kwon Date: Mon, 7 Apr 2025 21:38:20 +0900 Subject: [PATCH 3/6] Polish Signed-off-by: Daeho Kwon --- .../servlet/ServletContextInitializerBeansTests.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java index d2e6e85be217..ce571c2bb25d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java @@ -302,6 +302,18 @@ ServletRegistrationBean testServletRegistrationBean() { return new ServletRegistrationBean<>(new TestServlet()); } + @Bean + ServletRegistrationBean nonMatchingServletRegistrationBean() { + return new ServletRegistrationBean<>(new NonMatchingServlet()); + } + + static class NonMatchingServlet extends HttpServlet implements ServletContextInitializer { + @Override + public void onStartup(ServletContext servletContext) { + + } + } + } @Configuration(proxyBeanMethods = false) From e606ad5397a0f950099124d431d586e875399e62 Mon Sep 17 00:00:00 2001 From: Daeho Kwon Date: Tue, 8 Apr 2025 20:04:13 +0900 Subject: [PATCH 4/6] Polish Signed-off-by: Daeho Kwon --- .../web/servlet/ServletContextInitializerBeans.java | 1 + .../ServletContextInitializerBeansTests.java | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java index af801d18dedd..f5e805df2891 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java @@ -63,6 +63,7 @@ * @author Phillip Webb * @author Brian Clozel * @author Moritz Halbritter + * @author Daeho Kwon * @since 1.4.0 */ public class ServletContextInitializerBeans extends AbstractCollection { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java index ce571c2bb25d..8461433123b6 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java @@ -142,10 +142,11 @@ void shouldApplyFilterRegistrationAnnotation() { assertThat(filterRegistrationBean.getUrlPatterns()).containsExactly("/test/*"); assertThat(filterRegistrationBean.getInitParameters()).containsEntry("env", "test") .containsEntry("debug", "true"); - Collection> servletRegistrationBeans = filterRegistrationBean.getServletRegistrationBeans(); + Collection> servletRegistrationBeans = filterRegistrationBean + .getServletRegistrationBeans(); assertThat(servletRegistrationBeans).hasSize(1); assertThat(servletRegistrationBeans.iterator().next().getServletName()) - .isEqualTo("testServletRegistrationBean"); + .isEqualTo("testServletRegistrationBean"); }); } @@ -291,8 +292,10 @@ static class FilterConfigurationWithAnnotation { @Bean @FilterRegistration(enabled = false, name = "test", asyncSupported = false, dispatcherTypes = DispatcherType.ERROR, matchAfter = true, servletNames = "test", - urlPatterns = "/test/*", initParameters = { @WebInitParam(name = "env", value = "test"), - @WebInitParam(name = "debug", value = "true") }, servletRegistrationBeans = { TestServlet.class }) + urlPatterns = "/test/*", + initParameters = { @WebInitParam(name = "env", value = "test"), + @WebInitParam(name = "debug", value = "true") }, + servletRegistrationBeans = { TestServlet.class }) TestFilter testFilter() { return new TestFilter(); } @@ -308,10 +311,12 @@ ServletRegistrationBean nonMatchingServletRegistrationBean() } static class NonMatchingServlet extends HttpServlet implements ServletContextInitializer { + @Override public void onStartup(ServletContext servletContext) { } + } } From 7ac49cbee38e1a6fe62c83e393de50f7ece4b493 Mon Sep 17 00:00:00 2001 From: Daeho Kwon Date: Tue, 8 Apr 2025 20:33:50 +0900 Subject: [PATCH 5/6] Add javadoc author Signed-off-by: Daeho Kwon --- .../boot/web/servlet/ServletContextInitializerBeans.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java index c9cf8b800f17..b040f075d791 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java @@ -64,6 +64,7 @@ * @author Phillip Webb * @author Brian Clozel * @author Moritz Halbritter + * @author Daeho Kwon * @since 1.4.0 */ public class ServletContextInitializerBeans extends AbstractCollection { @@ -318,7 +319,9 @@ private void configureFromAnnotation(ServletRegistrationBean bean, Serv bean.setAsyncSupported(registration.asyncSupported()); bean.setIgnoreRegistrationFailure(registration.ignoreRegistrationFailure()); bean.setLoadOnStartup(registration.loadOnStartup()); - bean.setUrlMappings(Arrays.asList(registration.urlMappings())); + if (registration.urlMappings().length > 0) { + bean.setUrlMappings(Arrays.asList(registration.urlMappings())); + } } } From a273627d9a54bced374dabd1cb2034034f978570 Mon Sep 17 00:00:00 2001 From: Daeho Kwon Date: Tue, 8 Apr 2025 20:42:10 +0900 Subject: [PATCH 6/6] Revert merge mistake: restore urlMappings assignment Signed-off-by: Daeho Kwon --- .../boot/web/servlet/ServletContextInitializerBeans.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java index b040f075d791..5d2d03cb4649 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java @@ -319,9 +319,7 @@ private void configureFromAnnotation(ServletRegistrationBean bean, Serv bean.setAsyncSupported(registration.asyncSupported()); bean.setIgnoreRegistrationFailure(registration.ignoreRegistrationFailure()); bean.setLoadOnStartup(registration.loadOnStartup()); - if (registration.urlMappings().length > 0) { - bean.setUrlMappings(Arrays.asList(registration.urlMappings())); - } + bean.setUrlMappings(Arrays.asList(registration.urlMappings())); } }