Skip to content

Commit 00c983d

Browse files
artembilangaryrussell
authored andcommitted
INT-4410 CollArgResolver only for group processor
JIRA: https://jira.spring.io/browse/INT-4410 The `CollectionArgumentResolver` has been introduced especially for the cases to work with `MessageGroupProcessor` (an aggregator) when the payload is a `Collection<Message<?>>`. This use-case doesn't apply for the general collection parameter use-case. * Register `CollectionArgumentResolver` only when `listCapable` option. For all other collection-based use-cases fallback to the standard `PayloadArgumentResolver` with an appropriate configured `MessageConverter` Note: this is for backward compatibility. In the `5.1` we may reconsider to use `MessageConverter` in the `CollectionArgumentResolver` as well, or just remove it altogether with an appropriate logic in the `PayloadArgumentResolver`, since this `CollectionArgumentResolver` solution isn't robust
1 parent f0a6cb7 commit 00c983d

File tree

3 files changed

+110
-14
lines changed

3 files changed

+110
-14
lines changed

spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2017 the original author or authors.
2+
* Copyright 2014-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -463,10 +463,13 @@ private BeanDefinition internalArgumentResolversBuilder(boolean listCapable) {
463463
resolvers.add(new RootBeanDefinition(PayloadExpressionArgumentResolver.class));
464464
resolvers.add(new RootBeanDefinition(PayloadsArgumentResolver.class));
465465
resolvers.add(new RootBeanDefinition(MapArgumentResolver.class));
466-
resolvers.add(
467-
BeanDefinitionBuilder.genericBeanDefinition(CollectionArgumentResolver.class)
468-
.addConstructorArgValue(listCapable)
469-
.getBeanDefinition());
466+
467+
if (listCapable) {
468+
resolvers.add(
469+
BeanDefinitionBuilder.genericBeanDefinition(CollectionArgumentResolver.class)
470+
.addConstructorArgValue(true)
471+
.getBeanDefinition());
472+
}
470473

471474
return BeanDefinitionBuilder.genericBeanDefinition(HandlerMethodArgumentResolversHolder.class)
472475
.addConstructorArgValue(resolvers)

spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -577,17 +577,19 @@ private void configureLocalMessageHandlerFactory() {
577577
PayloadsArgumentResolver payloadsArgumentResolver = new PayloadsArgumentResolver();
578578
payloadsArgumentResolver.setBeanFactory(getBeanFactory());
579579

580-
CollectionArgumentResolver collectionArgumentResolver =
581-
new CollectionArgumentResolver(this.canProcessMessageList);
582-
collectionArgumentResolver.setBeanFactory(getBeanFactory());
583-
584580
MapArgumentResolver mapArgumentResolver = new MapArgumentResolver();
585581
mapArgumentResolver.setBeanFactory(getBeanFactory());
586582

587583
List<HandlerMethodArgumentResolver> customArgumentResolvers = new LinkedList<>();
588584
customArgumentResolvers.add(payloadExpressionArgumentResolver);
589585
customArgumentResolvers.add(payloadsArgumentResolver);
590-
customArgumentResolvers.add(collectionArgumentResolver);
586+
587+
if (this.canProcessMessageList) {
588+
CollectionArgumentResolver collectionArgumentResolver = new CollectionArgumentResolver(true);
589+
collectionArgumentResolver.setBeanFactory(getBeanFactory());
590+
customArgumentResolvers.add(collectionArgumentResolver);
591+
}
592+
591593
customArgumentResolvers.add(mapArgumentResolver);
592594

593595
this.messageHandlerMethodFactory.setCustomArgumentResolvers(customArgumentResolvers);

spring-integration-core/src/test/java/org/springframework/integration/handler/MethodInvokingMessageProcessorTests.java

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,16 +31,19 @@
3131
import static org.mockito.Mockito.mock;
3232

3333
import java.lang.reflect.Method;
34+
import java.util.Arrays;
3435
import java.util.Collections;
3536
import java.util.Date;
3637
import java.util.LinkedHashMap;
38+
import java.util.List;
3739
import java.util.Map;
3840
import java.util.Optional;
3941
import java.util.Properties;
4042
import java.util.UUID;
4143
import java.util.concurrent.CountDownLatch;
4244
import java.util.concurrent.atomic.AtomicBoolean;
4345
import java.util.concurrent.atomic.AtomicReference;
46+
import java.util.stream.Collectors;
4447

4548
import org.aopalliance.intercept.MethodInterceptor;
4649
import org.apache.commons.logging.Log;
@@ -56,6 +59,9 @@
5659
import org.springframework.beans.DirectFieldAccessor;
5760
import org.springframework.beans.factory.BeanFactory;
5861
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
62+
import org.springframework.context.ApplicationContext;
63+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
64+
import org.springframework.context.annotation.Configuration;
5965
import org.springframework.expression.Expression;
6066
import org.springframework.expression.spel.SpelCompilerMode;
6167
import org.springframework.expression.spel.SpelEvaluationException;
@@ -64,6 +70,7 @@
6470
import org.springframework.expression.spel.support.StandardEvaluationContext;
6571
import org.springframework.integration.annotation.ServiceActivator;
6672
import org.springframework.integration.annotation.UseSpelInvoker;
73+
import org.springframework.integration.config.EnableIntegration;
6774
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
6875
import org.springframework.integration.gateway.RequestReplyExchanger;
6976
import org.springframework.integration.support.MessageBuilder;
@@ -79,6 +86,9 @@
7986
import org.springframework.messaging.support.GenericMessage;
8087
import org.springframework.util.StopWatch;
8188

89+
import com.fasterxml.jackson.core.JsonProcessingException;
90+
import com.fasterxml.jackson.databind.ObjectMapper;
91+
8292

8393
/**
8494
* @author Mark Fisher
@@ -896,7 +906,7 @@ public void testUseSpelInvoker() throws Exception {
896906
catch (IllegalArgumentException e) {
897907
assertThat(e.getMessage(), equalTo(
898908
"UseSpelInvoker.compilerMode: Object of class [java.lang.Object] "
899-
+ "must be an instance of class java.lang.String"));
909+
+ "must be an instance of class java.lang.String"));
900910
}
901911

902912
// Check other CTORs
@@ -916,7 +926,7 @@ public void testSingleMethodJson() throws Exception {
916926
SingleMethodJsonWithSpELBean bean = new SingleMethodJsonWithSpELBean();
917927
MessagingMethodInvokerHelper<?> helper = new MessagingMethodInvokerHelper<>(bean,
918928
SingleMethodJsonWithSpELBean.class.getDeclaredMethod("foo",
919-
SingleMethodJsonWithSpELBean.Foo.class),
929+
SingleMethodJsonWithSpELBean.Foo.class),
920930
false);
921931
Message<?> message = new GenericMessage<>("{\"bar\":\"bar\"}",
922932
Collections.singletonMap(MessageHeaders.CONTENT_TYPE, "application/json"));
@@ -979,6 +989,87 @@ public void testCompiledSpELForProxy() {
979989
}
980990

981991

992+
@Test
993+
public void testCollectionArgument() throws JsonProcessingException {
994+
995+
class A {
996+
997+
@SuppressWarnings("unused")
998+
public String myMethod(List<Employee<Person>> msg) {
999+
return msg.stream()
1000+
.map(Employee::getEntity)
1001+
.map(Person::getName)
1002+
.collect(Collectors.joining(","));
1003+
}
1004+
1005+
}
1006+
1007+
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfiguration.class);
1008+
1009+
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new A(), "myMethod");
1010+
processor.setBeanFactory(applicationContext);
1011+
1012+
List<Employee<Person>> testData =
1013+
Arrays.asList(
1014+
new Employee<>(new Person("Foo")),
1015+
new Employee<>(new Person("Bar")));
1016+
1017+
ObjectMapper objectMapper = new ObjectMapper();
1018+
byte[] value = objectMapper.writeValueAsBytes(testData);
1019+
1020+
String result = (String) processor.processMessage(new GenericMessage<>(value));
1021+
1022+
assertEquals("Foo,Bar", result);
1023+
}
1024+
1025+
public static class Employee<T> {
1026+
1027+
private T entity;
1028+
1029+
public Employee() {
1030+
}
1031+
1032+
public Employee(T entity) {
1033+
this.entity = entity;
1034+
}
1035+
1036+
public void setEntity(T entity) {
1037+
this.entity = entity;
1038+
}
1039+
1040+
public T getEntity() {
1041+
return this.entity;
1042+
}
1043+
1044+
}
1045+
1046+
public static class Person {
1047+
1048+
private String name;
1049+
1050+
public Person() {
1051+
}
1052+
1053+
public Person(String name) {
1054+
this.name = name;
1055+
}
1056+
1057+
public void setName(String name) {
1058+
this.name = name;
1059+
}
1060+
1061+
public String getName() {
1062+
return this.name;
1063+
}
1064+
1065+
}
1066+
1067+
@Configuration
1068+
@EnableIntegration
1069+
public static class TestConfiguration {
1070+
1071+
}
1072+
9821073
public interface Foo {
9831074

9841075
String handle(String payload);

0 commit comments

Comments
 (0)