diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolver.java index ec6e86f9de..7a24738068 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolver.java @@ -34,14 +34,15 @@ import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.validation.SmartValidator; import org.springframework.validation.Validator; +import org.springframework.validation.annotation.Validated; /** * A resolver to extract and convert the payload of a message using a * {@link MessageConverter}. It also validates the payload using a * {@link Validator} if the argument is annotated with a Validation annotation. * - *
This {@link HandlerMethodArgumentResolver} should be ordered last as it supports all - * types and does not require the {@link Payload} annotation. + *
This {@link HandlerMethodArgumentResolver} should be ordered last as it + * supports all types and does not require the {@link Payload} annotation. * * @author Rossen Stoyanchev * @author Brian Clozel @@ -70,14 +71,14 @@ public class PayloadArgumentResolver implements HandlerMethodArgumentResolver { @Override public Object resolveArgument(MethodParameter param, Message> message) throws Exception { - Payload annot = param.getParameterAnnotation(Payload.class); - if ((annot != null) && StringUtils.hasText(annot.value())) { + Payload ann = param.getParameterAnnotation(Payload.class); + if (ann != null && StringUtils.hasText(ann.value())) { throw new IllegalStateException("@Payload SpEL expressions not supported by this resolver"); } Object payload = message.getPayload(); if (isEmptyPayload(payload)) { - if (annot == null || annot.required()) { + if (ann == null || ann.required()) { String paramName = getParameterName(param); BindingResult bindingResult = new BeanPropertyBindingResult(payload, paramName); bindingResult.addError(new ObjectError(paramName, "@Payload param is required")); @@ -97,7 +98,7 @@ public class PayloadArgumentResolver implements HandlerMethodArgumentResolver { payload = this.converter.fromMessage(message, targetClass); if (payload == null) { throw new MessageConversionException(message, - "No converter found to convert to " + targetClass + ", message=" + message, null); + "No converter found to convert to " + targetClass + ", message=" + message); } validate(message, param, payload); return payload; @@ -106,7 +107,7 @@ public class PayloadArgumentResolver implements HandlerMethodArgumentResolver { private String getParameterName(MethodParameter param) { String paramName = param.getParameterName(); - return (paramName == null ? "Arg " + param.getParameterIndex() : paramName); + return (paramName != null ? paramName : "Arg " + param.getParameterIndex()); } /** @@ -132,26 +133,22 @@ public class PayloadArgumentResolver implements HandlerMethodArgumentResolver { if (this.validator == null) { return; } - - for (Annotation annot : parameter.getParameterAnnotations()) { - if (annot.annotationType().getSimpleName().startsWith("Valid")) { + 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)); + Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(target, getParameterName(parameter)); - - Object hints = AnnotationUtils.getValue(annot); - Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); - if (!ObjectUtils.isEmpty(validationHints) && this.validator instanceof SmartValidator) { ((SmartValidator) this.validator).validate(target, bindingResult, validationHints); } else { this.validator.validate(target, bindingResult); } - if (bindingResult.hasErrors()) { throw new MethodArgumentNotValidException(message, parameter, bindingResult); } - break; } } diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolverTests.java index a75f34fd49..2c40b6b465 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PayloadArgumentResolverTests.java @@ -16,6 +16,10 @@ package org.springframework.messaging.handler.annotation.support; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.Locale; @@ -72,10 +76,8 @@ public class PayloadArgumentResolverTests { @Before public void setup() throws Exception { - this.resolver = new PayloadArgumentResolver(new StringMessageConverter(), testValidator()); - - payloadMethod = PayloadArgumentResolverTests.class.getDeclaredMethod("handleMessage", + this.payloadMethod = PayloadArgumentResolverTests.class.getDeclaredMethod("handleMessage", String.class, String.class, Locale.class, String.class, String.class, String.class, String.class); this.paramAnnotated = getMethodParameter(this.payloadMethod, 0); @@ -115,7 +117,6 @@ public class PayloadArgumentResolverTests { @Test public void resolveNotRequired() throws Exception { - Message> emptyByteArrayMessage = MessageBuilder.withPayload(new byte[0]).build(); assertNull(this.resolver.resolveArgument(this.paramAnnotatedNotRequired, emptyByteArrayMessage)); @@ -168,14 +169,12 @@ public class PayloadArgumentResolverTests { @Test public void resolveNonAnnotatedParameter() throws Exception { - Message> notEmptyMessage = MessageBuilder.withPayload("ABC".getBytes()).build(); assertEquals("ABC", this.resolver.resolveArgument(this.paramNotAnnotated, notEmptyMessage)); Message> emptyStringMessage = MessageBuilder.withPayload("").build(); thrown.expect(MethodArgumentNotValidException.class); this.resolver.resolveArgument(this.paramValidated, emptyStringMessage); - } @Test @@ -188,8 +187,8 @@ public class PayloadArgumentResolverTests { assertEquals("invalidValue", this.resolver.resolveArgument(this.paramValidatedNotAnnotated, message)); } - private Validator testValidator() { + private Validator testValidator() { return new Validator() { @Override public boolean supports(Class> clazz) { @@ -216,9 +215,16 @@ public class PayloadArgumentResolverTests { @Payload(required=false) String paramNotRequired, @Payload(required=true) Locale nonConvertibleRequiredParam, @Payload("foo.bar") String paramWithSpelExpression, - @Validated @Payload String validParam, + @MyValid @Payload String validParam, @Validated String validParamNotAnnotated, String paramNotAnnotated) { } + + @Validated + @Target({ElementType.PARAMETER}) + @Retention(RetentionPolicy.RUNTIME) + public @interface MyValid { + } + } diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java index 11f98ba95e..d1e86e4ffb 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java +++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -59,6 +59,7 @@ import org.springframework.util.ReflectionUtils; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; +import org.springframework.validation.annotation.Validated; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.CookieValue; @@ -82,11 +83,11 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartRequest; /** - * Support class for invoking an annotated handler method. Operates on the introspection results of a {@link - * HandlerMethodResolver} for a specific handler type. + * Support class for invoking an annotated handler method. Operates on the introspection + * results of a {@link HandlerMethodResolver} for a specific handler type. * - *
Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} and {@link - * org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}. + *
Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
+ * and {@link org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}.
*
* @author Juergen Hoeller
* @author Arjen Poutsma
@@ -295,10 +296,13 @@ public class HandlerMethodInvoker {
else if (Value.class.isInstance(paramAnn)) {
defaultValue = ((Value) paramAnn).value();
}
- else if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
- validate = true;
- Object value = AnnotationUtils.getValue(paramAnn);
- validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value});
+ else {
+ Validated validatedAnn = AnnotationUtils.getAnnotation(paramAnn, Validated.class);
+ if (validatedAnn != null || paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
+ validate = true;
+ Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(paramAnn));
+ validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
+ }
}
}
diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java
index 2ecd2c8173..be7b0b54ed 100644
--- a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java
+++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java
@@ -27,6 +27,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.support.WebDataBinderFactory;
@@ -157,9 +158,11 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
Annotation[] annotations = parameter.getParameterAnnotations();
for (Annotation ann : annotations) {
- if (ann.annotationType().getSimpleName().startsWith("Valid")) {
- Object hints = AnnotationUtils.getValue(ann);
- binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
+ 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});
+ binder.validate(validationHints);
break;
}
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java
index 207bfd6ff6..5d076b2e79 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java
@@ -31,6 +31,7 @@ import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestBody;
@@ -223,10 +224,12 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
private void validate(WebDataBinder binder, MethodParameter parameter) throws MethodArgumentNotValidException {
Annotation[] annotations = parameter.getParameterAnnotations();
- for (Annotation annot : annotations) {
- if (annot.annotationType().getSimpleName().startsWith("Valid")) {
- Object hints = AnnotationUtils.getValue(annot);
- binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
+ 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});
+ binder.validate(validationHints);
BindingResult bindingResult = binder.getBindingResult();
if (bindingResult.hasErrors()) {
if (isBindingErrorFatal(parameter)) {
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java
index 08fe6a9e96..c13e8f1a7c 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java
@@ -33,6 +33,7 @@ import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.accept.ContentNegotiationManager;
@@ -114,9 +115,11 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
private void validate(WebDataBinder binder, MethodParameter parameter) throws Exception {
Annotation[] annotations = parameter.getParameterAnnotations();
for (Annotation ann : annotations) {
- if (ann.annotationType().getSimpleName().startsWith("Valid")) {
- Object hints = AnnotationUtils.getValue(ann);
- binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
+ 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});
+ binder.validate(validationHints);
BindingResult bindingResult = binder.getBindingResult();
if (bindingResult.hasErrors()) {
if (isBindExceptionRequired(binder, parameter)) {
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
index e7d8db60a1..7fc8ef0f14 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
@@ -16,8 +16,10 @@
package org.springframework.web.servlet.config;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
@@ -150,6 +152,7 @@ public class MvcNamespaceTests {
private HandlerMethod handlerMethod;
+
@Before
public void setUp() throws Exception {
TestMockServletContext servletContext = new TestMockServletContext();
@@ -187,7 +190,7 @@ public class MvcNamespaceTests {
List