INT-670 now supporting a method-level @Payload containing a SpEL expression for Gateway methods

This commit is contained in:
Mark Fisher
2010-07-23 02:58:47 +00:00
parent e11a29f65f
commit 4c6d5fd752
2 changed files with 52 additions and 11 deletions

View File

@@ -26,6 +26,9 @@ import java.util.Map;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.integration.annotation.Header;
import org.springframework.integration.annotation.Headers;
import org.springframework.integration.annotation.Payload;
@@ -96,12 +99,18 @@ import org.springframework.util.StringUtils;
*/
public class ArgumentArrayMessageMapper implements InboundMessageMapper<Object[]> {
private Map<String, Object> staticHeaders;
private static final SpelExpressionParser PARSER = new SpelExpressionParser();
private final Map<String, Object> staticHeaders;
private final Method method;
private final List<MethodParameter> parameterList;
private final Expression payloadExpression;
public ArgumentArrayMessageMapper(Method method) {
this(method, null);
}
@@ -110,9 +119,11 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper<Object[]
Assert.notNull(method, "method must not be null");
this.method = method;
this.staticHeaders = staticHeaders;
this.parameterList = this.getMethodParameterList(method);
this.parameterList = getMethodParameterList(method);
this.payloadExpression = parsePayloadExpression(method);
}
public Message<?> toMessage(Object[] arguments) {
Assert.notNull(arguments, "cannot map null arguments to Message");
if (arguments.length != this.parameterList.size()) {
@@ -128,19 +139,24 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper<Object[]
Object messageOrPayload = null;
boolean foundPayloadAnnotation = false;
Map<String, Object> headers = new HashMap<String, Object>();
if (this.payloadExpression != null) {
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("args", arguments);
messageOrPayload = this.payloadExpression.getValue(context);
}
for (int i = 0; i < this.parameterList.size(); i++) {
Object argumentValue = arguments[i];
MethodParameter methodParameter = this.parameterList.get(i);
Annotation annotation = this.findMappingAnnotation(methodParameter.getParameterAnnotations());
if (annotation != null) {
if (annotation.annotationType().equals(Payload.class)) {
if (messageOrPayload != null) {
this.throwExceptionForMultipleMessageOrPayloadParameters(methodParameter);
}
if (((Payload) annotation).value().length() != 0) {
throw new MessagingException(
"The Payload annotation does not support an expression when mapping to a Message.");
}
if (messageOrPayload != null) {
this.throwExceptionForMultipleMessageOrPayloadParameters(methodParameter);
}
foundPayloadAnnotation = true;
messageOrPayload = argumentValue;
}
@@ -176,7 +192,7 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper<Object[]
}
this.copyHeaders((Map) argumentValue, headers);
}
else {
else if (this.payloadExpression == null) {
this.throwExceptionForMultipleMessageOrPayloadParameters(methodParameter);
}
}
@@ -223,8 +239,8 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper<Object[]
private void throwExceptionForMultipleMessageOrPayloadParameters(MethodParameter methodParameter) {
throw new MessagingException(
"At most one parameter may be mapped to the payload or Message, " +
"found more than one on method [" + methodParameter.getMethod() + "]");
"At most one parameter (or expression via method-level @Payload) may be mapped to the " +
"payload or Message. Found more than one on method [" + methodParameter.getMethod() + "]");
}
private String determineHeaderName(Header headerAnnotation, MethodParameter methodParameter) {
@@ -235,7 +251,7 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper<Object[]
return headerName;
}
private List<MethodParameter> getMethodParameterList(Method method) {
private static List<MethodParameter> getMethodParameterList(Method method) {
List<MethodParameter> parameterList = new LinkedList<MethodParameter>();
ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
int parameterCount = method.getParameterTypes().length;
@@ -246,4 +262,17 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper<Object[]
}
return parameterList;
}
private static Expression parsePayloadExpression(Method method) {
Expression expression = null;
Payload payload = method.getAnnotation(Payload.class);
if (payload != null) {
String expressionString = payload.value();
Assert.hasText(expressionString,
"@Payload at method-level on a Gateway must provide a non-empty Expression.");
expression = PARSER.parseExpression(expressionString);
}
return expression;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* 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.
@@ -118,6 +118,15 @@ public class GatewayProxyMessageMappingTests {
assertNull(result.getHeaders().get("k1"));
}
@Test
public void payloadAnnotationAtMethodLevel() throws Exception {
gateway.payloadAnnotationAtMethodLevel("foo", "bar");
Message<?> result = channel.receive(0);
assertNotNull(result);
assertEquals("foobar!", result.getPayload());
}
@Test(expected = MessagingException.class)
public void twoMapsWithoutAnnotations() {
Map<String, Object> map1 = new HashMap<String, Object>();
@@ -160,6 +169,9 @@ public class GatewayProxyMessageMappingTests {
void twoMapsAndOneAnnotatedWithPayload(@Payload Map<String, Object> payload, Map<String, Object> headers);
@Payload("#args[0] + #args[1] + '!'")
void payloadAnnotationAtMethodLevel(String a, String b);
// invalid
void twoMapsWithoutAnnotations(Map<String, Object> m1, Map<String, Object> m2);