Introduce base exception class for arg resolution

Issue: SPR-11584
This commit is contained in:
Rossen Stoyanchev
2014-03-25 11:02:24 -04:00
parent 2aee0d8250
commit 2c1d5efbb0
5 changed files with 143 additions and 75 deletions

View File

@@ -0,0 +1,68 @@
/*
* 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.
* 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.messaging.handler.annotation.support;
import org.springframework.core.MethodParameter;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
/**
* Base class for exceptions resulting from the invocation of
* {@link org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver}.
*
* @author Rossen Stoyanchev
* @since 4.0.3
*/
@SuppressWarnings("serial")
public abstract class AbstractMethodArgumentResolutionException extends MessagingException {
private final MethodParameter parameter;
/**
* Create a new instance providing the invalid {@code MethodParameter}.
*/
protected AbstractMethodArgumentResolutionException(Message<?> message, MethodParameter parameter) {
this(message, parameter, getMethodParamMessage(parameter));
}
/**
* Create a new instance providing the invalid {@code MethodParameter} and
* a prepared description. Sub-classes should prepend the description with
* the help of {@link #getMethodParamMessage(org.springframework.core.MethodParameter)}.
*/
protected AbstractMethodArgumentResolutionException(Message<?> message,
MethodParameter parameter, String description) {
super(message, description);
this.parameter = parameter;
}
/**
* Return the MethodParameter that was rejected.
*/
public MethodParameter getMethodParameter() {
return this.parameter;
}
protected static String getMethodParamMessage(MethodParameter param) {
return new StringBuilder("Could not resolve method parameter at index ")
.append(param.getParameterIndex()).append(" in method: ")
.append(param.getMethod().toGenericString()).toString();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 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.
@@ -21,6 +21,8 @@ import org.springframework.core.ResolvableType;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import java.lang.reflect.Type;
/**
* A {@link HandlerMethodArgumentResolver} for {@link Message} parameters. Validates
* that the generic type of the payload matches with the message value.
@@ -39,28 +41,30 @@ public class MessageMethodArgumentResolver implements HandlerMethodArgumentResol
@Override
public Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception {
// Validate the message type is assignable
if (!parameter.getParameterType().isAssignableFrom(message.getClass())) {
throw new MethodArgumentTypeMismatchException(message,
"Could not resolve Message parameter: invalid message type:"
+ "expected [" + message.getClass().getName() + "] but got ["
+ parameter.getParameterType().getName() + "]");
Class<?> paramType = parameter.getParameterType();
if (!paramType.isAssignableFrom(message.getClass())) {
throw new MethodArgumentTypeMismatchException(message, parameter,
"The actual message type [" + message.getClass().getName() + "] " +
"does not match the expected type [" + paramType.getName() + "]");
}
// validate that the payload type matches
Class<?> effectivePayloadType = getPayloadType(parameter);
if (effectivePayloadType != null && !effectivePayloadType.isInstance(message.getPayload())) {
throw new MethodArgumentTypeMismatchException(message,
"Could not resolve Message parameter: invalid payload type: "
+ "expected [" + effectivePayloadType.getName() + "] but got ["
+ message.getPayload().getClass().getName() + "]");
Class<?> expectedPayloadType = getPayloadType(parameter);
Object payload = message.getPayload();
if (expectedPayloadType != null && !expectedPayloadType.isInstance(payload)) {
throw new MethodArgumentTypeMismatchException(message, parameter,
"The expected Message<?> payload type [" + expectedPayloadType.getClass().getName() +
"] does not match the actual payload type [" + payload.getClass().getName() + "]");
}
return message;
}
private Class<?> getPayloadType(MethodParameter parameter) {
ResolvableType resolvableType = ResolvableType
.forType(parameter.getGenericParameterType()).as(Message.class);
Type genericParamType = parameter.getGenericParameterType();
ResolvableType resolvableType = ResolvableType.forType(genericParamType).as(Message.class);
return resolvableType.getGeneric(0).resolve(Object.class);
}

View File

@@ -18,22 +18,19 @@ package org.springframework.messaging.handler.annotation.support;
import org.springframework.core.MethodParameter;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
/**
* Exception to be thrown when a method argument is not valid. For instance, this
* can be issued if a validation on a method parameter annotated with
* {@code @Valid} fails.
* Exception to be thrown when a method argument fails validation perhaps as a
* result of {@code @Valid} style validation, or perhaps because it is required.
*
* @author Brian Clozel
* @author Rossen Stoyanchev
* @since 4.0.1
*/
@SuppressWarnings("serial")
public class MethodArgumentNotValidException extends MessagingException {
private final MethodParameter parameter;
public class MethodArgumentNotValidException extends AbstractMethodArgumentResolutionException {
private final BindingResult bindingResult;
@@ -41,7 +38,6 @@ public class MethodArgumentNotValidException extends MessagingException {
/**
* Create a new instance with the invalid {@code MethodParameter}.
*/
public MethodArgumentNotValidException(Message<?> message, MethodParameter parameter) {
this(message, parameter, null);
}
@@ -53,19 +49,13 @@ public class MethodArgumentNotValidException extends MessagingException {
public MethodArgumentNotValidException(Message<?> message, MethodParameter parameter,
BindingResult bindingResult) {
super(message, generateMessage(parameter, bindingResult));
this.parameter = parameter;
super(message, parameter, getMethodParamMessage(parameter) +
getValidationErrorMessage(parameter, bindingResult));
this.bindingResult = bindingResult;
}
/**
* Return the MethodParameter that was rejected.
*/
public MethodParameter getMethodParameter() {
return this.parameter;
}
/**
* Return the BindingResult if the failure is validation-related or {@code null}.
*/
@@ -74,21 +64,18 @@ public class MethodArgumentNotValidException extends MessagingException {
}
private static String generateMessage(MethodParameter parameter, BindingResult bindingResult) {
StringBuilder sb = new StringBuilder("Invalid parameter at index ")
.append(parameter.getParameterIndex()).append(" in method: ")
.append(parameter.getMethod().toGenericString());
private static String getValidationErrorMessage(MethodParameter parameter, BindingResult bindingResult) {
if (bindingResult != null) {
StringBuilder sb = new StringBuilder();
sb.append(", with ").append(bindingResult.getErrorCount()).append(" error(s): ");
for (ObjectError error : bindingResult.getAllErrors()) {
sb.append("[").append(error).append("] ");
}
return sb.toString();
}
else {
return "";
}
return sb.toString();
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.messaging.handler.annotation.support;
import org.springframework.core.MethodParameter;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
@@ -26,9 +27,14 @@ import org.springframework.messaging.MessagingException;
* @author Stephane Nicoll
* @since 4.0.3
*/
public class MethodArgumentTypeMismatchException extends MessagingException {
@SuppressWarnings("serial")
public class MethodArgumentTypeMismatchException extends AbstractMethodArgumentResolutionException {
public MethodArgumentTypeMismatchException(Message<?> message, String description) {
super(message, description);
/**
* Create a new instance with the invalid {@code MethodParameter}.
*/
public MethodArgumentTypeMismatchException(Message<?> message, MethodParameter parameter, String description) {
super(message, parameter, getMethodParamMessage(parameter) + description);
}
}