Skip to content

Commit e7eaaad

Browse files
committed
Explicit initialization of shouldValidate flags
Closes gh-32007
1 parent f6e5290 commit e7eaaad

File tree

6 files changed

+47
-34
lines changed

6 files changed

+47
-34
lines changed

spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -72,6 +72,7 @@ public class HandlerMethod extends AnnotatedMethod {
7272
/** Logger that is available to subclasses. */
7373
protected static final Log logger = LogFactory.getLog(HandlerMethod.class);
7474

75+
7576
private final Object bean;
7677

7778
@Nullable
@@ -116,8 +117,8 @@ protected HandlerMethod(Object bean, Method method, @Nullable MessageSource mess
116117
this.beanFactory = null;
117118
this.messageSource = messageSource;
118119
this.beanType = ClassUtils.getUserClass(bean);
119-
this.validateArguments = MethodValidationInitializer.checkArguments(this.beanType, getMethodParameters());
120-
this.validateReturnValue = MethodValidationInitializer.checkReturnValue(this.beanType, getBridgedMethod());
120+
this.validateArguments = false;
121+
this.validateReturnValue = false;
121122
evaluateResponseStatus();
122123
this.description = initDescription(this.beanType, method);
123124
}
@@ -132,8 +133,8 @@ public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes)
132133
this.beanFactory = null;
133134
this.messageSource = null;
134135
this.beanType = ClassUtils.getUserClass(bean);
135-
this.validateArguments = MethodValidationInitializer.checkArguments(this.beanType, getMethodParameters());
136-
this.validateReturnValue = MethodValidationInitializer.checkReturnValue(this.beanType, getBridgedMethod());
136+
this.validateArguments = false;
137+
this.validateReturnValue = false;
137138
evaluateResponseStatus();
138139
this.description = initDescription(this.beanType, getMethod());
139140
}
@@ -166,8 +167,8 @@ public HandlerMethod(
166167
throw new IllegalStateException("Cannot resolve bean type for bean with name '" + beanName + "'");
167168
}
168169
this.beanType = ClassUtils.getUserClass(beanType);
169-
this.validateArguments = MethodValidationInitializer.checkArguments(this.beanType, getMethodParameters());
170-
this.validateReturnValue = MethodValidationInitializer.checkReturnValue(this.beanType, getBridgedMethod());
170+
this.validateArguments = false;
171+
this.validateReturnValue = false;
171172
evaluateResponseStatus();
172173
this.description = initDescription(this.beanType, method);
173174
}
@@ -176,31 +177,24 @@ public HandlerMethod(
176177
* Copy constructor for use in subclasses.
177178
*/
178179
protected HandlerMethod(HandlerMethod handlerMethod) {
179-
super(handlerMethod);
180-
this.bean = handlerMethod.bean;
181-
this.beanFactory = handlerMethod.beanFactory;
182-
this.messageSource = handlerMethod.messageSource;
183-
this.beanType = handlerMethod.beanType;
184-
this.validateArguments = handlerMethod.validateArguments;
185-
this.validateReturnValue = handlerMethod.validateReturnValue;
186-
this.responseStatus = handlerMethod.responseStatus;
187-
this.responseStatusReason = handlerMethod.responseStatusReason;
188-
this.description = handlerMethod.description;
189-
this.resolvedFromHandlerMethod = handlerMethod.resolvedFromHandlerMethod;
180+
this(handlerMethod, null, false);
190181
}
191182

192183
/**
193-
* Re-create HandlerMethod with the resolved handler.
184+
* Re-create HandlerMethod with additional input.
194185
*/
195-
private HandlerMethod(HandlerMethod handlerMethod, Object handler) {
186+
private HandlerMethod(HandlerMethod handlerMethod, @Nullable Object handler, boolean initValidateFlags) {
196187
super(handlerMethod);
197-
Assert.notNull(handler, "Handler object is required");
198-
this.bean = handler;
188+
this.bean = (handler != null ? handler : handlerMethod.bean);
199189
this.beanFactory = handlerMethod.beanFactory;
200190
this.messageSource = handlerMethod.messageSource;
201191
this.beanType = handlerMethod.beanType;
202-
this.validateArguments = handlerMethod.validateArguments;
203-
this.validateReturnValue = handlerMethod.validateReturnValue;
192+
this.validateArguments = (initValidateFlags ?
193+
MethodValidationInitializer.checkArguments(this.beanType, getMethodParameters()) :
194+
handlerMethod.validateArguments);
195+
this.validateReturnValue = (initValidateFlags ?
196+
MethodValidationInitializer.checkReturnValue(this.beanType, getBridgedMethod()) :
197+
handlerMethod.validateReturnValue);
204198
this.responseStatus = handlerMethod.responseStatus;
205199
this.responseStatusReason = handlerMethod.responseStatusReason;
206200
this.resolvedFromHandlerMethod = handlerMethod;
@@ -313,6 +307,15 @@ public HandlerMethod getResolvedFromHandlerMethod() {
313307
return this.resolvedFromHandlerMethod;
314308
}
315309

310+
/**
311+
* Re-create the HandlerMethod and initialize
312+
* {@link #shouldValidateArguments()} and {@link #shouldValidateReturnValue()}.
313+
* @since 6.1.3
314+
*/
315+
public HandlerMethod createWithValidateFlags() {
316+
return new HandlerMethod(this, null, true);
317+
}
318+
316319
/**
317320
* If the provided instance contains a bean name rather than an object instance,
318321
* the bean name is resolved before a {@link HandlerMethod} is created and returned.
@@ -323,7 +326,8 @@ public HandlerMethod createWithResolvedBean() {
323326
Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
324327
handler = this.beanFactory.getBean(beanName);
325328
}
326-
return new HandlerMethod(this, handler);
329+
Assert.notNull(handler, "No handler instance");
330+
return new HandlerMethod(this, handler, false);
327331
}
328332

329333
/**
@@ -392,14 +396,17 @@ protected String formatInvokeError(String text, Object[] args) {
392396
*/
393397
private static class MethodValidationInitializer {
394398

399+
private static final boolean BEAN_VALIDATION_PRESENT =
400+
ClassUtils.isPresent("jakarta.validation.Validator", HandlerMethod.class.getClassLoader());
401+
395402
private static final Predicate<MergedAnnotation<? extends Annotation>> CONSTRAINT_PREDICATE =
396403
MergedAnnotationPredicates.typeIn("jakarta.validation.Constraint");
397404

398405
private static final Predicate<MergedAnnotation<? extends Annotation>> VALID_PREDICATE =
399406
MergedAnnotationPredicates.typeIn("jakarta.validation.Valid");
400407

401408
public static boolean checkArguments(Class<?> beanType, MethodParameter[] parameters) {
402-
if (AnnotationUtils.findAnnotation(beanType, Validated.class) == null) {
409+
if (BEAN_VALIDATION_PRESENT && AnnotationUtils.findAnnotation(beanType, Validated.class) == null) {
403410
for (MethodParameter param : parameters) {
404411
MergedAnnotations merged = MergedAnnotations.from(param.getParameterAnnotations());
405412
if (merged.stream().anyMatch(CONSTRAINT_PREDICATE)) {
@@ -419,7 +426,7 @@ public static boolean checkArguments(Class<?> beanType, MethodParameter[] parame
419426
}
420427

421428
public static boolean checkReturnValue(Class<?> beanType, Method method) {
422-
if (AnnotationUtils.findAnnotation(beanType, Validated.class) == null) {
429+
if (BEAN_VALIDATION_PRESENT && AnnotationUtils.findAnnotation(beanType, Validated.class) == null) {
423430
MergedAnnotations merged = MergedAnnotations.from(method, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
424431
return merged.stream().anyMatch(CONSTRAINT_PREDICATE.or(VALID_PREDICATE));
425432
}

spring-web/src/test/java/org/springframework/web/method/HandlerMethodTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ private static void testValidateReturnValue(Object target, List<String> methodNa
8686

8787
private static HandlerMethod getHandlerMethod(Object target, String methodName) {
8888
Method method = ClassUtils.getMethod(target.getClass(), methodName, (Class<?>[]) null);
89-
return new HandlerMethod(target, method);
89+
return new HandlerMethod(target, method).createWithValidateFlags();
9090
}
9191

9292

spring-webflux/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java

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

527+
// Enable method validation, if applicable
528+
handlerMethod = handlerMethod.createWithValidateFlags();
529+
527530
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
528531
for (String path : directPaths) {
529532
this.pathLookup.add(path, mapping);

spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MethodValidationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -339,7 +339,7 @@ void springValidator() throws Exception {
339339
@SuppressWarnings("unchecked")
340340
private static <T> HandlerMethod handlerMethod(T controller, Consumer<T> mockCallConsumer) {
341341
Method method = ResolvableMethod.on((Class<T>) controller.getClass()).mockCall(mockCallConsumer).method();
342-
return new HandlerMethod(controller, method);
342+
return new HandlerMethod(controller, method).createWithValidateFlags();
343343
}
344344

345345
private static MockServerHttpRequest.BodyBuilder request() {

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

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

635+
// Enable method validation, if applicable
636+
handlerMethod = handlerMethod.createWithValidateFlags();
637+
635638
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
636639
for (String path : directPaths) {
637640
this.pathLookup.add(path, mapping);

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MethodValidationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -301,7 +301,7 @@ void springValidator() throws Exception {
301301
@SuppressWarnings("unchecked")
302302
private static <T> HandlerMethod handlerMethod(T controller, Consumer<T> mockCallConsumer) {
303303
Method method = ResolvableMethod.on((Class<T>) controller.getClass()).mockCall(mockCallConsumer).method();
304-
return new HandlerMethod(controller, method);
304+
return new HandlerMethod(controller, method).createWithValidateFlags();
305305
}
306306

307307
@SuppressWarnings("SameParameterValue")

0 commit comments

Comments
 (0)