From ecd0f34b3ccbaf59ce72b3c9209b8164d034edf8 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Tue, 20 Jul 2010 16:10:45 +0000 Subject: [PATCH] INT-1243 (refactoring publishing-interceptor) Step 2: removed "payload" attribute from @Publisher. The @Payload annotation now may be used either at method-level or on a single parameter. --- .../integration/annotation/Payload.java | 2 +- .../aop/MethodAnnotationExpressionSource.java | 24 ++++++++- .../integration/aop/Publisher.java | 11 +---- .../AnnotationConfigRegistrationTests.java | 4 +- ...MessagePublishingAnnotationUsageTests.java | 49 +++++++++++++------ ...MethodAnnotationExpressionSourceTests.java | 11 +++-- .../aop/PublisherAnnotationAdvisorTests.java | 2 +- .../aop/PublisherExpressionTests.java | 4 +- 8 files changed, 75 insertions(+), 32 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Payload.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Payload.java index bc33141806..8162ce2277 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Payload.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Payload.java @@ -34,7 +34,7 @@ import java.lang.annotation.Target; * @author Oleg Zhurakousky * @since 2.0 */ -@Target(ElementType.PARAMETER) +@Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Payload { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aop/MethodAnnotationExpressionSource.java b/spring-integration-core/src/main/java/org/springframework/integration/aop/MethodAnnotationExpressionSource.java index ff3db26f85..e409b5a605 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aop/MethodAnnotationExpressionSource.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aop/MethodAnnotationExpressionSource.java @@ -27,6 +27,7 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.integration.annotation.Header; +import org.springframework.integration.annotation.Payload; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -62,7 +63,28 @@ public class MethodAnnotationExpressionSource implements ExpressionSource { } public String getPayloadExpression(Method method) { - return this.getAnnotationValue(method, "payload", String.class); + String payloadExpression = null; + method.getAnnotation(Payload.class); + Payload methodPayloadAnnotation = AnnotationUtils.findAnnotation(method, Payload.class); + if (methodPayloadAnnotation != null) { + payloadExpression = StringUtils.hasText(methodPayloadAnnotation.value()) + ? methodPayloadAnnotation.value() + : "#" + this.getReturnValueVariableName(method); + } + Annotation[][] annotationArray = method.getParameterAnnotations(); + for (int i = 0; i < annotationArray.length; i++) { + Annotation[] parameterAnnotations = annotationArray[i]; + for (Annotation currentAnnotation : parameterAnnotations) { + if (Payload.class.equals(currentAnnotation.annotationType())) { + Assert.state(payloadExpression == null, + "@Payload can be used at most once on a @Publisher method, either at method-level or on a single parameter"); + Assert.state("".equals(((Payload) currentAnnotation).value()), + "@Payload on a parameter for a @Publisher method may not contain an expression"); + payloadExpression = "#" + this.getArgumentMapVariableName(method) + "[" + i + "]"; + } + } + } + return payloadExpression; } public Map getHeaderExpressions(Method method) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aop/Publisher.java b/spring-integration-core/src/main/java/org/springframework/integration/aop/Publisher.java index e1abdbf922..a0bddc6a3c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aop/Publisher.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aop/Publisher.java @@ -23,8 +23,8 @@ import java.lang.annotation.Target; /** * Annotation to indicate that a method, or all public methods if applied at - * class-level, should publish Messages whose payloads will be determined by - * the provided EL expression. + * class-level, should publish Messages. The @Payload and @Header annotations + * can be used in conjunction with this to determine the content of the Message. * * @author Mark Fisher * @since 2.0 @@ -33,13 +33,6 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) public @interface Publisher { - /** - * String representation of a Spel Expression to evaluate when creating the - * Message payload. The default will be empty, thereby causing the return - * value to be used as the payload. - */ - String payload() default ""; - /** * Name of the Message Channel to which Messages will be published. */ diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aop/AnnotationConfigRegistrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aop/AnnotationConfigRegistrationTests.java index 4ce3250e45..43b4c3b14f 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aop/AnnotationConfigRegistrationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aop/AnnotationConfigRegistrationTests.java @@ -23,6 +23,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.integration.annotation.Header; +import org.springframework.integration.annotation.Payload; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.core.Message; import org.springframework.test.context.ContextConfiguration; @@ -69,7 +70,8 @@ public class AnnotationConfigRegistrationTests { public static class TestBean { - @Publisher(channel="testChannel", payload="#return + #args.lname") + @Publisher(channel="testChannel") + @Payload("#return + #args.lname") public String setName(String fname, String lname, @Header("x") int num) { return fname + " " + lname; } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTests.java index 8490a7f487..eae5156e9a 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aop/MessagePublishingAnnotationUsageTests.java @@ -16,13 +16,15 @@ package org.springframework.integration.aop; -import junit.framework.Assert; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.integration.annotation.Header; +import org.springframework.integration.annotation.Payload; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.core.Message; import org.springframework.test.context.ContextConfiguration; @@ -46,34 +48,51 @@ public class MessagePublishingAnnotationUsageTests { @Test public void headerWithExplicitName() { - String name = testBean.setName1("John", "Doe"); - Assert.assertNotNull(name); + String name = testBean.defaultPayload("John", "Doe"); + assertNotNull(name); Message message = channel.receive(1000); - Assert.assertNotNull(message); - Assert.assertEquals("John Doe", message.getPayload()); - Assert.assertEquals("Doe", message.getHeaders().get("last")); + assertNotNull(message); + assertEquals("John Doe", message.getPayload()); + assertEquals("Doe", message.getHeaders().get("last")); } @Test public void headerWithImplicitName() { - String name = testBean.setName2("John", "Doe"); - Assert.assertNotNull(name); + String name = testBean.defaultPayloadButExplicitAnnotation("John", "Doe"); + assertNotNull(name); Message message = channel.receive(1000); - Assert.assertNotNull(message); - Assert.assertEquals("John Doe", message.getPayload()); - Assert.assertEquals("Doe", message.getHeaders().get("lname")); + assertNotNull(message); + assertEquals("John Doe", message.getPayload()); + assertEquals("Doe", message.getHeaders().get("lname")); + } + + @Test + public void payloadAsArgument() { + String name = testBean.argumentAsPayload("John", "Doe"); + assertNotNull(name); + assertEquals("John Doe", name); + Message message = channel.receive(1000); + assertNotNull(message); + assertEquals("John", message.getPayload()); + assertEquals("Doe", message.getHeaders().get("lname")); } public static class TestBean { - @Publisher(channel="testChannel", payload="#return") - public String setName1(String fname, @Header("last") String lname) { + @Publisher(channel="testChannel") + public String defaultPayload(String fname, @Header("last") String lname) { return fname + " " + lname; } - @Publisher(channel="testChannel", payload="#return") - public String setName2(String fname, @Header String lname) { + @Publisher(channel="testChannel") + @Payload + public String defaultPayloadButExplicitAnnotation(String fname, @Header String lname) { + return fname + " " + lname; + } + + @Publisher(channel="testChannel") + public String argumentAsPayload(@Payload String fname, @Header String lname) { return fname + " " + lname; } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aop/MethodAnnotationExpressionSourceTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aop/MethodAnnotationExpressionSourceTests.java index 2028a80b84..cc0bac665f 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aop/MethodAnnotationExpressionSourceTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aop/MethodAnnotationExpressionSourceTests.java @@ -24,6 +24,8 @@ import java.util.Map; import org.junit.Test; +import org.springframework.integration.annotation.Payload; + /** * @author Mark Fisher * @since 2.0 @@ -79,15 +81,18 @@ public class MethodAnnotationExpressionSourceTests { } - @Publisher(payload="testExpression1") + @Publisher + @Payload("testExpression1") public void methodWithExpressionAnnotationOnly(String arg1, int arg2) { } - @Publisher(payload="#return", channel="foo") + @Publisher(channel="foo") + @Payload public void methodWithChannelAndReturnAsPayload() { } - @Publisher(payload="testExpression2") + @Publisher + @Payload("testExpression2") @ExpressionBinding(argumentVariableNames="s, i", argumentMapVariableName="argz", exceptionVariableName="x", returnValueVariableName="result") public void methodWithExpressionBinding(String arg1, int arg2) { diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aop/PublisherAnnotationAdvisorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aop/PublisherAnnotationAdvisorTests.java index 2cec09f97c..1397b499fd 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aop/PublisherAnnotationAdvisorTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aop/PublisherAnnotationAdvisorTests.java @@ -66,7 +66,7 @@ public class PublisherAnnotationAdvisorTests { static class TestBeanImpl implements TestBean { - @Publisher(payload="#return") + @Publisher public String test() { return "foo"; } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aop/PublisherExpressionTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aop/PublisherExpressionTests.java index 5da7364d6e..681648134d 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aop/PublisherExpressionTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aop/PublisherExpressionTests.java @@ -25,6 +25,7 @@ import org.junit.Test; import org.springframework.aop.framework.ProxyFactory; import org.springframework.context.support.StaticApplicationContext; import org.springframework.integration.annotation.Header; +import org.springframework.integration.annotation.Payload; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.core.Message; @@ -67,7 +68,8 @@ public class PublisherExpressionTests { static class TestBeanImpl implements TestBean { - @Publisher(payload="#return") + @Publisher + @Payload("#return") public String test(@Header("foo") String foo) { return "hello"; }