Skip to content

Commit 8499253

Browse files
committed
Defer initialization of HandlerMethod validation flags
Re-create the HandlerMethod only after the original is used as a key in the CORS lookup map. Closes gh-34375
1 parent ff49b0b commit 8499253

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 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.
@@ -636,9 +636,6 @@ public void register(T mapping, Object handler, Method method) {
636636
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
637637
validateMethodMapping(handlerMethod, mapping);
638638

639-
// Enable method validation, if applicable
640-
handlerMethod = handlerMethod.createWithValidateFlags();
641-
642639
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
643640
for (String path : directPaths) {
644641
this.pathLookup.add(path, mapping);
@@ -657,6 +654,10 @@ public void register(T mapping, Object handler, Method method) {
657654
this.corsLookup.put(handlerMethod, corsConfig);
658655
}
659656

657+
// Init validation flags
658+
// We do this strictly after using the original instance in the CORS lookups
659+
handlerMethod = handlerMethod.createWithValidateFlags();
660+
660661
this.registry.put(mapping,
661662
new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
662663
}

spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 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.
@@ -292,6 +292,23 @@ void getCorsConfigWithBeanNameHandler() throws Exception {
292292
HandlerMethod handlerMethod = this.mapping.getHandlerInternal(new MockHttpServletRequest("GET", key));
293293
}
294294

295+
@Test
296+
void registerCustomHandlerMethod() throws Exception {
297+
this.mapping.setCustomerHandlerMethod(true);
298+
this.mapping.registerMapping("/foo", this.handler, this.handler.getClass().getMethod("corsHandlerMethod"));
299+
300+
MockHttpServletRequest request = new MockHttpServletRequest("OPTIONS", "/foo");
301+
request.addParameter("abort", "true");
302+
request.addHeader(HttpHeaders.ORIGIN, "https://domain.com");
303+
request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET");
304+
305+
MockHttpServletResponse response = new MockHttpServletResponse();
306+
307+
HandlerExecutionChain chain = this.mapping.getHandler(request);
308+
309+
assertThat(chain).isNotNull();
310+
assertThat(response.getStatus()).isEqualTo(200);
311+
}
295312

296313

297314
private static class MyHandlerMethodMapping extends AbstractHandlerMethodMapping<String> {
@@ -302,6 +319,8 @@ private static class MyHandlerMethodMapping extends AbstractHandlerMethodMapping
302319

303320
private final List<String> matches = new ArrayList<>();
304321

322+
private boolean customerHandlerMethod;
323+
305324
public MyHandlerMethodMapping() {
306325
setHandlerMethodMappingNamingStrategy(new SimpleMappingNamingStrategy());
307326
}
@@ -326,6 +345,16 @@ protected String getMappingForMethod(Method method, Class<?> handlerType) {
326345
return methodName.startsWith("handler") ? methodName : null;
327346
}
328347

348+
public void setCustomerHandlerMethod(boolean customerHandlerMethod) {
349+
this.customerHandlerMethod = customerHandlerMethod;
350+
}
351+
352+
@Override
353+
protected HandlerMethod createHandlerMethod(Object handler, Method method) {
354+
return (this.customerHandlerMethod ?
355+
new CustomHandlerMethod(handler, method) : super.createHandlerMethod(handler, method));
356+
}
357+
329358
@Override
330359
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, String mapping) {
331360
CrossOrigin crossOrigin = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);
@@ -355,6 +384,7 @@ protected Comparator<String> getMappingComparator(HttpServletRequest request) {
355384

356385
}
357386

387+
358388
private static class SimpleMappingNamingStrategy implements HandlerMethodMappingNamingStrategy<String> {
359389

360390
@Override
@@ -363,6 +393,16 @@ public String getName(HandlerMethod handlerMethod, String mapping) {
363393
}
364394
}
365395

396+
397+
private static class CustomHandlerMethod extends HandlerMethod {
398+
399+
public CustomHandlerMethod(Object bean, Method method) {
400+
super(bean, method);
401+
}
402+
403+
}
404+
405+
366406
@Controller
367407
static class MyHandler {
368408

0 commit comments

Comments
 (0)