From a92933e800d6629971751e511f1afb98e8c593aa Mon Sep 17 00:00:00 2001 From: jmaxwell Date: Wed, 7 Mar 2018 15:21:15 -0600 Subject: [PATCH] INT-4427 add value attribute to the @Publisher JIRA: https://jira.spring.io/browse/INT-4427 --- .../integration/annotation/Publisher.java | 29 ++-- .../aop/PublisherAnnotationAdvisorTests.java | 151 ++++++++++++++++-- 2 files changed, 158 insertions(+), 22 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Publisher.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Publisher.java index b494cc10b3..c6453c3560 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Publisher.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Publisher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 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. @@ -21,16 +21,16 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.core.annotation.AliasFor; + /** - * Annotation to indicate that a method, or all public methods if applied at - * class-level, should publish Messages. + * Annotation to indicate that a method, or all public methods if applied at class-level, + * should publish Messages. *

* By default, the Message will be constructed from the return value of the method - * invocation - * and sent to a channel specified by the {@link #channel()} attribute. - * However, a combination of both @Payload and @Header annotations - * can be used to further manage the message structure. See the reference manual for - * examples. + * invocation and sent to a channel specified by the {@link #channel()} attribute. + * However, a combination of both @Payload and @Header annotations can be used to further + * manage the message structure. See the reference manual for examples. *

* Note: unlike @Gateway, this annotation is used to generate an AOP Advice for an * existing service and its method implementation. The message sending is a side effect @@ -40,17 +40,28 @@ import java.lang.annotation.Target; * The XML equivalent is {@code } * * @author Mark Fisher + * @author Jeff Maxwell * * @since 2.0 + * * @see org.springframework.integration.aop.MessagePublishingInterceptor */ -@Target({ElementType.METHOD, ElementType.TYPE}) +@Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface Publisher { + /** + * Alias for the {@link #channel()} attribute. + * @return The name of the Message Channel to which Messages will be published. + * @since 5.0.4 + */ + @AliasFor("channel") + String value() default ""; + /** * @return The name of the Message Channel to which Messages will be published. */ + @AliasFor("value") String channel() default ""; } 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 0e06f96a6d..87af422207 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 @@ -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,27 +29,27 @@ import org.junit.Test; import org.springframework.aop.framework.ProxyFactory; import org.springframework.context.support.StaticApplicationContext; -import org.springframework.messaging.Message; -import org.springframework.messaging.handler.annotation.Payload; import org.springframework.integration.annotation.Publisher; import org.springframework.integration.channel.QueueChannel; +import org.springframework.messaging.Message; +import org.springframework.messaging.handler.annotation.Payload; /** * @author Mark Fisher + * @author Jeff Maxwell + * * @since 2.0 */ public class PublisherAnnotationAdvisorTests { private final StaticApplicationContext context = new StaticApplicationContext(); - @Before public void setup() { context.registerSingleton("testChannel", QueueChannel.class); context.registerSingleton("testMetaChannel", QueueChannel.class); } - @Test public void annotationAtMethodLevelOnVoidReturnWithParamAnnotation() { PublisherAnnotationAdvisor advisor = new PublisherAnnotationAdvisor(); @@ -120,6 +120,75 @@ public class PublisherAnnotationAdvisorTests { assertEquals("foo", message.getPayload()); } + @Test + public void annotationViaValueAtMethodLevelOnVoidReturnWithParamAnnotation() { + PublisherAnnotationAdvisor advisor = new PublisherAnnotationAdvisor(); + advisor.setBeanFactory(context); + QueueChannel testChannel = context.getBean("testChannel", QueueChannel.class); + ProxyFactory pf = new ProxyFactory(new AnnotationViaValueAtMethodLevelTestBeanImpl()); + pf.addAdvisor(advisor); + TestVoidBean proxy = (TestVoidBean) pf.getProxy(); + proxy.testVoidMethod("foo"); + Message message = testChannel.receive(0); + assertNotNull(message); + assertEquals("foo", message.getPayload()); + } + + @Test + public void annotationViaValueAtMethodLevel() { + PublisherAnnotationAdvisor advisor = new PublisherAnnotationAdvisor(); + advisor.setBeanFactory(context); + QueueChannel testChannel = context.getBean("testChannel", QueueChannel.class); + ProxyFactory pf = new ProxyFactory(new AnnotationViaValueAtMethodLevelTestBeanImpl()); + pf.addAdvisor(advisor); + TestBean proxy = (TestBean) pf.getProxy(); + proxy.test(); + Message message = testChannel.receive(0); + assertNotNull(message); + assertEquals("foo", message.getPayload()); + } + + @Test + public void annotationViaValueAtClassLevel() { + PublisherAnnotationAdvisor advisor = new PublisherAnnotationAdvisor(); + advisor.setBeanFactory(context); + QueueChannel testChannel = context.getBean("testChannel", QueueChannel.class); + ProxyFactory pf = new ProxyFactory(new AnnotationViaValueAtClassLevelTestBeanImpl()); + pf.addAdvisor(advisor); + TestBean proxy = (TestBean) pf.getProxy(); + proxy.test(); + Message message = testChannel.receive(0); + assertNotNull(message); + assertEquals("foo", message.getPayload()); + } + + @Test + public void metaAnnotationViaValueAtMethodLevel() { + PublisherAnnotationAdvisor advisor = new PublisherAnnotationAdvisor(); + advisor.setBeanFactory(context); + QueueChannel testMetaChannel = context.getBean("testMetaChannel", QueueChannel.class); + ProxyFactory pf = new ProxyFactory(new MetaAnnotationViaValueAtMethodLevelTestBeanImpl()); + pf.addAdvisor(advisor); + TestBean proxy = (TestBean) pf.getProxy(); + proxy.test(); + Message message = testMetaChannel.receive(0); + assertNotNull(message); + assertEquals("foo", message.getPayload()); + } + + @Test + public void metaAnnotationViaValueAtClassLevel() { + PublisherAnnotationAdvisor advisor = new PublisherAnnotationAdvisor(); + advisor.setBeanFactory(context); + QueueChannel testMetaChannel = context.getBean("testMetaChannel", QueueChannel.class); + ProxyFactory pf = new ProxyFactory(new MetaAnnotationViaValueAtClassLevelTestBeanImpl()); + pf.addAdvisor(advisor); + TestBean proxy = (TestBean) pf.getProxy(); + proxy.test(); + Message message = testMetaChannel.receive(0); + assertNotNull(message); + assertEquals("foo", message.getPayload()); + } interface TestBean { @@ -127,58 +196,114 @@ public class PublisherAnnotationAdvisorTests { } - interface TestVoidBean { void testVoidMethod(String s); } - static class AnnotationAtMethodLevelTestBeanImpl implements TestBean, TestVoidBean { + @Override @Publisher(channel = "testChannel") public String test() { return "foo"; } + @Override @Publisher(channel = "testChannel") - public void testVoidMethod(@Payload String s) { } - } + public void testVoidMethod(@Payload String s) { + } + } @Publisher(channel = "testChannel") static class AnnotationAtClassLevelTestBeanImpl implements TestBean { + @Override public String test() { return "foo"; } } - - @Target({ElementType.METHOD, ElementType.TYPE}) + @Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Publisher(channel = "testMetaChannel") public @interface TestMetaPublisher { - } + } static class MetaAnnotationAtMethodLevelTestBeanImpl implements TestBean { + @Override @TestMetaPublisher public String test() { return "foo"; } - } + } @TestMetaPublisher static class MetaAnnotationAtClassLevelTestBeanImpl implements TestBean { + @Override public String test() { return "foo"; } + + } + + static class AnnotationViaValueAtMethodLevelTestBeanImpl implements TestBean, TestVoidBean { + + @Override + @Publisher("testChannel") + public String test() { + return "foo"; + } + + @Override + @Publisher("testChannel") + public void testVoidMethod(@Payload String s) { + } + + } + + @Publisher("testChannel") + static class AnnotationViaValueAtClassLevelTestBeanImpl implements TestBean { + + @Override + public String test() { + return "foo"; + } + + } + + @Target({ ElementType.METHOD, ElementType.TYPE }) + @Retention(RetentionPolicy.RUNTIME) + @Publisher("testMetaChannel") + public @interface TestMetaPublisherViaValue { + + } + + static class MetaAnnotationViaValueAtMethodLevelTestBeanImpl implements TestBean { + + @Override + @TestMetaPublisherViaValue + public String test() { + return "foo"; + } + + } + + @TestMetaPublisherViaValue + static class MetaAnnotationViaValueAtClassLevelTestBeanImpl implements TestBean { + + @Override + public String test() { + return "foo"; + } + } }