Some Fixes and Improvements

* Remove `durable-subscription-name` from the `JmsMessageDrivenEndpointParser`, since we don't have such an attribute any more
* Fix `configuration.adoc` for various typos
* Remove `spring.integration.messagingAnnotations.require.componentAnnotation` and `spring.integration.messagingGateway.convertReceiveMessage` properties and their usage,
since they are not actual any more starting with SI-5.0
* Fix tests appropriately

Address PR comments and more polishing

Polishing
This commit is contained in:
Artem Bilan
2016-08-31 11:53:52 -04:00
committed by Gary Russell
parent 370be4853d
commit 868004e9e4
12 changed files with 128 additions and 238 deletions

View File

@@ -356,11 +356,8 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
*/
private void registerMessagingAnnotationPostProcessors(AnnotationMetadata meta, BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME)) {
String requireComponentAnnotationExpression =
IntegrationProperties.getExpressionFor(IntegrationProperties.REQUIRE_COMPONENT_ANNOTATION);
BeanDefinitionBuilder builder =
BeanDefinitionBuilder.genericBeanDefinition(MessagingAnnotationPostProcessor.class)
.addPropertyValue("requireComponentAnnotation", requireComponentAnnotationExpression)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME,

View File

@@ -55,7 +55,6 @@ import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.support.SmartLifecycleRoleController;
import org.springframework.integration.util.MessagingAnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
@@ -84,7 +83,6 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
private ConfigurableListableBeanFactory beanFactory;
private boolean requireComponentAnnotation;
@Override
public void setBeanFactory(BeanFactory beanFactory) {
@@ -93,17 +91,6 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
/**
*
* @param requireComponentAnnotation the {@code boolean} flag to indicate requirements for the
* {@link Component} annotation presentation for the messaging annotations.
* @since 4.3
* @see org.springframework.integration.context.IntegrationProperties#REQUIRE_COMPONENT_ANNOTATION
*/
public void setRequireComponentAnnotation(boolean requireComponentAnnotation) {
this.requireComponentAnnotation = requireComponentAnnotation;
}
protected ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
@@ -147,75 +134,65 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
Assert.notNull(this.beanFactory, "BeanFactory must not be null");
final Class<?> beanClass = this.getBeanClass(bean);
if (this.requireComponentAnnotation && AnnotationUtils.findAnnotation(beanClass, Component.class) == null) {
// we only post-process stereotype components
return bean;
}
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Map<Class<? extends Annotation>, List<Annotation>> annotationChains =
new HashMap<Class<? extends Annotation>, List<Annotation>>();
for (Class<? extends Annotation> annotationType :
MessagingAnnotationPostProcessor.this.postProcessors.keySet()) {
if (AnnotatedElementUtils.isAnnotated(method, annotationType.getName())) {
List<Annotation> annotationChain = getAnnotationChain(method, annotationType);
if (annotationChain.size() > 0) {
annotationChains.put(annotationType, annotationChain);
}
ReflectionUtils.doWithMethods(beanClass, method -> {
Map<Class<? extends Annotation>, List<Annotation>> annotationChains = new HashMap<>();
for (Class<? extends Annotation> annotationType :
MessagingAnnotationPostProcessor.this.postProcessors.keySet()) {
if (AnnotatedElementUtils.isAnnotated(method, annotationType.getName())) {
List<Annotation> annotationChain = getAnnotationChain(method, annotationType);
if (annotationChain.size() > 0) {
annotationChains.put(annotationType, annotationChain);
}
}
}
for (Map.Entry<Class<? extends Annotation>, List<Annotation>> entry : annotationChains.entrySet()) {
Class<? extends Annotation> annotationType = entry.getKey();
List<Annotation> annotations = entry.getValue();
MethodAnnotationPostProcessor postProcessor =
MessagingAnnotationPostProcessor.this.postProcessors.get(annotationType);
if (postProcessor != null && postProcessor.shouldCreateEndpoint(method, annotations)) {
Method targetMethod = method;
if (AopUtils.isJdkDynamicProxy(bean)) {
try {
targetMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
}
catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Service methods must be extracted to the service "
+ "interface for JdkDynamicProxy. The affected bean is: '" + beanName + "' "
+ "and its method: '" + method + "'", e);
for (Entry<Class<? extends Annotation>, List<Annotation>> entry : annotationChains.entrySet()) {
Class<? extends Annotation> annotationType = entry.getKey();
List<Annotation> annotations = entry.getValue();
MethodAnnotationPostProcessor<?> postProcessor =
MessagingAnnotationPostProcessor.this.postProcessors.get(annotationType);
if (postProcessor != null && postProcessor.shouldCreateEndpoint(method, annotations)) {
Method targetMethod = method;
if (AopUtils.isJdkDynamicProxy(bean)) {
try {
targetMethod = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
}
catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Service methods must be extracted to the service "
+ "interface for JdkDynamicProxy. The affected bean is: '" + beanName + "' "
+ "and its method: '" + method + "'", e);
}
}
Object result = postProcessor.postProcess(bean, beanName, targetMethod, annotations);
if (result != null && result instanceof AbstractEndpoint) {
AbstractEndpoint endpoint = (AbstractEndpoint) result;
String autoStartup = MessagingAnnotationUtils.resolveAttribute(annotations, "autoStartup",
String.class);
if (StringUtils.hasText(autoStartup)) {
autoStartup = getBeanFactory().resolveEmbeddedValue(autoStartup);
if (StringUtils.hasText(autoStartup)) {
endpoint.setAutoStartup(Boolean.parseBoolean(autoStartup));
}
}
Object result = postProcessor.postProcess(bean, beanName, targetMethod, annotations);
if (result != null && result instanceof AbstractEndpoint) {
AbstractEndpoint endpoint = (AbstractEndpoint) result;
String autoStartup = MessagingAnnotationUtils.resolveAttribute(annotations, "autoStartup",
String.class);
if (StringUtils.hasText(autoStartup)) {
autoStartup = getBeanFactory().resolveEmbeddedValue(autoStartup);
if (StringUtils.hasText(autoStartup)) {
endpoint.setAutoStartup(Boolean.parseBoolean(autoStartup));
}
}
String phase = MessagingAnnotationUtils.resolveAttribute(annotations, "phase", String.class);
String phase = MessagingAnnotationUtils.resolveAttribute(annotations, "phase", String.class);
if (StringUtils.hasText(phase)) {
phase = getBeanFactory().resolveEmbeddedValue(phase);
if (StringUtils.hasText(phase)) {
phase = getBeanFactory().resolveEmbeddedValue(phase);
if (StringUtils.hasText(phase)) {
endpoint.setPhase(Integer.parseInt(phase));
}
endpoint.setPhase(Integer.parseInt(phase));
}
}
String endpointBeanName = generateBeanName(beanName, method, annotationType);
endpoint.setBeanName(endpointBeanName);
getBeanFactory().registerSingleton(endpointBeanName, endpoint);
getBeanFactory().initializeBean(endpoint, endpointBeanName);
String endpointBeanName = generateBeanName(beanName, method, annotationType);
endpoint.setBeanName(endpointBeanName);
getBeanFactory().registerSingleton(endpointBeanName, endpoint);
getBeanFactory().initializeBean(endpoint, endpointBeanName);
Role role = AnnotationUtils.findAnnotation(method, Role.class);
if (role != null) {
MessagingAnnotationPostProcessor.this.lazyLifecycleRoles.add(role.value(),
endpointBeanName);
}
Role role = AnnotationUtils.findAnnotation(method, Role.class);
if (role != null) {
MessagingAnnotationPostProcessor.this.lazyLifecycleRoles.add(role.value(),
endpointBeanName);
}
}
}

View File

@@ -66,16 +66,6 @@ public final class IntegrationProperties {
*/
public static final String THROW_EXCEPTION_ON_LATE_REPLY = INTEGRATION_PROPERTIES_PREFIX + "messagingTemplate.throwExceptionOnLateReply";
/**
* Specifies the value of {@link org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor#requireComponentAnnotation}.
*/
public static final String REQUIRE_COMPONENT_ANNOTATION = INTEGRATION_PROPERTIES_PREFIX + "messagingAnnotations.require.componentAnnotation";
/**
* Specifies the value of {@link org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor#requireComponentAnnotation}.
*/
public static final String GATEWAY_CONVERT_RECEIVE_MESSAGE = INTEGRATION_PROPERTIES_PREFIX + "messagingGateway.convertReceiveMessage";
private static Properties defaults;
static {

View File

@@ -47,7 +47,6 @@ import org.springframework.expression.Expression;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.GatewayHeader;
import org.springframework.integration.context.IntegrationProperties;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.support.channel.BeanFactoryChannelResolver;
import org.springframework.integration.support.management.TrackableComponent;
@@ -130,8 +129,6 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
private volatile MethodArgsMessageMapper argsMapper;
private volatile boolean convertReceiveMessage;
/**
* Create a Factory whose service interface type can be configured by setter injection.
* If none is set, it will fall back to the default service interface type,
@@ -343,8 +340,6 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
}
}
this.convertReceiveMessage =
getIntegrationProperty(IntegrationProperties.GATEWAY_CONVERT_RECEIVE_MESSAGE, Boolean.class);
this.initialized = true;
}
}
@@ -434,12 +429,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint
if (paramCount == 0 && !hasPayloadExpression) {
if (shouldReply) {
if (shouldReturnMessage) {
if (this.convertReceiveMessage) {
return gateway.receive();
}
else {
return gateway.receiveMessage();
}
return gateway.receiveMessage();
}
response = gateway.receive();
}

View File

@@ -3,5 +3,3 @@ spring.integration.channels.maxUnicastSubscribers=0x7fffffff
spring.integration.channels.maxBroadcastSubscribers=0x7fffffff
spring.integration.taskScheduler.poolSize=10
spring.integration.messagingTemplate.throwExceptionOnLateReply=false
spring.integration.messagingAnnotations.require.componentAnnotation=false
spring.integration.messagingGateway.convertReceiveMessage=false

View File

@@ -13,10 +13,6 @@
<annotation-config/> <!-- Second declaration should not be a problem - see INT-3445 -->
<util:properties id="integrationGlobalProperties">
<beans:prop key="spring.integration.messagingAnnotations.require.componentAnnotation">true</beans:prop>
</util:properties>
<beans:bean id="annotatedEndpoint"
class="org.springframework.integration.config.annotation.AnnotatedEndpointActivationTests.AnnotatedEndpoint"/>

View File

@@ -17,7 +17,6 @@
package org.springframework.integration.config.annotation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -80,7 +79,7 @@ public class AnnotatedEndpointActivationTests {
assertEquals(1, count);
assertTrue(this.applicationContext.containsBean("annotatedEndpoint.process.serviceActivator"));
assertFalse(this.applicationContext.containsBean("annotatedEndpoint2.process.serviceActivator"));
assertTrue(this.applicationContext.containsBean("annotatedEndpoint2.process.serviceActivator"));
}
@Test

View File

@@ -16,20 +16,14 @@
package org.springframework.integration.gateway;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willAnswer;
import static org.mockito.Mockito.mock;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -50,8 +44,6 @@ import org.springframework.expression.Expression;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.context.IntegrationProperties;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.messaging.Message;
@@ -161,41 +153,6 @@ public class GatewayProxyFactoryBeanTests {
assertEquals("foo", message.getPayload());
}
@Test
public void testReceiveMessageConvert() throws Exception {
QueueChannel replyChannel = new QueueChannel();
replyChannel.send(new GenericMessage<>("foo"));
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean();
proxyFactory.setServiceInterface(TestService.class);
proxyFactory.setDefaultReplyChannel(replyChannel);
BeanFactory beanFactory = mock(BeanFactory.class);
given(beanFactory.containsBean(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME))
.willReturn(true);
willAnswer(invocation -> {
Properties properties = new Properties();
properties.setProperty(IntegrationProperties.GATEWAY_CONVERT_RECEIVE_MESSAGE, "true");
return properties;
})
.given(beanFactory)
.getBean(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME, Properties.class);
proxyFactory.setBeanFactory(beanFactory);
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
try {
service.getMessage();
fail("ClassCastException expected");
}
catch (Exception e) {
assertThat(e, instanceOf(ClassCastException.class));
assertThat(e.getMessage(),
containsString("java.lang.String cannot be cast to org.springframework.messaging.Message"));
}
}
@Test
public void testRequestReplyWithTypeConversion() throws Exception {
final QueueChannel requestChannel = new QueueChannel();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
@@ -68,7 +68,7 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
"max-messages-per-task", "selector",
"receive-timeout", "recovery-interval",
"idle-consumer-limit", "idle-task-execution-limit",
"cache-level", "subscription-durable", "durable-subscription-name",
"cache-level", "subscription-durable",
"subscription-shared", "subscription-name",
"client-id", "task-executor"
};
@@ -103,11 +103,6 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
return id;
}
@Override
protected boolean shouldGenerateId() {
return false;
}
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
@@ -163,7 +158,7 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
String destinationName = element.getAttribute(destinationNameAttribute);
boolean hasDestination = StringUtils.hasText(destination);
boolean hasDestinationName = StringUtils.hasText(destinationName);
if (!(hasDestination ^ hasDestinationName)) {
if (hasDestination == hasDestinationName) {
parserContext.getReaderContext().error(
"Exactly one of '" + destinationAttribute +
"' or '" + destinationNameAttribute + "' is required.", element);
@@ -178,11 +173,6 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, pubSubDomainAttribute, "pubSubDomain");
}
if (StringUtils.hasText(element.getAttribute("subscription-name"))
&& StringUtils.hasText(element.getAttribute("durable-subscription-name"))) {
parserContext.getReaderContext().error(
"Only one of 'subscription-name' or 'durable-subscription-name' is allowed.", element);
}
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "destination-resolver");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "transaction-manager");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "task-executor");
@@ -196,12 +186,9 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "idle-task-execution-limit");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "cache-level");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "subscription-durable");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "durable-subscription-name",
"subscriptionName");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "subscription-shared");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "subscription-name");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "client-id");
builder.addPropertyValue("autoStartup", false);
String beanName = adapterBeanNameRoot(element, parserContext, adapterBeanDefinition)
+ ".container";
parserContext.getRegistry().registerBeanDefinition(beanName, builder.getBeanDefinition());

View File

@@ -1525,7 +1525,7 @@
<xsd:attribute name="recovery-interval" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Interval in miliseconds between the recovery attempts
Interval in milliseconds between the recovery attempts
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@@ -1368,6 +1368,12 @@ Class `org.springframework.amqp.support.AmqpHeaders` identifies the default head
* amqp_returnRoutingKey
* amqp_channel
* amqp_consumerTag
* amqp_consumerQueue
CAUTION: As mentioned above, using a header mapping pattern `*` is a common way to copy all headers.
However, this can have some unexpected side-effects because certain RabbitMQ proprietary properties/headers will be
copied as well.
@@ -1401,7 +1407,7 @@ IMPORTANT: If you have a user defined header that begins with `!` that you *do*
To experiment with the AMQP adapters, check out the samples available in the Spring Integration Samples Git repository at:
* https://github.com/SpringSource/spring-integration-samples[https://github.com/SpringSource/spring-integration-samples]
* https://github.com/spring-projects/spring-integration-samples[https://github.com/SpringSource/spring-integration-samples]

View File

@@ -102,7 +102,7 @@ This is also defined as a constant:
IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME
----
By default Spring Integration relies on an instance of ThreadPoolTaskScheduler as described in the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html[Task Execution and Scheduling] section of the Spring Framework reference manual.
By default Spring Integration relies on an instance of `ThreadPoolTaskScheduler` as described in the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html[Task Execution and Scheduling] section of the Spring Framework reference manual.
That default TaskScheduler will startup automatically with a pool of 10 threads, but see <<global-properties>>.
If you provide your own TaskScheduler instance instead, you can set the 'autoStartup' property to _false_, and/or you can provide your own pool size value.
@@ -205,7 +205,6 @@ spring.integration.channels.maxUnicastSubscribers=0x7fffffff <2>
spring.integration.channels.maxBroadcastSubscribers=0x7fffffff <3>
spring.integration.taskScheduler.poolSize=10 <4>
spring.integration.messagingTemplate.throwExceptionOnLateReply=false <5>
spring.integration.messagingAnnotations.require.componentAnnotation=false <6>
----
<1> When true, `input-channel` s will be automatically declared as `DirectChannel` s when not explicitly found in the
@@ -224,15 +223,9 @@ This can be overridden on individual channels with the `max-subscribers` attribu
<5> When `true`, messages that arrive at a gateway reply channel will throw an exception, when the gateway is not
expecting a reply - because the sending thread has timed out, or already received a reply.
<6> When `true`, Messaging Annotation Support (<<annotations>>) requires a declaration of the
`@MessageEndpoint` (or any other `@Component`) annotation on the class level.
These properties can be overridden by adding a file `/META-INF/spring.integration.properties` to the classpath.
It is not necessary to provide all the properties, just those that you want to override.
NOTE: In versions prior to _4.3_, these property names had a typographical error (`...integraton...`); they have now been
corrected (`...integration...`).
[[annotations]]
=== Annotation Support
@@ -304,7 +297,7 @@ public class FooService {
}
----
There is also a @Headers annotation that provides all of the Message headers as a Map:
There is also a `@Headers` annotation that provides all of the Message headers as a Map:
[source,java]
----
public class FooService {
@@ -365,18 +358,17 @@ Starting with _version 4.0_, the `@Poller` annotation has been introduced to all
----
public class AnnotationService {
@Transformer(inputChannel = "input", outputChannel = "output",
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.fixedDelay}"))
public String handle(String payload) {
...
}
@Transformer(inputChannel = "input", outputChannel = "output",
poller = @Poller(maxMessagesPerPoll = "${poller.maxMessagesPerPoll}", fixedDelay = "${poller.fixedDelay}"))
public String handle(String payload) {
...
}
}
----
This annotation provides only simple `PollerMetadata` options.
The `@Poller`'s attributes `maxMessagesPerPoll`, `fixedDelay`, `fixedRate` and `cron` can be configured with _property-placeholder_s.
If it is necessary to provide more polling options (e.g.
transaction, advice-chain, error-handler), the`PollerMetadata` should be configured as a generic bean with its bean name used for `@Poller`'s `value` attribute.
The `@Poller`'s attributes `maxMessagesPerPoll`, `fixedDelay`, `fixedRate` and `cron` can be configured with _property-placeholders_.
If it is necessary to provide more polling options (e.g. transaction, advice-chain, error-handler), the `PollerMetadata` should be configured as a generic bean with its bean name used for `@Poller`'s `value` attribute.
In this case, no other attributes are allowed (they would be specified on the `PollerMetadata` bean).
Note, if `inputChannel` is `PollableChannel` and no `@Poller` is configured, the default `PollerMetadata` will be used, if it is present in the application context.
To declare the default poller using `@Configuration`, use:
@@ -384,9 +376,9 @@ To declare the default poller using `@Configuration`, use:
----
@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(10));
return pollerMetadata;
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(10));
return pollerMetadata;
}
----
@@ -395,10 +387,10 @@ With this endpoint using the default poller:
----
public class AnnotationService {
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output")
public String handle(String payload) {
...
}
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output")
public String handle(String payload) {
...
}
}
----
@@ -407,9 +399,9 @@ To use a named poller, use:
----
@Bean
public PollerMetadata myPoller() {
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(1000));
return pollerMetadata;
PollerMetadata pollerMetadata = new PollerMetadata();
pollerMetadata.setTrigger(new PeriodicTrigger(1000));
return pollerMetadata;
}
----
@@ -418,11 +410,11 @@ With this endpoint using the default poller:
----
public class AnnotationService {
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output"
poller = @Poller("myPoller")
public String handle(String payload) {
...
}
@Transformer(inputChannel = "aPollableChannel", outputChannel = "output"
poller = @Poller("myPoller")
public String handle(String payload) {
...
}
}
----
@@ -438,12 +430,12 @@ If there is need to provide some `MessageHeaders`, use a `Message<?>` return typ
----
@InboundChannelAdapter("counterChannel")
public Integer count() {
return this.counter.incrementAndGet();
return this.counter.incrementAndGet();
}
@InboundChannelAdapter(value = "fooChannel", poller = @Poller(fixed-rate = "5000"))
public String foo() {
return "foo";
return "foo";
}
----
@@ -487,7 +479,7 @@ In addition, meta-annotations can be configured hierarchically:
@ServiceActivator(inputChannel = "annInput", outputChannel = "annOutput")
public @interface MyServiceActivator {
String[] adviceChain = { "annAdvice" };
String[] adviceChain = { "annAdvice" };
}
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@@ -495,9 +487,9 @@ public @interface MyServiceActivator {
@MyServiceActivator
public @interface MyServiceActivator1 {
String inputChannel();
String inputChannel();
String outputChannel();
String outputChannel();
}
...
@@ -521,32 +513,32 @@ It is useful when `@Bean` definitions are "out of the box" `MessageHandler` s (`
@EnableIntegration
public class MyFlowConfiguration {
@Bean
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
public MessageSource<String> consoleSource() {
return CharacterStreamReadingMessageSource.stdin();
}
@Bean
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
public MessageSource<String> consoleSource() {
return CharacterStreamReadingMessageSource.stdin();
}
@Bean
@Transformer(inputChannel = "inputChannel", outputChannel = "httpChannel")
public ObjectToMapTransformer toMapTransformer() {
return new ObjectToMapTransformer();
}
@Bean
@Transformer(inputChannel = "inputChannel", outputChannel = "httpChannel")
public ObjectToMapTransformer toMapTransformer() {
return new ObjectToMapTransformer();
}
@Bean
@ServiceActivator(inputChannel = "httpChannel")
public MessageHandler httpHandler() {
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("http://foo/service");
handler.setExpectedResponseType(String.class);
handler.setOutputChannelName("outputChannel");
return handler;
}
@Bean
@ServiceActivator(inputChannel = "httpChannel")
public MessageHandler httpHandler() {
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("http://foo/service");
handler.setExpectedResponseType(String.class);
handler.setOutputChannelName("outputChannel");
return handler;
}
@Bean
@ServiceActivator(inputChannel = "outputChannel")
public LoggingHandler loggingHandler() {
return new LoggingHandler("info");
}
@Bean
@ServiceActivator(inputChannel = "outputChannel")
public LoggingHandler loggingHandler() {
return new LoggingHandler("info");
}
}
----
@@ -578,7 +570,7 @@ method level, meaning to skip the bean registration by some condition reason:
@ServiceActivator(inputChannel = "skippedChannel")
@Profile("foo")
public MessageHandler skipped() {
return System.out::println;
return System.out::println;
}
----
Together with the existing Spring Container logic, the Messaging Endpoint bean, based on the `@ServiceActivator`
@@ -592,23 +584,23 @@ This is just for completeness, providing a convenient mechanism to declare a`Bri
----
@Bean
public PollableChannel bridgeFromInput() {
return new QueueChannel();
return new QueueChannel();
}
@Bean
@BridgeFrom(value = "bridgeFromInput", poller = @Poller(fixedDelay = "1000"))
public MessageChannel bridgeFromOutput() {
return new DirectChannel();
return new DirectChannel();
}
@Bean
public QueueChannel bridgeToOutput() {
return new QueueChannel();
return new QueueChannel();
}
@Bean
@BridgeTo("bridgeToOutput")
public MessageChannel bridgeToInput() {
return new DirectChannel();
return new DirectChannel();
}
----
@@ -770,7 +762,8 @@ The payload is not being mapped to any argument.
_Multiple parameters:_
Multiple parameters could create a lot of ambiguity with regards to determining the appropriate mappings.
The general advice is to annotate your method parameters with @Payload and/or @Header/@Headers Below are some of the examples of ambiguous conditions which result in an Exception being raised.
The general advice is to annotate your method parameters with `@Payload` and/or `@Header`/`@Headers`.
Below are some of the examples of ambiguous conditions which result in an Exception being raised.
[source,java]
----
@@ -805,9 +798,9 @@ _Multiple methods (same or different name) with legal (mappable) signatures:_
[source,java]
----
public class Foo {
public String foo(String str, Map m);
public String foo(String str, Map m);
public String foo(Map m);
public String foo(Map m);
}
----
@@ -819,7 +812,7 @@ To make meters worse both methods have the same name which at first might look v
[source,xml]
----
<int:service-activator input-channel="input" output-channel="output" method="foo">
<bean class="org.bar.Foo"/>
<bean class="org.bar.Foo"/>
</int:service-activator>
----
@@ -831,9 +824,9 @@ On the other hand let's look at slightly different example:
[source,java]
----
public class Foo {
public String foo(String str, Map m);
public String foo(String str, Map m);
public String foo(String str);
public String foo(String str);
}
----
@@ -846,16 +839,16 @@ However if the method names were different you could influence the mapping with
[source,java]
----
public class Foo {
public String foo(String str, Map m);
public String foo(String str, Map m);
public String bar(String str);
public String bar(String str);
}
----
[source,xml]
----
<int:service-activator input-channel="input" output-channel="output" method="bar">
<bean class="org.bar.Foo"/>
<bean class="org.bar.Foo"/>
</int:service-activator>
----