INT-28 Added support for headers based on the evaluation of EL expressions provided on the @Publisher annotation.

This commit is contained in:
Mark Fisher
2009-08-25 22:35:01 +00:00
parent 0afaa22344
commit 4db77d65c8
6 changed files with 74 additions and 21 deletions

View File

@@ -35,9 +35,16 @@ interface ExpressionSource {
/**
* Returns the expression string to be evaluated.
* Returns the expression string to be evaluated for creating the Message
* payload.
*/
String getExpressionString(Method method);
String getPayloadExpression(Method method);
/**
* Returns the array of expression strings to be evaluated for any headers
* that should be set on the published Message.
*/
String[] getHeaderExpressions(Method method);
/**
* Returns the variable names to be associated with the intercepted method

View File

@@ -26,8 +26,10 @@ import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParserConfiguration;
import org.springframework.expression.spel.support.StandardEvaluationContext;
@@ -35,9 +37,9 @@ import org.springframework.integration.channel.ChannelResolver;
import org.springframework.integration.channel.MessageChannelTemplate;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.gateway.SimpleMessageMapper;
import org.springframework.integration.message.InboundMessageMapper;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* A {@link MethodInterceptor} that publishes Messages to a channel. The
@@ -58,8 +60,6 @@ public class MessagePublishingInterceptor implements MethodInterceptor {
SpelExpressionParserConfiguration.CreateObjectIfAttemptToReferenceNull |
SpelExpressionParserConfiguration.GrowListsOnIndexBeyondSize);
private final InboundMessageMapper<Object> messageMapper = new SimpleMessageMapper();
private volatile ChannelResolver channelResolver;
@@ -109,12 +109,19 @@ public class MessagePublishingInterceptor implements MethodInterceptor {
}
private void publishMessage(Method method, EvaluationContext context) throws Exception {
String expressionString = this.expressionSource.getExpressionString(method);
if (expressionString != null) {
Expression expression = this.parser.parseExpression(expressionString);
String payloadExpressionString = this.expressionSource.getPayloadExpression(method);
if (payloadExpressionString != null) {
Expression expression = this.parser.parseExpression(payloadExpressionString);
Object result = expression.getValue(context);
if (result != null) {
Message<?> message = this.messageMapper.toMessage(result);
MessageBuilder<?> builder = (result instanceof Message<?>)
? MessageBuilder.fromMessage((Message<?>) result)
: MessageBuilder.withPayload(result);
Map<String, Object> headers = this.evaluateHeaders(method, context);
if (headers != null) {
builder.copyHeaders(headers);
}
Message<?> message = builder.build();
String channelName = this.expressionSource.getChannelName(method);
MessageChannel channel = null;
if (channelName != null) {
@@ -131,4 +138,24 @@ public class MessagePublishingInterceptor implements MethodInterceptor {
}
}
private Map<String, Object> evaluateHeaders(Method method, EvaluationContext context)
throws ParseException, EvaluationException {
String[] headerExpressionStrings = this.expressionSource.getHeaderExpressions(method);
if (headerExpressionStrings != null) {
Map<String, Object> headers = new HashMap<String, Object>();
context.setRootObject(headers);
for (String headerExpression : headerExpressionStrings) {
if (StringUtils.hasText(headerExpression)) {
Expression expression = this.parser.parseExpression(headerExpression);
expression.getValue(context);
}
}
if (headers.size() > 0) {
return headers;
}
}
return null;
}
}

View File

@@ -58,10 +58,14 @@ public class MethodAnnotationExpressionSource implements ExpressionSource {
this.channelAttributeName = channelAttributeName;
}
public String getExpressionString(Method method) {
public String getPayloadExpression(Method method) {
return this.getAnnotationValue(method, null, String.class);
}
public String[] getHeaderExpressions(Method method) {
return this.getAnnotationValue(method, "headers", String[].class);
}
public String[] getArgumentNames(Method method) {
ExpressionBinding annotation = AnnotationUtils.findAnnotation(method, ExpressionBinding.class);
if (annotation != null) {

View File

@@ -34,10 +34,17 @@ import java.lang.annotation.Target;
public @interface Publisher {
/**
* String representation of a Spel Expression. Required.
* String representation of a Spel Expression to evaluate when creating the
* Message payload. Required.
*/
String value();
/**
* String representations of Spel Expressions to evaluate for adding any
* headers to the Message. Optional.
*/
String[] headers() default "";
/**
* Name of the Message Channel to which Messages will be published.
*/

View File

@@ -88,22 +88,25 @@ public class MessagePublishingInterceptorTests {
return new String[] { "a1", "a2" };
}
public String getChannelName(Method method) {
return "c";
public String getReturnValueName(Method method) {
return "r";
}
public String getExceptionName(Method method) {
return "x";
}
public String getExpressionString(Method method) {
public String getPayloadExpression(Method method) {
return "#r";
}
public String getReturnValueName(Method method) {
return "r";
public String[] getHeaderExpressions(Method method) {
return null;
}
public String getChannelName(Method method) {
return "c";
}
}
}

View File

@@ -17,6 +17,7 @@
package org.springframework.integration.aop;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.lang.reflect.Method;
@@ -33,11 +34,15 @@ public class MethodAnnotationExpressionSourceTests {
@Test
public void defaultBindings() {
Method method = getMethod("methodWithExpressionAnnotationOnly", String.class, int.class);
String expressionString = source.getExpressionString(method);
String expressionString = source.getPayloadExpression(method);
assertEquals("testExpression1", expressionString);
assertEquals(2, source.getArgumentNames(method).length);
assertEquals("arg1", source.getArgumentNames(method)[0]);
assertEquals("arg2", source.getArgumentNames(method)[1]);
String[] headerStrings = source.getHeaderExpressions(method);
assertNotNull(headerStrings);
assertEquals(1, headerStrings.length);
assertEquals("", headerStrings[0]);
assertEquals(ExpressionSource.DEFAULT_ARGUMENT_MAP_NAME, source.getArgumentMapName(method));
assertEquals(ExpressionSource.DEFAULT_EXCEPTION_NAME, source.getExceptionName(method));
assertEquals(ExpressionSource.DEFAULT_RETURN_VALUE_NAME, source.getReturnValueName(method));
@@ -46,7 +51,7 @@ public class MethodAnnotationExpressionSourceTests {
@Test
public void annotationBindings() {
Method method = getMethod("methodWithExpressionBinding", String.class, int.class);
String expressionString = source.getExpressionString(method);
String expressionString = source.getPayloadExpression(method);
assertEquals("testExpression2", expressionString);
assertEquals(2, source.getArgumentNames(method).length);
assertEquals("s", source.getArgumentNames(method)[0]);
@@ -78,7 +83,7 @@ public class MethodAnnotationExpressionSourceTests {
public void methodWithExpressionAnnotationOnly(String arg1, int arg2) {
}
@Publisher(value="#return", channel="foo")
@Publisher(value="#return", channel="foo", headers="bar=123")
public void methodWithChannelAndReturnAsPayload() {
}