Replace RequestBodyNotValidException and RequestPartNotValidException with MethodArgumentNotValidException and add MethodParameter information to the exception message.

This commit is contained in:
Rossen Stoyanchev
2011-08-03 15:10:10 +00:00
parent 3c7e44ada4
commit fc4ea16ba0
9 changed files with 109 additions and 175 deletions

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2002-2011 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
*
* http://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.web.servlet.mvc.method.annotation.support;
import org.springframework.validation.Errors;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.RequestBody;
/**
* Thrown by {@link RequestResponseBodyMethodProcessor} when an @{@link RequestBody} argument annotated with
* {@code @Valid} results in validation errors.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@SuppressWarnings("serial")
public class RequestBodyNotValidException extends RuntimeException {
private final Errors errors;
/**
* @param errors contains the results of validating an @{@link RequestBody} argument.
*/
public RequestBodyNotValidException(Errors errors) {
this.errors = errors;
}
/**
* Returns an Errors instance with validation errors.
*/
public Errors getErrors() {
return errors;
}
@Override
public String getMessage() {
StringBuilder sb = new StringBuilder("Request body content validation failed: ");
sb.append(errors.getErrorCount()).append(" errors");
for (ObjectError error : errors.getAllErrors()) {
sb.append('\n').append(error);
}
return sb.toString();
}
}

View File

@@ -27,7 +27,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.validation.Errors;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestBody;
@@ -35,6 +35,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.support.MethodArgumentNotValidException;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@@ -134,9 +135,9 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
if (isValidationApplicable(arg, parameter)) {
WebDataBinder binder = binderFactory.createBinder(request, arg, partName);
binder.validate();
Errors errors = binder.getBindingResult();
if (errors.hasErrors()) {
throw new RequestPartNotValidException(errors);
BindingResult bindingResult = binder.getBindingResult();
if (bindingResult.hasErrors()) {
throw new MethodArgumentNotValidException(parameter, bindingResult);
}
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2002-2011 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
*
* http://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.web.servlet.mvc.method.annotation.support;
import org.springframework.validation.Errors;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestPart;
/**
* Thrown by {@link RequestPartMethodArgumentResolver} when an @{@link RequestPart} argument also annotated with
* {@code @Valid} results in validation errors.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@SuppressWarnings("serial")
public class RequestPartNotValidException extends RuntimeException {
private final Errors errors;
/**
* @param errors contains the results of validating an @{@link RequestBody} argument.
*/
public RequestPartNotValidException(Errors errors) {
this.errors = errors;
}
/**
* Returns an Errors instance with validation errors.
*/
public Errors getErrors() {
return errors;
}
@Override
public String getMessage() {
StringBuilder sb = new StringBuilder(
"Validation of the content of request part '" + errors.getObjectName() + "' failed: ");
sb.append(errors.getErrorCount()).append(" errors");
for (ObjectError error : errors.getAllErrors()) {
sb.append('\n').append(error);
}
return sb.toString();
}
}

View File

@@ -23,13 +23,14 @@ import java.util.List;
import org.springframework.core.Conventions;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.Errors;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.support.MethodArgumentNotValidException;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
@@ -38,7 +39,7 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
* annotated with {@link ResponseBody}.
*
* <p>An @{@link RequestBody} method argument will be validated if annotated with {@code @Valid}.
* In case of validation failure, a {@link RequestBodyNotValidException} is thrown and handled
* In case of validation failure, a {@link MethodArgumentNotValidException} is thrown and handled
* automatically in {@link DefaultHandlerExceptionResolver}.
*
* @author Arjen Poutsma
@@ -68,9 +69,9 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
String name = Conventions.getVariableNameForParameter(parameter);
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
binder.validate();
Errors errors = binder.getBindingResult();
if (errors.hasErrors()) {
throw new RequestBodyNotValidException(errors);
BindingResult bindingResult = binder.getBindingResult();
if (bindingResult.hasErrors()) {
throw new MethodArgumentNotValidException(parameter, bindingResult);
}
}
return arg;

View File

@@ -37,10 +37,11 @@ import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.method.annotation.support.MethodArgumentNotValidException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.support.RequestBodyNotValidException;
import org.springframework.web.servlet.mvc.method.annotation.support.RequestPartNotValidException;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;
/**
@@ -127,11 +128,8 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
else if (ex instanceof HttpMessageNotWritableException) {
return handleHttpMessageNotWritable((HttpMessageNotWritableException) ex, request, response, handler);
}
else if (ex instanceof RequestBodyNotValidException) {
return handleRequestBodyNotValidException((RequestBodyNotValidException) ex, request, response, handler);
}
else if (ex instanceof RequestPartNotValidException) {
return handleRequestPartNotValidException((RequestPartNotValidException) ex, request, response, handler);
else if (ex instanceof MethodArgumentNotValidException) {
return handleMethodArgumentNotValidException((MethodArgumentNotValidException) ex, request, response, handler);
}
}
catch (Exception handlerException) {
@@ -343,33 +341,19 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
}
/**
* Handle the case where the object created from the body of a request has failed validation.
* The default implementation sends an HTTP 400 error.
* Handle the case where an argument annotated with {@code @Valid} such as
* an {@link RequestBody} or {@link RequestPart} argument fails validation.
* An HTTP 400 error is sent back to the client.
* @param request current HTTP request
* @param response current HTTP response
* @param handler the executed handler
* @return an empty ModelAndView indicating the exception was handled
* @throws IOException potentially thrown from response.sendError()
*/
protected ModelAndView handleRequestBodyNotValidException(RequestBodyNotValidException ex,
protected ModelAndView handleMethodArgumentNotValidException(MethodArgumentNotValidException ex,
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return new ModelAndView();
}
/**
* Handle the case where the object created from the part of a multipart request has failed validation.
* The default implementation sends an HTTP 400 error.
* @param request current HTTP request
* @param response current HTTP response
* @param handler the executed handler
* @return an empty ModelAndView indicating the exception was handled
* @throws IOException potentially thrown from response.sendError()
*/
protected ModelAndView handleRequestPartNotValidException(RequestPartNotValidException ex,
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return new ModelAndView();
}
}