diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Aggregator.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Aggregator.java index 6038d50aab..0493cd28fb 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Aggregator.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Aggregator.java @@ -35,7 +35,7 @@ import org.springframework.integration.aggregator.AbstractCorrelatingMessageHand * @author Oleg Zhurakousky * @author Artem Bilan */ -@Target(ElementType.METHOD) +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Aggregator { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Filter.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Filter.java index dc74a2a40a..45697b1cc0 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Filter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Filter.java @@ -39,7 +39,7 @@ import java.lang.annotation.Target; * @author Artem Bilan * @since 2.0 */ -@Target(ElementType.METHOD) +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Filter { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Gateway.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Gateway.java index 2b254c7bfe..e9f6a6dfee 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Gateway.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Gateway.java @@ -46,7 +46,7 @@ import java.lang.annotation.Target; * @author Gary Russell * @author Artem Bilan */ -@Target(ElementType.METHOD) +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/InboundChannelAdapter.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/InboundChannelAdapter.java index bf56090133..ea4c043b35 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/annotation/InboundChannelAdapter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/InboundChannelAdapter.java @@ -45,7 +45,7 @@ import java.lang.annotation.Target; * @author Artem Bilan * @since 4.0 */ -@Target(ElementType.METHOD) +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Router.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Router.java index e196418071..1dd3f9de51 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Router.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Router.java @@ -43,7 +43,7 @@ import java.lang.annotation.Target; * @author Mark Fisher * @author Artem Bilan */ -@Target(ElementType.METHOD) +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/ServiceActivator.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/ServiceActivator.java index 5ffcde9cf2..bf669599ea 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/annotation/ServiceActivator.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/ServiceActivator.java @@ -41,7 +41,7 @@ import java.lang.annotation.Target; * @author Gary Russell * @author Artem Bilan */ -@Target(ElementType.METHOD) +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Splitter.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Splitter.java index 555aaf2fd5..fed04887e1 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Splitter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Splitter.java @@ -41,7 +41,7 @@ import java.lang.annotation.Target; * @author Gary Russell * @author Artem Bilan */ -@Target(ElementType.METHOD) +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Splitter { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationComponentScanRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationComponentScanRegistrar.java index fe3f7efbbe..eb501a5a55 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationComponentScanRegistrar.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationComponentScanRegistrar.java @@ -48,7 +48,7 @@ public class IntegrationComponentScanRegistrar implements ImportBeanDefinitionRe private ResourceLoader resourceLoader; public IntegrationComponentScanRegistrar() { - this.componentRegistrars.put(new AnnotationTypeFilter(MessagingGateway.class), new MessagingGatewayRegistrar()); + this.componentRegistrars.put(new AnnotationTypeFilter(MessagingGateway.class, true), new MessagingGatewayRegistrar()); } @Override @@ -58,7 +58,8 @@ public class IntegrationComponentScanRegistrar implements ImportBeanDefinitionRe @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { - Map componentScan = importingClassMetadata.getAnnotationAttributes("org.springframework.integration.annotation.IntegrationComponentScan"); + Map componentScan = importingClassMetadata + .getAnnotationAttributes("org.springframework.integration.annotation.IntegrationComponentScan"); Set basePackages = new HashSet(); for (String pkg : (String[]) componentScan.get("value")) { @@ -98,7 +99,8 @@ public class IntegrationComponentScanRegistrar implements ImportBeanDefinitionRe for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { for (ImportBeanDefinitionRegistrar importBeanDefinitionRegistrar : componentRegistrars.values()) { - importBeanDefinitionRegistrar.registerBeanDefinitions(((AnnotatedBeanDefinition) candidateComponent).getMetadata(), registry); + importBeanDefinitionRegistrar.registerBeanDefinitions(((AnnotatedBeanDefinition) candidateComponent).getMetadata(), + registry); } } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java index f7b70cc450..835d041cb2 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java @@ -48,7 +48,7 @@ public class MessagingGatewayRegistrar implements ImportBeanDefinitionRegistrar @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { - if (importingClassMetadata != null && importingClassMetadata.hasAnnotation(MessagingGateway.class.getName())) { + if (importingClassMetadata != null && importingClassMetadata.isAnnotated(MessagingGateway.class.getName())) { Assert.isTrue(importingClassMetadata.isInterface(), "@MessagingGateway can only be specified on an interface"); Map annotationAttributes = importingClassMetadata.getAnnotationAttributes(MessagingGateway.class.getName()); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java index 8f0dc6202e..3b3d33eabe 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessor.java @@ -125,7 +125,13 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { - Annotation[] annotations = AnnotationUtils.getAnnotations(method); + List annotations = new ArrayList(); + for (Class annotation : postProcessors.keySet()) { + Annotation result = AnnotationUtils.getAnnotation(method, annotation); + if (result != null) { + annotations.add(result); + } + } for (Annotation annotation : annotations) { MethodAnnotationPostProcessor postProcessor = postProcessors.get(annotation.annotationType()); if (postProcessor != null && shouldCreateEndpoint(annotation)) { diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessorTests.java index 24d83be1b7..494ccfe4d1 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessorTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/MessagingAnnotationPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -16,12 +16,15 @@ package org.springframework.integration.config.annotation; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; @@ -48,6 +51,7 @@ import org.springframework.messaging.support.GenericMessage; /** * @author Mark Fisher * @author Gary Russell + * @author Artem Bilan */ public class MessagingAnnotationPostProcessorTests { @@ -157,8 +161,10 @@ public class MessagingAnnotationPostProcessorTests { TestApplicationContext context = TestUtils.createTestApplicationContext(); DirectChannel inputChannel = new DirectChannel(); QueueChannel outputChannel = new QueueChannel(); + DirectChannel eventBus = new DirectChannel(); context.registerChannel("inputChannel", inputChannel); context.registerChannel("outputChannel", outputChannel); + context.registerChannel("eventBus", eventBus); MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor(); postProcessor.setBeanFactory(context.getBeanFactory()); postProcessor.afterPropertiesSet(); @@ -170,6 +176,10 @@ public class MessagingAnnotationPostProcessorTests { inputChannel.send(message); Message reply = outputChannel.receive(0); assertNotNull(reply); + + eventBus.send(new GenericMessage("foo")); + assertTrue(bean.getInvoked()); + context.stop(); } @@ -353,11 +363,21 @@ public class MessagingAnnotationPostProcessorTests { @MessageEndpoint private static class ServiceActivatorAnnotatedBean { + public final AtomicBoolean invoked = new AtomicBoolean(); + @ServiceActivator(inputChannel="inputChannel") public String test(String s) { return s + s; } + @EventHandler + public void eventBus(Object payload) { + invoked.set(true); + } + + public Boolean getInvoked() { + return invoked.get(); + } } @@ -378,4 +398,11 @@ public class MessagingAnnotationPostProcessorTests { } } + + @Target({ ElementType.METHOD }) + @Retention(RetentionPolicy.RUNTIME) + @ServiceActivator(inputChannel = "eventBus") + public static @interface EventHandler { + } + } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java index 8b80a81ed1..94759fdafa 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java @@ -26,6 +26,10 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.Date; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -654,7 +658,7 @@ public class EnableIntegrationTests { } - @MessagingGateway(defaultRequestChannel = "gatewayChannel", defaultHeaders = @GatewayHeader(name = "foo", value = "FOO")) + @TestMessagingGateway public static interface TestGateway { @Gateway(headers = @GatewayHeader(name = "calledMethod", expression = "#gatewayMethod.name")) @@ -662,6 +666,14 @@ public class EnableIntegrationTests { } + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @MessagingGateway(defaultRequestChannel = "gatewayChannel", + defaultHeaders = @GatewayHeader(name = "foo", value = "FOO")) + public static @interface TestMessagingGateway { + } + + // Error because the annotation is on a class; it must be on an interface // @MessagingGateway(defaultRequestChannel = "gatewayChannel", defaultHeaders = @GatewayHeader(name = "foo", value = "FOO")) // public static class TestGateway2 { }