INT-3373: Make Messaging Annotations as Meta

JIRA: https://jira.spring.io/browse/INT-3373

Allow messaging annotations to be used as
meta annotations.
This commit is contained in:
Artem Bilan
2014-04-15 18:52:50 +03:00
committed by Gary Russell
parent 66fe1c74be
commit 18920851d3
12 changed files with 64 additions and 17 deletions

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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<String, Object> componentScan = importingClassMetadata.getAnnotationAttributes("org.springframework.integration.annotation.IntegrationComponentScan");
Map<String, Object> componentScan = importingClassMetadata
.getAnnotationAttributes("org.springframework.integration.annotation.IntegrationComponentScan");
Set<String> basePackages = new HashSet<String>();
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);
}
}
}

View File

@@ -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<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(MessagingGateway.class.getName());

View File

@@ -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<Annotation> annotations = new ArrayList<Annotation>();
for (Class<? extends Annotation> 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)) {

View File

@@ -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<String>("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 {
}
}

View File

@@ -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 { }