AbstractMethodMessageHandler processes Error as MessageHandlingException
Issue: SPR-16912
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -29,6 +29,7 @@ public interface MessageHandler {
|
||||
/**
|
||||
* Handle the given message.
|
||||
* @param message the message to be handled
|
||||
* @throws MessagingException if the handler failed to process the message
|
||||
*/
|
||||
void handleMessage(Message<?> message) throws MessagingException;
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.MessageHandlingException;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
|
||||
import org.springframework.messaging.handler.HandlerMethod;
|
||||
@@ -84,7 +85,7 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private Collection<String> destinationPrefixes = new ArrayList<>();
|
||||
private final List<String> destinationPrefixes = new ArrayList<>();
|
||||
|
||||
private final List<HandlerMethodArgumentResolver> customArgumentResolvers = new ArrayList<>(4);
|
||||
|
||||
@@ -395,6 +396,7 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
if (lookupDestination == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MessageHeaderAccessor headerAccessor = MessageHeaderAccessor.getMutableAccessor(message);
|
||||
headerAccessor.setHeader(DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER, lookupDestination);
|
||||
headerAccessor.setLeaveMutable(true);
|
||||
@@ -452,9 +454,9 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
handleNoMatch(this.handlerMethods.keySet(), lookupDestination, message);
|
||||
return;
|
||||
}
|
||||
|
||||
Comparator<Match> comparator = new MatchComparator(getMappingComparator(message));
|
||||
matches.sort(comparator);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Found " + matches.size() + " handler methods: " + matches);
|
||||
}
|
||||
@@ -531,16 +533,16 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
processHandlerMethodException(handlerMethod, ex, message);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Error while processing message " + message, ex);
|
||||
}
|
||||
Exception handlingException =
|
||||
new MessageHandlingException(message, "Unexpected handler method invocation error", ex);
|
||||
processHandlerMethodException(handlerMethod, handlingException, message);
|
||||
}
|
||||
}
|
||||
|
||||
protected void processHandlerMethodException(HandlerMethod handlerMethod, Exception ex, Message<?> message) {
|
||||
InvocableHandlerMethod invocable = getExceptionHandlerMethod(handlerMethod, ex);
|
||||
protected void processHandlerMethodException(HandlerMethod handlerMethod, Exception exception, Message<?> message) {
|
||||
InvocableHandlerMethod invocable = getExceptionHandlerMethod(handlerMethod, exception);
|
||||
if (invocable == null) {
|
||||
logger.error("Unhandled exception from message handler method", ex);
|
||||
logger.error("Unhandled exception from message handler method", exception);
|
||||
return;
|
||||
}
|
||||
invocable.setMessageMethodArgumentResolvers(this.argumentResolvers);
|
||||
@@ -548,7 +550,10 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
logger.debug("Invoking " + invocable.getShortLogMessage());
|
||||
}
|
||||
try {
|
||||
Object returnValue = invocable.invoke(message, ex, handlerMethod);
|
||||
Throwable cause = exception.getCause();
|
||||
Object returnValue = (cause != null ?
|
||||
invocable.invoke(message, exception, cause, handlerMethod) :
|
||||
invocable.invoke(message, exception, handlerMethod));
|
||||
MethodParameter returnType = invocable.getReturnType();
|
||||
if (void.class == returnType.getParameterType()) {
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -86,6 +86,12 @@ public class AnnotationExceptionHandlerMethodResolverTests {
|
||||
assertEquals("handleIOException", this.resolver.resolveMethod(exception).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveMethodAgainstCause() {
|
||||
IllegalStateException exception = new IllegalStateException(new IOException());
|
||||
assertEquals("handleIOException", this.resolver.resolveMethod(exception).getName());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void ambiguousExceptionMapping() {
|
||||
new AnnotationExceptionHandlerMethodResolver(AmbiguousController.class);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -75,7 +75,6 @@ import static org.mockito.BDDMockito.*;
|
||||
* @author Brian Clozel
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class SimpAnnotationMethodMessageHandlerTests {
|
||||
|
||||
private static final String TEST_INVALID_VALUE = "invalidValue";
|
||||
@@ -201,6 +200,30 @@ public class SimpAnnotationMethodMessageHandlerTests {
|
||||
assertEquals("illegalState", handlerMethod.getMethod().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exceptionAsCause() {
|
||||
Message<?> message = createMessage("/pre/illegalStateCause");
|
||||
this.messageHandler.registerHandler(this.testController);
|
||||
this.messageHandler.handleMessage(message);
|
||||
|
||||
assertEquals("handleExceptionWithHandlerMethodArg", this.testController.method);
|
||||
HandlerMethod handlerMethod = (HandlerMethod) this.testController.arguments.get("handlerMethod");
|
||||
assertNotNull(handlerMethod);
|
||||
assertEquals("illegalStateCause", handlerMethod.getMethod().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorAsMessageHandlingException() {
|
||||
Message<?> message = createMessage("/pre/error");
|
||||
this.messageHandler.registerHandler(this.testController);
|
||||
this.messageHandler.handleMessage(message);
|
||||
|
||||
assertEquals("handleErrorWithHandlerMethodArg", this.testController.method);
|
||||
HandlerMethod handlerMethod = (HandlerMethod) this.testController.arguments.get("handlerMethod");
|
||||
assertNotNull(handlerMethod);
|
||||
assertEquals("errorAsThrowable", handlerMethod.getMethod().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpScope() {
|
||||
Map<String, Object> sessionAttributes = new ConcurrentHashMap<>();
|
||||
@@ -412,7 +435,17 @@ public class SimpAnnotationMethodMessageHandlerTests {
|
||||
|
||||
@MessageMapping("/illegalState")
|
||||
public void illegalState() {
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException("my cause");
|
||||
}
|
||||
|
||||
@MessageMapping("/illegalStateCause")
|
||||
public void illegalStateCause() {
|
||||
throw new RuntimeException(new IllegalStateException("my cause"));
|
||||
}
|
||||
|
||||
@MessageMapping("/error")
|
||||
public void errorAsThrowable() {
|
||||
throw new Error("my cause");
|
||||
}
|
||||
|
||||
@MessageExceptionHandler(MethodArgumentNotValidException.class)
|
||||
@@ -420,10 +453,18 @@ public class SimpAnnotationMethodMessageHandlerTests {
|
||||
this.method = "handleValidationException";
|
||||
}
|
||||
|
||||
@MessageExceptionHandler(IllegalStateException.class)
|
||||
public void handleExceptionWithHandlerMethodArg(HandlerMethod handlerMethod) {
|
||||
@MessageExceptionHandler
|
||||
public void handleExceptionWithHandlerMethodArg(IllegalStateException ex, HandlerMethod handlerMethod) {
|
||||
this.method = "handleExceptionWithHandlerMethodArg";
|
||||
this.arguments.put("handlerMethod", handlerMethod);
|
||||
assertEquals("my cause", ex.getMessage());
|
||||
}
|
||||
|
||||
@MessageExceptionHandler
|
||||
public void handleErrorWithHandlerMethodArg(Error ex, HandlerMethod handlerMethod) {
|
||||
this.method = "handleErrorWithHandlerMethodArg";
|
||||
this.arguments.put("handlerMethod", handlerMethod);
|
||||
assertEquals("my cause", ex.getMessage());
|
||||
}
|
||||
|
||||
@MessageMapping("/scope")
|
||||
@@ -446,7 +487,6 @@ public class SimpAnnotationMethodMessageHandlerTests {
|
||||
|
||||
private String method;
|
||||
|
||||
|
||||
@MessageMapping("foo")
|
||||
public void handleFoo() {
|
||||
this.method = "handleFoo";
|
||||
|
||||
Reference in New Issue
Block a user