Browse Source

Merge branch '6.0.x'

pull/31063/head
Juergen Hoeller 1 year ago
parent
commit
86a101ac2b
  1. 27
      spring-context/src/main/java/org/springframework/validation/annotation/ValidationAnnotationUtils.java
  2. 4
      spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java
  3. 19
      spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/reactive/PayloadMethodArgumentResolver.java
  4. 19
      spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadMethodArgumentResolver.java

27
spring-context/src/main/java/org/springframework/validation/annotation/ValidationAnnotationUtils.java

@ -26,37 +26,46 @@ import org.springframework.lang.Nullable;
* Mainly for internal use within the framework. * Mainly for internal use within the framework.
* *
* @author Christoph Dreis * @author Christoph Dreis
* @author Juergen Hoeller
* @since 5.3.7 * @since 5.3.7
*/ */
public abstract class ValidationAnnotationUtils { public abstract class ValidationAnnotationUtils {
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
/** /**
* Determine any validation hints by the given annotation. * Determine any validation hints by the given annotation.
* <p>This implementation checks for {@code @jakarta.validation.Valid}, * <p>This implementation checks for Spring's
* Spring's {@link org.springframework.validation.annotation.Validated}, * {@link org.springframework.validation.annotation.Validated},
* and custom annotations whose name starts with "Valid". * {@code @jakarta.validation.Valid}, and custom annotations whose
* name starts with "Valid" which may optionally declare validation
* hints through the "value" attribute.
* @param ann the annotation (potentially a validation annotation) * @param ann the annotation (potentially a validation annotation)
* @return the validation hints to apply (possibly an empty array), * @return the validation hints to apply (possibly an empty array),
* or {@code null} if this annotation does not trigger any validation * or {@code null} if this annotation does not trigger any validation
*/ */
@Nullable @Nullable
public static Object[] determineValidationHints(Annotation ann) { public static Object[] determineValidationHints(Annotation ann) {
// Direct presence of @Validated ?
if (ann instanceof Validated validated) {
return validated.value();
}
// Direct presence of @Valid ?
Class<? extends Annotation> annotationType = ann.annotationType(); Class<? extends Annotation> annotationType = ann.annotationType();
String annotationName = annotationType.getName(); if ("jakarta.validation.Valid".equals(annotationType.getName())) {
if ("jakarta.validation.Valid".equals(annotationName)) {
return EMPTY_OBJECT_ARRAY; return EMPTY_OBJECT_ARRAY;
} }
// Meta presence of @Validated ?
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
if (validatedAnn != null) { if (validatedAnn != null) {
Object hints = validatedAnn.value(); return validatedAnn.value();
return convertValidationHints(hints);
} }
// Custom validation annotation ?
if (annotationType.getSimpleName().startsWith("Valid")) { if (annotationType.getSimpleName().startsWith("Valid")) {
Object hints = AnnotationUtils.getValue(ann); return convertValidationHints(AnnotationUtils.getValue(ann));
return convertValidationHints(hints);
} }
// No validation triggered
return null; return null;
} }

4
spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

@ -1309,8 +1309,8 @@ public abstract class AnnotationUtils {
*/ */
public static boolean isSynthesizedAnnotation(@Nullable Annotation annotation) { public static boolean isSynthesizedAnnotation(@Nullable Annotation annotation) {
try { try {
return ((annotation != null) && Proxy.isProxyClass(annotation.getClass()) && return (annotation != null && Proxy.isProxyClass(annotation.getClass()) &&
(Proxy.getInvocationHandler(annotation) instanceof SynthesizedMergedAnnotationInvocationHandler)); Proxy.getInvocationHandler(annotation) instanceof SynthesizedMergedAnnotationInvocationHandler);
} }
catch (SecurityException ex) { catch (SecurityException ex) {
// Security settings disallow reflective access to the InvocationHandler: // Security settings disallow reflective access to the InvocationHandler:

19
spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/reactive/PayloadMethodArgumentResolver.java

@ -33,7 +33,6 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapter; import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.codec.Decoder; import org.springframework.core.codec.Decoder;
import org.springframework.core.codec.DecodingException; import org.springframework.core.codec.DecodingException;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
@ -54,17 +53,17 @@ import org.springframework.util.StringUtils;
import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.SmartValidator; import org.springframework.validation.SmartValidator;
import org.springframework.validation.Validator; import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.ValidationAnnotationUtils;
/** /**
* A resolver to extract and decode the payload of a message using a * A resolver to extract and decode the payload of a message using a
* {@link Decoder}, where the payload is expected to be a {@link Publisher} of * {@link Decoder}, where the payload is expected to be a {@link Publisher}
* {@link DataBuffer DataBuffer}. * of {@link DataBuffer DataBuffer}.
* *
* <p>Validation is applied if the method argument is annotated with * <p>Validation is applied if the method argument is annotated with
* {@code @jakarta.validation.Valid} or * {@link org.springframework.validation.annotation.Validated} or
* {@link org.springframework.validation.annotation.Validated}. Validation * {@code @jakarta.validation.Valid}. Validation failure results in an
* failure results in an {@link MethodArgumentNotValidException}. * {@link MethodArgumentNotValidException}.
* *
* <p>This resolver should be ordered last if {@link #useDefaultResolution} is * <p>This resolver should be ordered last if {@link #useDefaultResolution} is
* set to {@code true} since in that case it supports all types and does not * set to {@code true} since in that case it supports all types and does not
@ -286,10 +285,8 @@ public class PayloadMethodArgumentResolver implements HandlerMethodArgumentResol
return null; return null;
} }
for (Annotation ann : parameter.getParameterAnnotations()) { for (Annotation ann : parameter.getParameterAnnotations()) {
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { if (validationHints != null) {
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
Object[] validationHints = (hints instanceof Object[] objectHints ? objectHints : new Object[] {hints});
String name = Conventions.getVariableNameForParameter(parameter); String name = Conventions.getVariableNameForParameter(parameter);
return target -> { return target -> {
BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(target, name); BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(target, name);

19
spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadMethodArgumentResolver.java

@ -20,7 +20,6 @@ import java.lang.annotation.Annotation;
import java.util.Optional; import java.util.Optional;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
import org.springframework.messaging.converter.MessageConversionException; import org.springframework.messaging.converter.MessageConversionException;
@ -38,12 +37,16 @@ import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError; import org.springframework.validation.ObjectError;
import org.springframework.validation.SmartValidator; import org.springframework.validation.SmartValidator;
import org.springframework.validation.Validator; import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.ValidationAnnotationUtils;
/** /**
* A resolver to extract and convert the payload of a message using a * A resolver to extract and convert the payload of a message using a
* {@link MessageConverter}. It also validates the payload using a * {@link MessageConverter}.
* {@link Validator} if the argument is annotated with a Validation annotation. *
* <p>Validation is applied if the method argument is annotated with
* {@link org.springframework.validation.annotation.Validated} or
* {@code @jakarta.validation.Valid}. Validation failure results in an
* {@link MethodArgumentNotValidException}.
* *
* <p>This {@link HandlerMethodArgumentResolver} should be ordered last as it * <p>This {@link HandlerMethodArgumentResolver} should be ordered last as it
* supports all types and does not require the {@link Payload} annotation. * supports all types and does not require the {@link Payload} annotation.
@ -196,8 +199,6 @@ public class PayloadMethodArgumentResolver implements HandlerMethodArgumentResol
/** /**
* Validate the payload if applicable. * Validate the payload if applicable.
* <p>The default implementation checks for {@code @jakarta.validation.Valid},
* Spring's {@link Validated}, and custom annotations whose name starts with "Valid".
* @param message the currently processed message * @param message the currently processed message
* @param parameter the method parameter * @param parameter the method parameter
* @param target the target payload object * @param target the target payload object
@ -208,10 +209,8 @@ public class PayloadMethodArgumentResolver implements HandlerMethodArgumentResol
return; return;
} }
for (Annotation ann : parameter.getParameterAnnotations()) { for (Annotation ann : parameter.getParameterAnnotations()) {
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { if (validationHints != null) {
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
Object[] validationHints = (hints instanceof Object[] objectHints ? objectHints : new Object[] {hints});
BeanPropertyBindingResult bindingResult = BeanPropertyBindingResult bindingResult =
new BeanPropertyBindingResult(target, getParameterName(parameter)); new BeanPropertyBindingResult(target, getParameterName(parameter));
if (!ObjectUtils.isEmpty(validationHints) && this.validator instanceof SmartValidator sv) { if (!ObjectUtils.isEmpty(validationHints) && this.validator instanceof SmartValidator sv) {

Loading…
Cancel
Save