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
This commit is contained in:
rstoyanchev 2025-02-07 13:10:33 +00:00
parent ff49b0b683
commit 84992536c5
2 changed files with 46 additions and 5 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -636,9 +636,6 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
validateMethodMapping(handlerMethod, mapping);
// Enable method validation, if applicable
handlerMethod = handlerMethod.createWithValidateFlags();
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
for (String path : directPaths) {
this.pathLookup.add(path, mapping);
@ -657,6 +654,10 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
this.corsLookup.put(handlerMethod, corsConfig);
}
// Init validation flags
// We do this strictly after using the original instance in the CORS lookups
handlerMethod = handlerMethod.createWithValidateFlags();
this.registry.put(mapping,
new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@ -292,6 +292,23 @@ public class HandlerMethodMappingTests {
HandlerMethod handlerMethod = this.mapping.getHandlerInternal(new MockHttpServletRequest("GET", key));
}
@Test
void registerCustomHandlerMethod() throws Exception {
this.mapping.setCustomerHandlerMethod(true);
this.mapping.registerMapping("/foo", this.handler, this.handler.getClass().getMethod("corsHandlerMethod"));
MockHttpServletRequest request = new MockHttpServletRequest("OPTIONS", "/foo");
request.addParameter("abort", "true");
request.addHeader(HttpHeaders.ORIGIN, "https://domain.com");
request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET");
MockHttpServletResponse response = new MockHttpServletResponse();
HandlerExecutionChain chain = this.mapping.getHandler(request);
assertThat(chain).isNotNull();
assertThat(response.getStatus()).isEqualTo(200);
}
private static class MyHandlerMethodMapping extends AbstractHandlerMethodMapping<String> {
@ -302,6 +319,8 @@ public class HandlerMethodMappingTests {
private final List<String> matches = new ArrayList<>();
private boolean customerHandlerMethod;
public MyHandlerMethodMapping() {
setHandlerMethodMappingNamingStrategy(new SimpleMappingNamingStrategy());
}
@ -326,6 +345,16 @@ public class HandlerMethodMappingTests {
return methodName.startsWith("handler") ? methodName : null;
}
public void setCustomerHandlerMethod(boolean customerHandlerMethod) {
this.customerHandlerMethod = customerHandlerMethod;
}
@Override
protected HandlerMethod createHandlerMethod(Object handler, Method method) {
return (this.customerHandlerMethod ?
new CustomHandlerMethod(handler, method) : super.createHandlerMethod(handler, method));
}
@Override
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, String mapping) {
CrossOrigin crossOrigin = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);
@ -355,6 +384,7 @@ public class HandlerMethodMappingTests {
}
private static class SimpleMappingNamingStrategy implements HandlerMethodMappingNamingStrategy<String> {
@Override
@ -363,6 +393,16 @@ public class HandlerMethodMappingTests {
}
}
private static class CustomHandlerMethod extends HandlerMethod {
public CustomHandlerMethod(Object bean, Method method) {
super(bean, method);
}
}
@Controller
static class MyHandler {