Skip to content

Commit e57b942

Browse files
committed
MockMvcBuilder supports filter name in addition to initParams
Closes gh-31474
1 parent ef47eef commit e57b942

File tree

6 files changed

+79
-48
lines changed

6 files changed

+79
-48
lines changed

spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ public final <T extends B> T addFilter(Filter filter, String... urlPatterns) {
100100

101101
@Override
102102
public <T extends B> T addFilter(
103-
Filter filter, Map<String, String> initParams,
103+
Filter filter, @Nullable String filterName, Map<String, String> initParams,
104104
EnumSet<DispatcherType> dispatcherTypes, String... urlPatterns) {
105105

106-
filter = new MockMvcFilterDecorator(filter, initParams, dispatcherTypes, urlPatterns);
106+
filter = new MockMvcFilterDecorator(filter, filterName, initParams, dispatcherTypes, urlPatterns);
107107
this.filters.add(filter);
108108
return self();
109109
}

spring-test/src/main/java/org/springframework/test/web/servlet/setup/ConfigurableMockMvcBuilder.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import jakarta.servlet.Filter;
2525
import jakarta.servlet.FilterConfig;
2626

27+
import org.springframework.lang.Nullable;
2728
import org.springframework.test.web.servlet.DispatcherServletCustomizer;
2829
import org.springframework.test.web.servlet.MockMvcBuilder;
2930
import org.springframework.test.web.servlet.RequestBuilder;
@@ -51,7 +52,7 @@ public interface ConfigurableMockMvcBuilder<B extends ConfigurableMockMvcBuilder
5152
/**
5253
* Add a filter mapped to specific patterns.
5354
* <p>Note: if you need the filter to be initialized with {@link Filter#init(FilterConfig)},
54-
* please use {@link #addFilter(Filter, Map, EnumSet, String...)} instead.
55+
* please use {@link #addFilter(Filter, String, Map, EnumSet, String...)} instead.
5556
* @param filter the filter to add
5657
* @param urlPatterns the URL patterns to map to; if empty, matches all requests
5758
*/
@@ -62,14 +63,17 @@ public interface ConfigurableMockMvcBuilder<B extends ConfigurableMockMvcBuilder
6263
* with the given init parameters, and will also apply only to requests that
6364
* match the given dispatcher types and URL patterns.
6465
* @param filter the filter to add
66+
* @param filterName the name to use for the filter; if {@code null}, then
67+
* {@link org.springframework.mock.web.MockFilterConfig} is created without
68+
* a name, which defaults to an empty String for the name
6569
* @param initParams the init parameters to initialize the filter with
6670
* @param dispatcherTypes dispatcher types the filter applies to
6771
* @param urlPatterns the URL patterns to map to; if empty, matches all requests
6872
* @since 6.1
6973
* @see org.springframework.mock.web.MockFilterConfig
7074
*/
7175
<T extends B> T addFilter(
72-
Filter filter, Map<String, String> initParams,
76+
Filter filter, @Nullable String filterName, Map<String, String> initParams,
7377
EnumSet<DispatcherType> dispatcherTypes, String... urlPatterns);
7478

7579
/**

spring-test/src/main/java/org/springframework/test/web/servlet/setup/MockMvcFilterDecorator.java

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.EnumSet;
2222
import java.util.List;
2323
import java.util.Map;
24+
import java.util.function.Function;
2425

2526
import jakarta.servlet.DispatcherType;
2627
import jakarta.servlet.Filter;
@@ -56,7 +57,7 @@ final class MockMvcFilterDecorator implements Filter {
5657
private final Filter delegate;
5758

5859
@Nullable
59-
private final Map<String, String> initParams;
60+
private final Function<ServletContext, FilterConfig> filterConfigInitializer;
6061

6162
@Nullable
6263
private final EnumSet<DispatcherType> dispatcherTypes;
@@ -78,46 +79,64 @@ final class MockMvcFilterDecorator implements Filter {
7879
* <p>Note: when this constructor is used, the Filter is not initialized.
7980
*/
8081
public MockMvcFilterDecorator(Filter delegate, String[] urlPatterns) {
81-
this(delegate, null, null, urlPatterns);
82+
Assert.notNull(delegate, "filter cannot be null");
83+
Assert.notNull(urlPatterns, "urlPatterns cannot be null");
84+
this.delegate = delegate;
85+
this.filterConfigInitializer = null;
86+
this.dispatcherTypes = null;
87+
this.hasPatterns = initPatterns(urlPatterns);
8288
}
8389

8490
/**
8591
* Create instance with init parameters to initialize the filter with,
8692
* as well as dispatcher types and URL patterns to match.
8793
*/
8894
public MockMvcFilterDecorator(
89-
Filter delegate, @Nullable Map<String, String> initParams,
95+
Filter delegate, @Nullable String filterName, @Nullable Map<String, String> initParams,
9096
@Nullable EnumSet<DispatcherType> dispatcherTypes, String... urlPatterns) {
9197

9298
Assert.notNull(delegate, "filter cannot be null");
9399
Assert.notNull(urlPatterns, "urlPatterns cannot be null");
94100
this.delegate = delegate;
95-
this.initParams = initParams;
101+
this.filterConfigInitializer = getFilterConfigInitializer(filterName, initParams);
96102
this.dispatcherTypes = dispatcherTypes;
97-
this.hasPatterns = (urlPatterns.length != 0);
98-
for (String urlPattern : urlPatterns) {
99-
addUrlPattern(urlPattern);
100-
}
103+
this.hasPatterns = initPatterns(urlPatterns);
101104
}
102105

103-
private void addUrlPattern(String urlPattern) {
104-
Assert.notNull(urlPattern, "Found null URL Pattern");
105-
if (urlPattern.startsWith(EXTENSION_MAPPING_PATTERN)) {
106-
this.endsWithMatches.add(urlPattern.substring(1));
107-
}
108-
else if (urlPattern.equals(PATH_MAPPING_PATTERN) || urlPattern.equals(ALL_MAPPING_PATTERN)) {
109-
this.startsWithMatches.add("");
110-
}
111-
else if (urlPattern.endsWith(PATH_MAPPING_PATTERN)) {
112-
this.startsWithMatches.add(urlPattern.substring(0, urlPattern.length() - 1));
113-
this.exactMatches.add(urlPattern.substring(0, urlPattern.length() - 2));
114-
}
115-
else {
116-
if (urlPattern.isEmpty()) {
117-
urlPattern = "/";
106+
private static Function<ServletContext, FilterConfig> getFilterConfigInitializer(
107+
@Nullable String filterName, @Nullable Map<String, String> initParams) {
108+
109+
return servletContext -> {
110+
MockFilterConfig filterConfig = (filterName != null ?
111+
new MockFilterConfig(servletContext, filterName) : new MockFilterConfig(servletContext));
112+
if (initParams != null) {
113+
initParams.forEach(filterConfig::addInitParameter);
114+
}
115+
return filterConfig;
116+
};
117+
}
118+
119+
private boolean initPatterns(String... urlPatterns) {
120+
for (String urlPattern : urlPatterns) {
121+
Assert.notNull(urlPattern, "Found null URL Pattern");
122+
if (urlPattern.startsWith(EXTENSION_MAPPING_PATTERN)) {
123+
this.endsWithMatches.add(urlPattern.substring(1));
124+
}
125+
else if (urlPattern.equals(PATH_MAPPING_PATTERN) || urlPattern.equals(ALL_MAPPING_PATTERN)) {
126+
this.startsWithMatches.add("");
127+
}
128+
else if (urlPattern.endsWith(PATH_MAPPING_PATTERN)) {
129+
this.startsWithMatches.add(urlPattern.substring(0, urlPattern.length() - 1));
130+
this.exactMatches.add(urlPattern.substring(0, urlPattern.length() - 2));
131+
}
132+
else {
133+
if (urlPattern.isEmpty()) {
134+
urlPattern = "/";
135+
}
136+
this.exactMatches.add(urlPattern);
118137
}
119-
this.exactMatches.add(urlPattern);
120138
}
139+
return (urlPatterns.length != 0);
121140
}
122141

123142

@@ -177,9 +196,8 @@ public void destroy() {
177196
}
178197

179198
public void initIfRequired(@Nullable ServletContext servletContext) throws ServletException {
180-
if (this.initParams != null) {
181-
MockFilterConfig filterConfig = new MockFilterConfig(servletContext);
182-
this.initParams.forEach(filterConfig::addInitParameter);
199+
if (this.filterConfigInitializer != null) {
200+
FilterConfig filterConfig = this.filterConfigInitializer.apply(servletContext);
183201
this.delegate.init(filterConfig);
184202
}
185203
}

spring-test/src/test/java/org/springframework/test/web/servlet/setup/MockMvcFilterDecoratorTests.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,14 @@ public void setup() {
6666
@Test
6767
public void init() throws Exception {
6868
FilterConfig config = new MockFilterConfig();
69-
filter = new MockMvcFilterDecorator(delegate, null, null, "/");
69+
filter = new MockMvcFilterDecorator(delegate, new String[] {"/"});
7070
filter.init(config);
7171
assertThat(delegate.filterConfig).isEqualTo(config);
7272
}
7373

7474
@Test
7575
public void destroy() {
76-
filter = new MockMvcFilterDecorator(delegate, null, null, "/");
76+
filter = new MockMvcFilterDecorator(delegate, new String[] {"/"});
7777
filter.destroy();
7878
assertThat(delegate.destroy).isTrue();
7979
}
@@ -251,7 +251,7 @@ private void assertFilterNotInvoked(
251251

252252
request.setDispatcherType(requestDispatcherType);
253253
request.setRequestURI(request.getContextPath() + requestUri);
254-
filter = new MockMvcFilterDecorator(delegate, null, EnumSet.of(filterDispatcherType), pattern);
254+
filter = new MockMvcFilterDecorator(delegate, null, null, EnumSet.of(filterDispatcherType), pattern);
255255
filter.doFilter(request, response, filterChain);
256256

257257
assertThat(delegate.request).isNull();
@@ -265,7 +265,7 @@ private void assertFilterNotInvoked(
265265

266266
private void assertFilterInvoked(String requestUri, String pattern) throws Exception {
267267
request.setRequestURI(request.getContextPath() + requestUri);
268-
filter = new MockMvcFilterDecorator(delegate, null, null, pattern);
268+
filter = new MockMvcFilterDecorator(delegate, new String[] {pattern});
269269
filter.doFilter(request, response, filterChain);
270270

271271
assertThat(delegate.request).isEqualTo(request);

spring-test/src/test/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilderTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ void addFilterWithInitParams() throws ServletException {
134134
ArgumentCaptor<FilterConfig> captor = ArgumentCaptor.forClass(FilterConfig.class);
135135

136136
MockMvcBuilders.standaloneSetup(new PersonController())
137-
.addFilter(filter, Map.of("p", "v"), EnumSet.of(DispatcherType.REQUEST), "/")
137+
.addFilter(filter, null, Map.of("p", "v"), EnumSet.of(DispatcherType.REQUEST), "/")
138138
.build();
139139

140140
verify(filter, times(1)).init(captor.capture());

spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -132,22 +132,12 @@ else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
132132
}
133133

134134
if (binderFactory != null && (arg != null || !hasDefaultValue)) {
135-
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
136-
try {
137-
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
138-
}
139-
catch (ConversionNotSupportedException ex) {
140-
throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
141-
namedValueInfo.name, parameter, ex.getCause());
142-
}
143-
catch (TypeMismatchException ex) {
144-
throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
145-
namedValueInfo.name, parameter, ex.getCause());
146-
}
135+
arg = convertIfNecessary(parameter, webRequest, binderFactory, namedValueInfo, arg);
147136
// Check for null value after conversion of incoming argument value
148137
if (arg == null) {
149138
if (namedValueInfo.defaultValue != null) {
150139
arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
140+
arg = convertIfNecessary(parameter, webRequest, binderFactory, namedValueInfo, arg);
151141
}
152142
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
153143
handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest);
@@ -284,6 +274,25 @@ else if (paramType.isPrimitive()) {
284274
return value;
285275
}
286276

277+
private static Object convertIfNecessary(
278+
MethodParameter parameter, NativeWebRequest webRequest, WebDataBinderFactory binderFactory,
279+
NamedValueInfo namedValueInfo, Object arg) throws Exception {
280+
281+
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
282+
try {
283+
arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
284+
}
285+
catch (ConversionNotSupportedException ex) {
286+
throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
287+
namedValueInfo.name, parameter, ex.getCause());
288+
}
289+
catch (TypeMismatchException ex) {
290+
throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
291+
namedValueInfo.name, parameter, ex.getCause());
292+
}
293+
return arg;
294+
}
295+
287296
/**
288297
* Invoked after a value is resolved.
289298
* @param arg the resolved argument value

0 commit comments

Comments
 (0)