Avoid exceptions when evaluating validation hints
Prior to this commit, evaluating validation hints for @javax.validation.Valid caused exceptions being raised when getting the value of this annotation, which does not exist. Bypassing AnnotationUtils.getValue() in those cases can improve performance by avoiding the cost incurred by raising exceptions. See gh-26787
This commit is contained in:
parent
d275a4e28d
commit
e7cbe23771
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.validation.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Utility class for handling validation annotations.
|
||||
* Mainly for internal use within the framework.
|
||||
*
|
||||
* @author Christoph Dreis
|
||||
* @since 5.3.7
|
||||
*/
|
||||
public abstract class ValidationAnnotationUtils {
|
||||
|
||||
/**
|
||||
* Determine any validation hints by the given annotation.
|
||||
* <p>This implementation checks for {@code @javax.validation.Valid},
|
||||
* Spring's {@link org.springframework.validation.annotation.Validated},
|
||||
* and custom annotations whose name starts with "Valid".
|
||||
* @param ann the annotation (potentially a validation annotation)
|
||||
* @return the validation hints to apply (possibly an empty array),
|
||||
* or {@code null} if this annotation does not trigger any validation
|
||||
* @since 5.3.7
|
||||
*/
|
||||
@Nullable
|
||||
public static Object[] determineValidationHints(Annotation ann) {
|
||||
Class<? extends Annotation> annotationType = ann.annotationType();
|
||||
String annotationName = annotationType.getName();
|
||||
if ("javax.validation.Valid".equals(annotationName)) {
|
||||
return new Object[0];
|
||||
}
|
||||
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
|
||||
if (validatedAnn != null) {
|
||||
Object hints = validatedAnn.value();
|
||||
return convertValidationHints(hints);
|
||||
}
|
||||
if (annotationType.getSimpleName().startsWith("Valid")) {
|
||||
Object hints = AnnotationUtils.getValue(ann);
|
||||
return convertValidationHints(hints);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Object[] convertValidationHints(@Nullable Object hints) {
|
||||
if (hints == null) {
|
||||
return new Object[0];
|
||||
}
|
||||
return (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
|
@ -37,7 +37,6 @@ import org.springframework.beans.BeanInstantiationException;
|
|||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.TypeMismatchException;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
@ -46,7 +45,7 @@ import org.springframework.validation.BindingResult;
|
|||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.SmartValidator;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.annotation.ValidationAnnotationUtils;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
|
@ -362,7 +361,7 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
|||
*/
|
||||
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
|
||||
for (Annotation ann : parameter.getParameterAnnotations()) {
|
||||
Object[] validationHints = determineValidationHints(ann);
|
||||
Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
|
||||
if (validationHints != null) {
|
||||
binder.validate(validationHints);
|
||||
break;
|
||||
|
@ -388,7 +387,7 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
|||
Class<?> targetType, String fieldName, @Nullable Object value) {
|
||||
|
||||
for (Annotation ann : parameter.getParameterAnnotations()) {
|
||||
Object[] validationHints = determineValidationHints(ann);
|
||||
Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
|
||||
if (validationHints != null) {
|
||||
for (Validator validator : binder.getValidators()) {
|
||||
if (validator instanceof SmartValidator) {
|
||||
|
@ -406,26 +405,6 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine any validation triggered by the given annotation.
|
||||
* @param ann the annotation (potentially a validation annotation)
|
||||
* @return the validation hints to apply (possibly an empty array),
|
||||
* or {@code null} if this annotation does not trigger any validation
|
||||
* @since 5.1
|
||||
*/
|
||||
@Nullable
|
||||
private Object[] determineValidationHints(Annotation ann) {
|
||||
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
|
||||
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
|
||||
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
|
||||
if (hints == null) {
|
||||
return new Object[0];
|
||||
}
|
||||
return (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to raise a fatal bind exception on validation errors.
|
||||
* <p>The default implementation delegates to {@link #isBindExceptionRequired(MethodParameter)}.
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.springframework.core.MethodParameter;
|
|||
import org.springframework.core.ReactiveAdapter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.codec.DecodingException;
|
||||
import org.springframework.core.codec.Hints;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
|
@ -45,7 +44,7 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
|
|||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.annotation.ValidationAnnotationUtils;
|
||||
import org.springframework.web.bind.support.WebExchangeBindException;
|
||||
import org.springframework.web.bind.support.WebExchangeDataBinder;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
|
@ -240,10 +239,9 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
|
|||
private Object[] extractValidationHints(MethodParameter parameter) {
|
||||
Annotation[] annotations = parameter.getParameterAnnotations();
|
||||
for (Annotation ann : annotations) {
|
||||
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
|
||||
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
|
||||
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
|
||||
return (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
|
||||
Object[] hints = ValidationAnnotationUtils.determineValidationHints(ann);
|
||||
if (hints != null) {
|
||||
return hints;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
|
@ -30,14 +30,13 @@ import org.springframework.core.MethodParameter;
|
|||
import org.springframework.core.ReactiveAdapter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.annotation.ValidationAnnotationUtils;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.support.WebExchangeBindException;
|
||||
import org.springframework.web.bind.support.WebExchangeDataBinder;
|
||||
|
@ -270,16 +269,9 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
|
|||
|
||||
private void validateIfApplicable(WebExchangeDataBinder binder, MethodParameter parameter) {
|
||||
for (Annotation ann : parameter.getParameterAnnotations()) {
|
||||
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
|
||||
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
|
||||
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
|
||||
if (hints != null) {
|
||||
Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
|
||||
binder.validate(validationHints);
|
||||
}
|
||||
else {
|
||||
binder.validate();
|
||||
}
|
||||
Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
|
||||
if (validationHints != null) {
|
||||
binder.validate(validationHints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ import org.apache.commons.logging.LogFactory;
|
|||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.log.LogFormatUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
|
@ -52,7 +51,7 @@ import org.springframework.lang.Nullable;
|
|||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.annotation.ValidationAnnotationUtils;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
@ -241,10 +240,8 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
|||
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
|
||||
Annotation[] annotations = parameter.getParameterAnnotations();
|
||||
for (Annotation ann : annotations) {
|
||||
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
|
||||
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
|
||||
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
|
||||
Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
|
||||
Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
|
||||
if (validationHints != null) {
|
||||
binder.validate(validationHints);
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue