From dd72b9b63d209f62d509174a39333fbdbd8a76cc Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Tue, 3 Jan 2017 13:06:47 -0500 Subject: [PATCH] INT-4197: Fix Annotation Case when not `messages` JIRA: https://jira.spring.io/browse/INT-4197 Since `Collection>` can be possible only if we are dealing with messages as a group (`MethodInvokingMessageListProcessor`), the case with the `List` param for Messaging Annotation method should not be treated as candidate for `messages` collection. * Add `this.canProcessMessageList` condition to avoid `messages` SpEL expression when we are not in the `MethodInvokingMessageListProcessor` environment **Cherry-pick to 4.3.x** * Fix Array creating formatting * Add comment about `ReflectiveMethodExecutor` to the `testRouterWithListParam()` * Send one test data as as `Collection` to be sure that `@Router` parameters mapping works well --- .../util/MessagingMethodInvokerHelper.java | 7 ++- .../RouterAnnotationPostProcessorTests.java | 59 +++++++++++++++++-- .../config/RouterParserTests-context.xml | 2 +- .../router/config/RouterParserTests.java | 4 +- 4 files changed, 60 insertions(+), 12 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java b/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java index 2f56eea796..0c4a58815e 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -752,8 +752,9 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator sb.append("message"); this.setExclusiveTargetParameterType(parameterTypeDescriptor, methodParameter); } - else if ((parameterTypeDescriptor.isAssignableTo(messageListTypeDescriptor) - || parameterTypeDescriptor.isAssignableTo(messageArrayTypeDescriptor))) { + else if (this.canProcessMessageList && + (parameterTypeDescriptor.isAssignableTo(messageListTypeDescriptor) + || parameterTypeDescriptor.isAssignableTo(messageArrayTypeDescriptor))) { sb.append("messages"); this.setExclusiveTargetParameterType(parameterTypeDescriptor, methodParameter); } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/RouterAnnotationPostProcessorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/RouterAnnotationPostProcessorTests.java index 8c2d7414b0..8cabd8754e 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/RouterAnnotationPostProcessorTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/annotation/RouterAnnotationPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -18,34 +18,47 @@ package org.springframework.integration.config.annotation; import static org.junit.Assert.assertEquals; +import java.util.Collections; +import java.util.List; + import org.junit.Before; import org.junit.Test; -import org.springframework.messaging.Message; import org.springframework.integration.annotation.MessageEndpoint; import org.springframework.integration.annotation.Router; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.channel.QueueChannel; -import org.springframework.messaging.support.GenericMessage; import org.springframework.integration.test.util.TestUtils; import org.springframework.integration.test.util.TestUtils.TestApplicationContext; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.GenericMessage; /** * @author Mark Fisher + * @author Artem Bilan */ public class RouterAnnotationPostProcessorTests { - private TestApplicationContext context = TestUtils.createTestApplicationContext(); + private final TestApplicationContext context = TestUtils.createTestApplicationContext(); - private DirectChannel inputChannel = new DirectChannel(); + private final DirectChannel inputChannel = new DirectChannel(); - private QueueChannel outputChannel = new QueueChannel(); + private final QueueChannel outputChannel = new QueueChannel(); + + private final DirectChannel routingChannel = new DirectChannel(); + + private final QueueChannel integerChannel = new QueueChannel(); + + private final QueueChannel stringChannel = new QueueChannel(); @Before public void init() { context.registerChannel("input", inputChannel); context.registerChannel("output", outputChannel); + context.registerChannel("routingChannel", routingChannel); + context.registerChannel("integerChannel", integerChannel); + context.registerChannel("stringChannel", stringChannel); } @@ -63,6 +76,26 @@ public class RouterAnnotationPostProcessorTests { context.stop(); } + @Test + public void testRouterWithListParam() { + MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor(); + postProcessor.setBeanFactory(context.getBeanFactory()); + postProcessor.afterPropertiesSet(); + TestRouter testRouter = new TestRouter(); + postProcessor.postProcessAfterInitialization(testRouter, "test"); + context.refresh(); + + routingChannel.send(new GenericMessage<>(Collections.singletonList("foo"))); + Message replyMessage = stringChannel.receive(0); + assertEquals(Collections.singletonList("foo"), replyMessage.getPayload()); + + // The SpEL ReflectiveMethodExecutor does a conversion of a single value to a List + routingChannel.send(new GenericMessage(2)); + replyMessage = integerChannel.receive(0); + assertEquals(2, replyMessage.getPayload()); + context.stop(); + } + @MessageEndpoint public static class TestRouter { @@ -71,6 +104,20 @@ public class RouterAnnotationPostProcessorTests { public String test(String s) { return null; } + + @Router(inputChannel = "routingChannel") + public String route(List payload) { + if (payload.size() == 0) { + return null; + } + if (payload.get(0) instanceof Integer) { + return "integerChannel"; + } + else { + return "stringChannel"; + } + } + } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterParserTests-context.xml index 6f9e050cab..aee10b1faf 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterParserTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterParserTests-context.xml @@ -96,6 +96,6 @@ + class="org.springframework.integration.router.config.RouterParserTests$TestChannelResolver"/> diff --git a/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterParserTests.java index d35031d73f..a03a8a28c0 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/router/config/RouterParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -285,7 +285,7 @@ public class RouterParserTests { } - static class TestChannelResover implements DestinationResolver { + static class TestChannelResolver implements DestinationResolver { @Override public MessageChannel resolveDestination(String channelName) {