INT-941: Catch and unwrap in AbstractMessageProcessor

This commit is contained in:
David Syer
2010-05-06 10:00:04 +00:00
parent a8d9c4cfc2
commit c00eb6bb0d
4 changed files with 195 additions and 10 deletions

View File

@@ -47,6 +47,10 @@ public abstract class AbstractMessageProcessor implements MessageProcessor {
try {
return expression.getValue(this.evaluationContext, message);
}
catch (EvaluationException e) {
Throwable cause = e.getCause();
throw new MessageHandlingException(message, "Expression evaluation failed.", cause==null ? e : cause);
}
catch (Exception e) {
throw new MessageHandlingException(message, "Expression evaluation failed.", e);
}

View File

@@ -31,14 +31,12 @@ import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.expression.MapAccessor;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
@@ -156,7 +154,7 @@ public class MethodInvokingMessageProcessor extends AbstractMessageProcessor {
}
public Object processMessage(Message<?> message) {
EvaluationException evaluationException = null;
Throwable evaluationException = null;
List<HandlerMethod> candidates = this.findHandlerMethodsForMessage(message);
for (HandlerMethod candidate : candidates) {
try {
@@ -169,17 +167,13 @@ public class MethodInvokingMessageProcessor extends AbstractMessageProcessor {
}
return result;
}
catch (EvaluationException e) {
catch (MessageHandlingException e) {
if (evaluationException == null) {
// keep the first exception
evaluationException = e;
evaluationException = e.getCause();
}
}
}
if (evaluationException == null) {
throw new MessageHandlingException(message, "Failed to find a suitable Message-handling " +
"method on target of type [" + targetObject.getClass() + "].");
}
throw new MessageHandlingException(message, "Failed to process Message.", evaluationException);
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2002-2010 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.integration.handler;
import static org.junit.Assert.assertEquals;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hamcrest.Description;
import org.junit.Rule;
import org.junit.Test;
import org.junit.internal.matchers.TypeSafeMatcher;
import org.junit.rules.ExpectedException;
import org.springframework.expression.EvaluationException;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.StringMessage;
/**
* @author Dave Syer
* @since 2.0
*
*/
public class ExpressionEvaluatingMessageProcessorTests {
private static final Log logger = LogFactory.getLog(ExpressionEvaluatingMessageProcessorTests.class);
@Rule
public ExpectedException expected = ExpectedException.none();
@Test
public void testProcessMessage() {
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("payload");
assertEquals("foo", processor.processMessage(new StringMessage("foo")));
}
@Test
public void testProcessMessageBadExpression() {
expected.expect(new TypeSafeMatcher<Exception>(Exception.class) {
private Throwable cause;
@Override
public boolean matchesSafely(Exception item) {
logger.debug(item);
cause = item.getCause();
return cause instanceof EvaluationException;
}
public void describeTo(Description description) {
description.appendText("cause to be EvaluationException but was ").appendValue(cause);
}
});
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("payload.fixMe()");
assertEquals("foo", processor.processMessage(new StringMessage("foo")));
}
@Test
public void testProcessMessageExpressionThrowsRuntimeException() {
expected.expect(new TypeSafeMatcher<Exception>(Exception.class) {
private Throwable cause;
@Override
public boolean matchesSafely(Exception item) {
logger.debug(item);
cause = item.getCause();
return cause instanceof UnsupportedOperationException;
}
public void describeTo(Description description) {
description.appendText("cause to be UnsupportedOperationException but was ").appendValue(cause);
}
});
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("payload.error()");
assertEquals("foo", processor.processMessage(new GenericMessage<ExpressionEvaluatingMessageProcessorTests>(this)));
}
@Test
public void testProcessMessageExpressionThrowsCheckedException() {
expected.expect(new TypeSafeMatcher<Exception>(Exception.class) {
private Throwable cause;
@Override
public boolean matchesSafely(Exception item) {
logger.debug(item);
cause = item.getCause();
return cause instanceof CheckedException;
}
public void describeTo(Description description) {
description.appendText("cause to be CheckedException but was ").appendValue(cause);
}
});
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("payload.check()");
assertEquals("foo", processor.processMessage(new GenericMessage<ExpressionEvaluatingMessageProcessorTests>(this)));
}
public String error() {
throw new UnsupportedOperationException("Expected test exception");
}
public String check() throws Exception {
throw new CheckedException("Expected test exception");
}
private static final class CheckedException extends Exception {
public CheckedException(String string) {
super(string);
}
}
}

View File

@@ -25,8 +25,14 @@ import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hamcrest.Description;
import org.junit.Rule;
import org.junit.Test;
import org.junit.internal.matchers.TypeSafeMatcher;
import org.junit.rules.ExpectedException;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.integration.annotation.Header;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.core.Message;
@@ -39,9 +45,15 @@ import org.springframework.integration.message.StringMessage;
* @author Mark Fisher
* @author Marius Bogoevici
* @author Oleg Zhurakousky
* @author Dave Syer
*/
public class MethodInvokingMessageProcessorTests {
private static final Log logger = LogFactory.getLog(MethodInvokingMessageProcessorTests.class);
@Rule
public ExpectedException expected = ExpectedException.none();
@Test
public void testHandlerInheritanceMethodImplInSuper() {
class A {
@@ -246,6 +258,33 @@ public class MethodInvokingMessageProcessorTests {
processor.processMessage(new StringMessage("foo"));
}
@Test
public void testProcessMessageBadExpression() throws Exception {
expected.expect(new ExceptionCauseMatcher(ConversionFailedException.class));
AnnotatedTestService service = new AnnotatedTestService();
Method method = service.getClass().getMethod("integerMethod", Integer.class);
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(service, method);
assertEquals("foo", processor.processMessage(new StringMessage("foo")));
}
@Test
public void testProcessMessageRuntimeException() throws Exception {
expected.expect(new ExceptionCauseMatcher(UnsupportedOperationException.class));
TestErrorService service = new TestErrorService();
Method method = service.getClass().getMethod("error", String.class);
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(service, method);
assertEquals("foo", processor.processMessage(new StringMessage("foo")));
}
@Test
public void testProcessMessageCheckedException() throws Exception {
expected.expect(new ExceptionCauseMatcher(CheckedException.class));
TestErrorService service = new TestErrorService();
Method method = service.getClass().getMethod("checked", String.class);
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(service, method);
assertEquals("foo", processor.processMessage(new StringMessage("foo")));
}
@Test
public void messageAndHeaderWithAnnotatedMethod() throws Exception {
AnnotatedTestService service = new AnnotatedTestService();
@@ -289,7 +328,40 @@ public class MethodInvokingMessageProcessorTests {
assertEquals("true", bean.lastArg);
}
private static class ExceptionCauseMatcher extends TypeSafeMatcher<Exception> {
private Throwable cause;
private Class<? extends Exception> type;
public ExceptionCauseMatcher(Class<? extends Exception> type) {
this.type = type;
}
@Override
public boolean matchesSafely(Exception item) {
logger.debug(item);
cause = item.getCause();
assertNotNull("There is no cause for "+item, cause);
return type.isAssignableFrom(cause.getClass());
}
public void describeTo(Description description) {
description.appendText("cause to be ").appendValue(type).appendText("but was ").appendValue(cause);
}
}
@SuppressWarnings("unused")
private static class TestErrorService {
public String error(String input) {
throw new UnsupportedOperationException("Expected test exception");
}
public String checked(String input) throws Exception {
throw new CheckedException("Expected test exception");
}
}
public static final class CheckedException extends Exception {
public CheckedException(String string) {
super(string);
}
}
@SuppressWarnings("unused")
private static class TestBean {