INT-538, INT-665, INT-818: @Header, @Headers and (new) @Payloads recognised in message list POJOs

* All method scanning and expression building is consolidated in one place
* MessageProcessor and MessageListProcessor implementations share commmon delegate helper
This commit is contained in:
David Syer
2010-08-10 10:48:25 +00:00
parent 7df44e7da3
commit e6b508ca87
34 changed files with 1705 additions and 1312 deletions

View File

@@ -31,7 +31,7 @@ import org.springframework.integration.MessageHeaders;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.MessageBuilder;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.core.MessagingOperations;
import org.springframework.integration.store.MessageGroup;
import org.springframework.integration.store.SimpleMessageStore;
@@ -231,7 +231,7 @@ public class AggregatorTests {
}
private class MultiplyingProcessor implements MessageGroupProcessor {
public void processAndSend(MessageGroup group, MessagingTemplate messagingTemplate,
public void processAndSend(MessageGroup group, MessagingOperations messagingTemplate,
MessageChannel outputChannel) {
Integer product = 1;
for (Message<?> message : group.getUnmarked()) {
@@ -242,7 +242,7 @@ public class AggregatorTests {
}
private class NullReturningMessageProcessor implements MessageGroupProcessor {
public void processAndSend(MessageGroup group, MessagingTemplate messagingTemplate,
public void processAndSend(MessageGroup group, MessagingOperations messagingTemplate,
MessageChannel outputChannel) {
// noop
}

View File

@@ -37,7 +37,7 @@ import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.MessageBuilder;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.core.MessagingOperations;
import org.springframework.integration.store.MessageGroup;
import org.springframework.integration.store.MessageGroupStore;
import org.springframework.integration.store.SimpleMessageStore;
@@ -344,7 +344,7 @@ public class ConcurrentAggregatorTests {
private class MultiplyingProcessor implements MessageGroupProcessor {
public void processAndSend(MessageGroup group,
MessagingTemplate messagingTemplate,
MessagingOperations messagingTemplate,
MessageChannel outputChannel) {
Integer product = 1;
for (Message<?> message : group.getUnmarked()) {
@@ -356,7 +356,7 @@ public class ConcurrentAggregatorTests {
private class NullReturningMessageProcessor implements MessageGroupProcessor {
public void processAndSend(MessageGroup group,
MessagingTemplate messagingTemplate,
MessagingOperations messagingTemplate,
MessageChannel outputChannel) {
// noop
}

View File

@@ -34,7 +34,7 @@ import static org.mockito.Mockito.*;
* @author Iwein Fuld
*/
@RunWith(MockitoJUnitRunner.class)
public class CorrelatingMessageBarrierTest {
public class CorrelatingMessageBarrierTests {
private CorrelatingMessageBarrier barrier;
@Mock

View File

@@ -25,29 +25,38 @@ import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.integration.Message;
import org.springframework.integration.annotation.Aggregator;
import org.springframework.integration.annotation.Header;
import org.springframework.integration.annotation.Headers;
import org.springframework.integration.annotation.Payloads;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.MessageBuilder;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.core.StringMessage;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.store.MessageGroup;
import org.springframework.integration.store.SimpleMessageGroup;
@RunWith(MockitoJUnitRunner.class)
public class MethodInvokingMessageGroupProcessorTests {
@@ -70,27 +79,28 @@ public class MethodInvokingMessageGroupProcessorTests {
messagesUpForProcessing.add(MessageBuilder.withPayload(4).build());
}
@SuppressWarnings("unused")
private class AnnotatedAggregatorMethod {
@Aggregator
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
public String know(List<Integer> flags) {
return "I'm not the one ";
}
}
@SuppressWarnings("unchecked")
@Test
public void shouldFindAnnotatedAggregatorMethod() throws Exception {
@SuppressWarnings("unused")
class AnnotatedAggregatorMethod {
@Aggregator
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
public String know(List<Integer> flags) {
return "I'm not the one ";
}
}
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new AnnotatedAggregatorMethod());
@SuppressWarnings("unchecked")
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
@@ -100,21 +110,22 @@ public class MethodInvokingMessageGroupProcessorTests {
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@SuppressWarnings("unused")
private class SimpleAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
}
@Test
@SuppressWarnings("unchecked")
public void shouldFindSimpleAggregatorMethod() throws Exception {
@SuppressWarnings("unused")
class SimpleAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
}
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new SimpleAggregator());
@SuppressWarnings("unchecked")
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
@@ -124,31 +135,169 @@ public class MethodInvokingMessageGroupProcessorTests {
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@SuppressWarnings("unused")
private class UnannotatedAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
@Test
@SuppressWarnings("unchecked")
public void shouldFindSimpleAggregatorMethodForMessages() throws Exception {
@SuppressWarnings("unused")
class SimpleAggregator {
public Integer and(List<Message<Integer>> flags) {
int result = 0;
for (Message<Integer> flag : flags) {
result = result | flag.getPayload();
}
return result;
}
return result;
}
public void voidMethodShouldBeIgnored(List<Integer> flags) {
fail("this method should not be invoked");
}
public String methodAcceptingNoCollectionShouldBeIgnored(@Header String irrelevant) {
fail("this method should not be invoked");
return null;
}
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new SimpleAggregator());
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, messagingTemplate, outputChannel);
// verify
verify(messagingTemplate).send(eq(outputChannel), messageCaptor.capture());
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@Test
@SuppressWarnings("unchecked")
public void shouldFindAnnotatedPayloads() throws Exception {
@SuppressWarnings("unused")
class SimpleAggregator {
public String and(@Payloads List<Integer> flags, @Header("foo") List<Integer> header) {
List<Integer> result = new ArrayList<Integer>();
for (int flag : flags) {
result.add(flag);
}
for (int flag : header) {
result.add(flag);
}
return result.toString();
}
}
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new SimpleAggregator());
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
messagesUpForProcessing.add(MessageBuilder.withPayload(3).setHeader("foo", Arrays.asList(101, 102)).build());
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, messagingTemplate, outputChannel);
// verify
verify(messagingTemplate).send(eq(outputChannel), messageCaptor.capture());
assertThat((String) messageCaptor.getValue().getPayload(), is("[1, 2, 4, 3, 101, 102]"));
}
@Test
@SuppressWarnings("unchecked")
public void shouldFindSimpleAggregatorMethodWithCollection() throws Exception {
@SuppressWarnings("unused")
class SimpleAggregator {
public Integer and(Collection<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
}
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new SimpleAggregator());
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, messagingTemplate, outputChannel);
// verify
verify(messagingTemplate).send(eq(outputChannel), messageCaptor.capture());
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@Test
@SuppressWarnings("unchecked")
public void shouldFindSimpleAggregatorMethodWithArray() throws Exception {
@SuppressWarnings("unused")
class SimpleAggregator {
public Integer and(int[] flags) {
int result = 0;
for (int flag : flags) {
result = result | flag;
}
return result;
}
}
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new SimpleAggregator());
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, messagingTemplate, outputChannel);
// verify
verify(messagingTemplate).send(eq(outputChannel), messageCaptor.capture());
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@Ignore("INT-938: it probably should work if there is a converter registered, but maybe a SpEL bug?")
@Test
@SuppressWarnings("unchecked")
public void shouldFindSimpleAggregatorMethodWithIterator() throws Exception {
@SuppressWarnings("unused")
class SimpleAggregator {
public Integer and(Iterator<Integer> flags) {
int result = 0;
for (int flag = flags.next(); flags.hasNext();) {
result = result | flag;
}
return result;
}
}
MethodInvokingMessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new SimpleAggregator());
GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
conversionService.addConverter(new Converter<ArrayList<?>, Iterator<?>>() {
public Iterator<?> convert(ArrayList<?> source) {
return source.iterator();
}
});
processor.setConversionService(conversionService);
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, messagingTemplate, outputChannel);
// verify
verify(messagingTemplate).send(eq(outputChannel), messageCaptor.capture());
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@Test
@SuppressWarnings("unchecked")
public void shouldFindFittingMethodAmongMultipleUnannotated() {
@SuppressWarnings("unused")
class UnannotatedAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
public void voidMethodShouldBeIgnored(List<Integer> flags) {
fail("this method should not be invoked");
}
public String methodAcceptingNoCollectionShouldBeIgnored(String irrelevant) {
fail("this method should not be invoked");
return null;
}
}
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new UnannotatedAggregator());
@SuppressWarnings("unchecked")
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
@@ -159,69 +308,168 @@ public class MethodInvokingMessageGroupProcessorTests {
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@SuppressWarnings("unused")
private class AnnotatedParametersAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
@Test(expected = IllegalArgumentException.class)
public void testTwoMethodsWithSameParameterTypesAmbiguous() {
@SuppressWarnings("unused")
class AnnotatedParametersAggregator {
public Integer and(List<Integer> flags) {
int result = 0;
for (Integer flag : flags) {
result = result | flag;
}
return result;
}
public String listHeaderShouldBeIgnored(@Header List<Integer> flags) {
fail("this method should not be invoked");
return "";
}
return result;
}
public String listHeaderShouldBeIgnored(@Header List<Integer> flags) {
fail("this method should not be invoked");
return "";
}
}
new MethodInvokingMessageGroupProcessor(new AnnotatedParametersAggregator());
@Test
public void shouldFindFittingMethodAmongMultipleWithAnnotatedParameters() {
MessageGroupProcessor processor = new MethodInvokingMessageGroupProcessor(new AnnotatedParametersAggregator());
@SuppressWarnings("unchecked")
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
when(outputChannel.send(isA(Message.class))).thenReturn(true);
when(messageGroupMock.getUnmarked()).thenReturn(messagesUpForProcessing);
processor.processAndSend(messageGroupMock, messagingTemplate, outputChannel);
// verify
verify(messagingTemplate).send(eq(outputChannel), messageCaptor.capture());
assertThat((Integer) messageCaptor.getValue().getPayload(), is(7));
}
@Test
public void singleAnnotation() throws Exception {
@SuppressWarnings("unused")
class SingleAnnotationTestBean {
@Aggregator
public String method1(List<String> input) {
return input.get(0);
}
public String method2(List<String> input) {
return input.get(1);
}
}
SingleAnnotationTestBean bean = new SingleAnnotationTestBean();
MethodInvokingMessageGroupProcessor aggregator = new MethodInvokingMessageGroupProcessor(bean);
Method method = this.getMethod(aggregator);
Method expected = SingleAnnotationTestBean.class.getMethod("method1", new Class[] { List.class });
assertEquals(expected, method);
SimpleMessageGroup group = new SimpleMessageGroup("FOO");
group.add(new StringMessage("foo"));
group.add(new StringMessage("bar"));
assertEquals("foo", aggregator.aggregatePayloads(group, null));
}
@Test
public void testHeaderParameters() throws Exception {
@SuppressWarnings("unused")
class SingleAnnotationTestBean {
@Aggregator
public String method1(List<String> input, @Header("foo") String foo) {
return input.get(0) + foo;
}
}
SingleAnnotationTestBean bean = new SingleAnnotationTestBean();
MethodInvokingMessageGroupProcessor aggregator = new MethodInvokingMessageGroupProcessor(bean);
SimpleMessageGroup group = new SimpleMessageGroup("FOO");
group.add(MessageBuilder.withPayload("foo").setHeader("foo", "bar").build());
group.add(MessageBuilder.withPayload("bar").setHeader("foo", "bar").build());
assertEquals("foobar", aggregator.aggregatePayloads(group, aggregator.aggregateHeaders(group)));
}
@Test
public void testHeadersParameters() throws Exception {
@SuppressWarnings("unused")
class SingleAnnotationTestBean {
@Aggregator
public String method1(List<String> input, @Headers Map<String, ?> map) {
return input.get(0) + map.get("foo");
}
}
SingleAnnotationTestBean bean = new SingleAnnotationTestBean();
MethodInvokingMessageGroupProcessor aggregator = new MethodInvokingMessageGroupProcessor(bean);
SimpleMessageGroup group = new SimpleMessageGroup("FOO");
group.add(MessageBuilder.withPayload("foo").setHeader("foo", "bar").build());
group.add(MessageBuilder.withPayload("bar").setHeader("foo", "bar").build());
assertEquals("foobar", aggregator.aggregatePayloads(group, aggregator.aggregateHeaders(group)));
}
@Test(expected = IllegalArgumentException.class)
public void multipleAnnotations() {
@SuppressWarnings("unused")
class MultipleAnnotationTestBean {
@Aggregator
public String method1(List<String> input) {
return input.get(0);
}
@Aggregator
public String method2(List<String> input) {
return input.get(0);
}
}
MultipleAnnotationTestBean bean = new MultipleAnnotationTestBean();
new MethodInvokingMessageGroupProcessor(bean);
}
@Test
public void noAnnotations() throws Exception {
@SuppressWarnings("unused")
class NoAnnotationTestBean {
public String method1(List<String> input) {
return input.get(0);
}
String method2(List<String> input) {
return input.get(1);
}
}
NoAnnotationTestBean bean = new NoAnnotationTestBean();
MethodInvokingMessageGroupProcessor aggregator = new MethodInvokingMessageGroupProcessor(bean);
Method method = this.getMethod(aggregator);
Method expected = NoAnnotationTestBean.class.getMethod("method1", new Class[] { List.class });
assertEquals(expected, method);
SimpleMessageGroup group = new SimpleMessageGroup("FOO");
group.add(new StringMessage("foo"));
group.add(new StringMessage("bar"));
assertEquals("foo", aggregator.aggregatePayloads(group, null));
}
@Test(expected = IllegalArgumentException.class)
public void multiplePublicMethods() {
@SuppressWarnings("unused")
class MultiplePublicMethodTestBean {
public String upperCase(String s) {
return s.toUpperCase();
}
public String lowerCase(String s) {
return s.toLowerCase();
}
}
MultiplePublicMethodTestBean bean = new MultiplePublicMethodTestBean();
new MethodInvokingMessageGroupProcessor(bean);
}
@Test(expected = IllegalArgumentException.class)
public void noPublicMethods() {
@SuppressWarnings("unused")
class NoPublicMethodTestBean {
String lowerCase(String s) {
return s.toLowerCase();
}
}
NoPublicMethodTestBean bean = new NoPublicMethodTestBean();
new MethodInvokingMessageGroupProcessor(bean);
}
@@ -264,74 +512,8 @@ public class MethodInvokingMessageGroupProcessorTests {
assertEquals("hello proxy", output.receive(0).getPayload());
}
private Method getMethod(MethodInvokingMessageGroupProcessor aggregator) {
Object invoker = new DirectFieldAccessor(aggregator).getPropertyValue("adapter");
return (Method) new DirectFieldAccessor(invoker).getPropertyValue("method");
}
@SuppressWarnings("unused")
private static class SingleAnnotationTestBean {
@Aggregator
public String method1(List<String> input) {
return input.get(0);
}
public String method2(List<String> input) {
return input.get(0);
}
}
@SuppressWarnings("unused")
private static class MultipleAnnotationTestBean {
@Aggregator
public String method1(List<String> input) {
return input.get(0);
}
@Aggregator
public String method2(List<String> input) {
return input.get(0);
}
}
@SuppressWarnings("unused")
private static class NoAnnotationTestBean {
public String method1(List<String> input) {
return input.get(0);
}
String method2(List<String> input) {
return input.get(0);
}
}
@SuppressWarnings("unused")
private static class MultiplePublicMethodTestBean {
public String upperCase(String s) {
return s.toUpperCase();
}
public String lowerCase(String s) {
return s.toLowerCase();
}
}
@SuppressWarnings("unused")
private static class NoPublicMethodTestBean {
String lowerCase(String s) {
return s.toLowerCase();
}
}
public interface GreetingService {
String sayHello(List<String> names);
}
public static class GreetingBean implements GreetingService {

View File

@@ -0,0 +1,287 @@
/*
* Copyright 2002-2008 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.aggregator;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.integration.Message;
import org.springframework.integration.core.GenericMessage;
import org.springframework.integration.store.MessageGroup;
import org.springframework.integration.store.SimpleMessageGroup;
/**
* @author Marius Bogoevici
* @author Dave Syer
*/
public class MethodInvokingReleaseStrategyTests {
@Test
public void testTrueConvertedProperly() {
MethodInvokingReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new AlwaysTrueReleaseStrategy(),
"checkCompleteness");
Assert.assertTrue(adapter.canRelease(createListOfMessages(0)));
}
@Test
public void testFalseConvertedProperly() {
MethodInvokingReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new AlwaysFalseReleaseStrategy(),
"checkCompleteness");
Assert.assertTrue(!adapter.canRelease(createListOfMessages(0)));
}
@Test
public void testAdapterWithNonParameterizedMessageListBasedMethod() {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public boolean checkCompletenessOnNonParameterizedListOfMessages(List<Message<?>> messages) {
Assert.assertTrue(messages.size() > 0);
return messages.size() > messages.iterator().next().getHeaders().getSequenceSize();
}
}
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new TestReleaseStrategy(),
"checkCompletenessOnNonParameterizedListOfMessages");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithWildcardParametrizedMessageBasedMethod() {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public boolean checkCompletenessOnListOfMessagesParametrizedWithWildcard(List<Message<?>> messages) {
Assert.assertTrue(messages.size() > 0);
return messages.size() > messages.iterator().next().getHeaders().getSequenceSize();
}
}
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new TestReleaseStrategy(),
"checkCompletenessOnListOfMessagesParametrizedWithWildcard");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithTypeParametrizedMessageBasedMethod() {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public boolean checkCompletenessOnListOfMessagesParametrizedWithString(List<Message<String>> messages) {
Assert.assertTrue(messages.size() > 0);
return messages.size() > messages.iterator().next().getHeaders().getSequenceSize();
}
}
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new TestReleaseStrategy(),
"checkCompletenessOnListOfMessagesParametrizedWithString");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithPojoBasedMethod() {
class TestReleaseStrategy {
@SuppressWarnings("unused")
// Example for the case when completeness is checked on the structure of
// the data
public boolean checkCompletenessOnListOfStrings(List<String> messages) {
StringBuffer buffer = new StringBuffer();
for (String content : messages) {
buffer.append(content);
}
return buffer.length() >= 9;
}
}
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new TestReleaseStrategy(),
"checkCompletenessOnListOfStrings");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithPojoBasedMethodReturningObject() {
class TestReleaseStrategy {
@SuppressWarnings("unused")
// Example for the case when completeness is checked on the structure of
// the data
public boolean checkCompletenessOnListOfStrings(List<String> messages) {
StringBuffer buffer = new StringBuffer();
for (String content : messages) {
buffer.append(content);
}
return buffer.length() >= 9;
}
}
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new TestReleaseStrategy(),
"checkCompletenessOnListOfStrings");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test(expected = IllegalArgumentException.class)
public void testAdapterWithWrongMethodName() {
class TestReleaseStrategy {
}
new MethodInvokingReleaseStrategy(new TestReleaseStrategy(), "methodThatDoesNotExist");
}
@Test(expected = IllegalStateException.class)
public void testInvalidParameterTypeUsingMethodName() {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public boolean invalidParameterType(Date invalid) {
return true;
}
}
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new TestReleaseStrategy(), "invalidParameterType");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test(expected = IllegalArgumentException.class)
public void testTooManyParametersUsingMethodName() {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public boolean tooManyParameters(List<?> c1, List<?> c2) {
return false;
}
}
new MethodInvokingReleaseStrategy(new TestReleaseStrategy(), "tooManyParameters");
}
@Test
public void testNotEnoughParametersUsingMethodName() {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public boolean notEnoughParameters() {
return false;
}
}
// TODO: this is stupid, but maybe it should be illegal?
new MethodInvokingReleaseStrategy(new TestReleaseStrategy(), "notEnoughParameters");
}
@Test
public void testNotEnoughParametersUsingMethodObject() throws SecurityException, NoSuchMethodException {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public boolean notEnoughParameters() {
return false;
}
}
// TODO: this is stupid, but maybe it should be illegal?
new MethodInvokingReleaseStrategy(new TestReleaseStrategy(), TestReleaseStrategy.class.getMethod(
"notEnoughParameters", new Class[] {}));
}
@Test
public void testListSubclassParameterUsingMethodName() {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public boolean listSubclassParameter(LinkedList<?> l1) {
return true;
}
}
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new TestReleaseStrategy(), "listSubclassParameter");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
// TODO: should this be MessageHandlingException?
@Test(expected = ConversionFailedException.class)
public void testWrongReturnType() throws SecurityException, NoSuchMethodError {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public String wrongReturnType(List<Message<?>> messages) {
return "foo";
}
}
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new TestReleaseStrategy(), "wrongReturnType");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test(expected = IllegalArgumentException.class)
public void testTooManyParametersUsingMethodObject() throws SecurityException, NoSuchMethodException {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public boolean tooManyParameters(List<?> c1, List<?> c2) {
return false;
}
}
new MethodInvokingReleaseStrategy(new TestReleaseStrategy(), TestReleaseStrategy.class.getMethod(
"tooManyParameters", List.class, List.class));
}
@Test
public void testListSubclassParameterUsingMethodObject() throws SecurityException, NoSuchMethodException {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public boolean listSubclassParameter(LinkedList<?> l1) {
return true;
}
}
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new TestReleaseStrategy(),
TestReleaseStrategy.class.getMethod("listSubclassParameter", new Class[] { LinkedList.class }));
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
// TODO: review exception type here
@Test(expected = IllegalStateException.class)
public void testWrongReturnTypeUsingMethodObject() throws SecurityException, NoSuchMethodException {
class TestReleaseStrategy {
@SuppressWarnings("unused")
public int wrongReturnType(List<Message<?>> message) {
return 0;
}
}
new MethodInvokingReleaseStrategy(new TestReleaseStrategy(), TestReleaseStrategy.class.getMethod(
"wrongReturnType", new Class[] { List.class }));
}
private static MessageGroup createListOfMessages(int size) {
List<Message<?>> messages = new ArrayList<Message<?>>();
if (size > 0) {
messages.add(new GenericMessage<String>("123"));
}
if (size > 1) {
messages.add(new GenericMessage<String>("456"));
}
if (size > 2) {
messages.add(new GenericMessage<String>("789"));
}
return new SimpleMessageGroup(messages, "ABC");
}
@SuppressWarnings("unused")
private static class AlwaysTrueReleaseStrategy {
public boolean checkCompleteness(List<Message<?>> messages) {
return true;
}
}
@SuppressWarnings("unused")
private static class AlwaysFalseReleaseStrategy {
public boolean checkCompleteness(List<Message<?>> messages) {
return false;
}
}
}

View File

@@ -1,226 +0,0 @@
/*
* Copyright 2002-2008 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.aggregator;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.integration.Message;
import org.springframework.integration.core.GenericMessage;
import org.springframework.integration.store.MessageGroup;
import org.springframework.integration.store.SimpleMessageGroup;
/**
* @author Marius Bogoevici
*/
public class ReleaseStrategyAdapterTests {
private SimpleReleaseStrategy simpleReleaseStrategy;
@Before
public void setUp() {
simpleReleaseStrategy = new SimpleReleaseStrategy();
}
@Test
public void testTrueConvertedProperly() {
MethodInvokingReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new AlwaysTrueReleaseStrategy(),
"checkCompleteness");
Assert.assertTrue(adapter.canRelease(createListOfMessages(0)));
}
@Test
public void testFalseConvertedProperly() {
MethodInvokingReleaseStrategy adapter = new MethodInvokingReleaseStrategy(new AlwaysFalseReleaseStrategy(),
"checkCompleteness");
Assert.assertTrue(!adapter.canRelease(createListOfMessages(0)));
}
@Test
public void testAdapterWithNonParameterizedMessageListBasedMethod() {
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(simpleReleaseStrategy,
"checkCompletenessOnNonParameterizedListOfMessages");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithWildcardParametrizedMessageBasedMethod() {
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(simpleReleaseStrategy,
"checkCompletenessOnListOfMessagesParametrizedWithWildcard");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithTypeParametrizedMessageBasedMethod() {
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(simpleReleaseStrategy,
"checkCompletenessOnListOfMessagesParametrizedWithString");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithPojoBasedMethod() {
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(simpleReleaseStrategy, "checkCompletenessOnListOfStrings");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test
public void testAdapterWithPojoBasedMethodReturningObject() {
ReleaseStrategy adapter = new MethodInvokingReleaseStrategy(simpleReleaseStrategy, "checkCompletenessOnListOfStrings");
MessageGroup messages = createListOfMessages(3);
Assert.assertTrue(adapter.canRelease(messages));
}
@Test(expected = IllegalArgumentException.class)
public void testAdapterWithWrongMethodName() {
new MethodInvokingReleaseStrategy(simpleReleaseStrategy, "methodThatDoesNotExist");
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidParameterTypeUsingMethodName() {
new MethodInvokingReleaseStrategy(simpleReleaseStrategy, "invalidParameterType");
}
@Test(expected = IllegalArgumentException.class)
public void testTooManyParametersUsingMethodName() {
new MethodInvokingReleaseStrategy(simpleReleaseStrategy, "tooManyParameters");
}
@Test(expected = IllegalArgumentException.class)
public void testNotEnoughParametersUsingMethodName() {
new MethodInvokingReleaseStrategy(simpleReleaseStrategy, "notEnoughParameters");
}
@Test(expected = IllegalArgumentException.class)
public void testListSubclassParameterUsingMethodName() {
new MethodInvokingReleaseStrategy(simpleReleaseStrategy, "ListSubclassParameter");
}
@Test(expected = IllegalArgumentException.class)
public void testWrongReturnType() throws SecurityException, NoSuchMethodError {
new MethodInvokingReleaseStrategy(simpleReleaseStrategy, "wrongReturnType");
}
@Test(expected = IllegalArgumentException.class)
public void testTooManyParametersUsingMethodObject() throws SecurityException, NoSuchMethodException {
new MethodInvokingReleaseStrategy(simpleReleaseStrategy, simpleReleaseStrategy.getClass().getMethod(
"tooManyParameters", List.class, List.class));
}
@Test(expected = IllegalArgumentException.class)
public void testNotEnoughParametersUsingMethodObject() throws SecurityException, NoSuchMethodException {
new MethodInvokingReleaseStrategy(simpleReleaseStrategy, simpleReleaseStrategy.getClass().getMethod(
"notEnoughParameters", new Class[] {}));
}
@Test(expected = IllegalArgumentException.class)
public void testListSubclassParameterUsingMethodObject() throws SecurityException, NoSuchMethodException {
new MethodInvokingReleaseStrategy(simpleReleaseStrategy, simpleReleaseStrategy.getClass().getMethod(
"ListSubclassParameter", new Class[] { LinkedList.class }));
}
@Test(expected = IllegalArgumentException.class)
public void testWrongReturnTypeUsingMethodObject() throws SecurityException, NoSuchMethodException {
new MethodInvokingReleaseStrategy(simpleReleaseStrategy, simpleReleaseStrategy.getClass().getMethod("wrongReturnType",
new Class[] { List.class }));
}
private static MessageGroup createListOfMessages(int size) {
List<Message<?>> messages = new ArrayList<Message<?>>();
if (size > 0) {
messages.add(new GenericMessage<String>("123"));
}
if (size > 1) {
messages.add(new GenericMessage<String>("456"));
}
if (size > 2) {
messages.add(new GenericMessage<String>("789"));
}
return new SimpleMessageGroup(messages, "ABC");
}
@SuppressWarnings("unused")
private static class AlwaysTrueReleaseStrategy {
public boolean checkCompleteness(List<Message<?>> messages) {
return true;
}
}
@SuppressWarnings("unused")
private static class AlwaysFalseReleaseStrategy {
public boolean checkCompleteness(List<Message<?>> messages) {
return false;
}
}
@SuppressWarnings("unused")
private static class SimpleReleaseStrategy {
public boolean checkCompletenessOnNonParameterizedListOfMessages(List<Message<?>> messages) {
Assert.assertTrue(messages.size() > 0);
return messages.size() > messages.iterator().next().getHeaders().getSequenceSize();
}
public boolean checkCompletenessOnListOfMessagesParametrizedWithWildcard(List<Message<?>> messages) {
Assert.assertTrue(messages.size() > 0);
return messages.size() > messages.iterator().next().getHeaders().getSequenceSize();
}
public boolean checkCompletenessOnListOfMessagesParametrizedWithString(List<Message<String>> messages) {
Assert.assertTrue(messages.size() > 0);
return messages.size() > messages.iterator().next().getHeaders().getSequenceSize();
}
// Example for the case when completeness is checked on the structure of
// the data
public boolean checkCompletenessOnListOfStrings(List<String> messages) {
StringBuffer buffer = new StringBuffer();
for (String content : messages) {
buffer.append(content);
}
return buffer.length() >= 9;
}
public String wrongReturnType(List<Message<?>> message) {
return "";
}
public boolean invalidParameterType(String invalid) {
return false;
}
public boolean tooManyParameters(List<?> c1, List<?> c2) {
return false;
}
public boolean notEnoughParameters() {
return false;
}
public boolean ListSubclassParameter(LinkedList<?> l1) {
return false;
}
}
}

View File

@@ -50,7 +50,7 @@ public class AggregatorIntegrationTests {
@Qualifier("output")
private PollableChannel output;
@Test(timeout=5000)
@Test//(timeout=5000)
public void testVanillaAggregation() throws Exception {
for (int i = 0; i < 5; i++) {
Map<String, Object> headers = stubHeaders(i, 5, 1);

View File

@@ -19,10 +19,11 @@ package org.springframework.integration.config;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Assert;
@@ -38,9 +39,8 @@ import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.MessageRejectedException;
import org.springframework.integration.aggregator.CorrelatingMessageHandler;
import org.springframework.integration.aggregator.CorrelationStrategy;
import org.springframework.integration.aggregator.MethodInvokingMessageListProcessor;
import org.springframework.integration.aggregator.ReleaseStrategy;
import org.springframework.integration.aggregator.MethodInvokingReleaseStrategy;
import org.springframework.integration.aggregator.ReleaseStrategy;
import org.springframework.integration.core.MessageBuilder;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageHandler;
@@ -48,7 +48,6 @@ import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.core.SubscribableChannel;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.util.MethodInvoker;
/**
* @author Marius Bogoevici
@@ -99,7 +98,8 @@ public class AggregatorParserTests {
for (Message<?> message : outboundMessages) {
input.send(message);
}
assertEquals("The aggregated message payload is not correct", "[123]", aggregatedMessage.get().getPayload().toString());
assertEquals("The aggregated message payload is not correct", "[123]", aggregatedMessage.get().getPayload()
.toString());
}
@Test
@@ -112,10 +112,14 @@ public class AggregatorParserTests {
Object consumer = new DirectFieldAccessor(endpoint).getPropertyValue("handler");
assertThat(consumer, is(CorrelatingMessageHandler.class));
DirectFieldAccessor accessor = new DirectFieldAccessor(consumer);
Method expectedMethod = TestAggregatorBean.class.getMethod("createSingleMessageFromGroup", List.class);
assertEquals("The MethodInvokingAggregator is not injected with the appropriate aggregation method",
expectedMethod, ((MethodInvokingMessageListProcessor) new DirectFieldAccessor(accessor
.getPropertyValue("outputProcessor")).getPropertyValue("adapter")).getMethod());
Map<?, ?> map = (Map<?, ?>) new DirectFieldAccessor(new DirectFieldAccessor(new DirectFieldAccessor(accessor
.getPropertyValue("outputProcessor")).getPropertyValue("processor")).getPropertyValue("delegate"))
.getPropertyValue("handlerMethods");
assertEquals("The MethodInvokingAggregator is not injected with the appropriate aggregation method", 1, map
.size());
assertEquals("The release strategy is not injected with the appropriate method", 1, map.size());
assertTrue("Handler methods do not contain correct method: " + map, map.toString().contains(
"createSingleMessageFromGroup"));
assertEquals("The AggregatorEndpoint is not injected with the appropriate ReleaseStrategy instance",
releaseStrategy, accessor.getPropertyValue("releaseStrategy"));
assertEquals("The AggregatorEndpoint is not injected with the appropriate CorrelationStrategy instance",
@@ -163,13 +167,12 @@ public class AggregatorParserTests {
ReleaseStrategy releaseStrategy = (ReleaseStrategy) new DirectFieldAccessor(new DirectFieldAccessor(endpoint)
.getPropertyValue("handler")).getPropertyValue("releaseStrategy");
Assert.assertTrue(releaseStrategy instanceof MethodInvokingReleaseStrategy);
DirectFieldAccessor releaseStrategyAccessor = new DirectFieldAccessor(new DirectFieldAccessor(releaseStrategy)
.getPropertyValue("adapter"));
MethodInvoker invoker = (MethodInvoker) releaseStrategyAccessor.getPropertyValue("invoker");
Assert
.assertTrue(new DirectFieldAccessor(invoker).getPropertyValue("object") instanceof MaxValueReleaseStrategy);
Assert.assertTrue(((Method) releaseStrategyAccessor.getPropertyValue("method")).getName().equals(
"checkCompleteness"));
DirectFieldAccessor releaseStrategyAccessor = new DirectFieldAccessor(new DirectFieldAccessor(new DirectFieldAccessor(releaseStrategy)
.getPropertyValue("adapter")).getPropertyValue("delegate"));
Map<?, ?> map = (Map<?, ?>) releaseStrategyAccessor.getPropertyValue("handlerMethods");
assertEquals("The release strategy is not injected with the appropriate method", 1, map.size());
assertTrue("Handler methods do not contain correct method: " + map, map.toString()
.contains("checkCompleteness"));
input.send(createMessage(1l, "correllationId", 4, 0, null));
input.send(createMessage(2l, "correllationId", 4, 1, null));
input.send(createMessage(3l, "correllationId", 4, 2, null));

View File

@@ -48,7 +48,9 @@ public class TestAggregatorBean {
}
}
Message<?> returnedMessage = new StringMessage(buffer.toString());
aggregatedMessages.put(correlationId, returnedMessage);
if (correlationId!=null) {
aggregatedMessages.put(correlationId, returnedMessage);
}
return returnedMessage;
}

View File

@@ -82,15 +82,16 @@ public class AggregatorAnnotationTests {
new String[] { "classpath:/org/springframework/integration/config/annotation/testAnnotatedAggregator.xml" });
final String endpointName = "endpointWithDefaultAnnotationAndCustomReleaseStrategy";
MessageHandler aggregator = this.getAggregator(context, endpointName);
Object ReleaseStrategy = getPropertyValue(aggregator, "releaseStrategy");
Assert.assertTrue(ReleaseStrategy instanceof MethodInvokingReleaseStrategy);
MethodInvokingReleaseStrategy releaseStrategyAdapter = (MethodInvokingReleaseStrategy) ReleaseStrategy;
DirectFieldAccessor invokerAccessor = new DirectFieldAccessor(new DirectFieldAccessor(new DirectFieldAccessor(
releaseStrategyAdapter).getPropertyValue("adapter")).getPropertyValue("invoker"));
Object targetObject = invokerAccessor.getPropertyValue("object");
assertSame(context.getBean(endpointName), targetObject);
Method completionCheckerMethod = (Method) invokerAccessor.getPropertyValue("method");
assertEquals("completionChecker", completionCheckerMethod.getName());
Object releaseStrategy = getPropertyValue(aggregator, "releaseStrategy");
Assert.assertTrue(releaseStrategy instanceof MethodInvokingReleaseStrategy);
MethodInvokingReleaseStrategy releaseStrategyAdapter = (MethodInvokingReleaseStrategy) releaseStrategy;
Map<?, ?> map = (Map<?, ?>) new DirectFieldAccessor(new DirectFieldAccessor(new DirectFieldAccessor(releaseStrategyAdapter)
.getPropertyValue("adapter")).getPropertyValue("delegate")).getPropertyValue("handlerMethods");
assertEquals("The MethodInvokingAggregator is not injected with the appropriate aggregation method", 1, map
.size());
assertEquals("The release strategy is not injected with the appropriate method", 1, map.size());
assertTrue("Handler methods do not contain correct method: " + map, map.toString()
.contains("completionChecker"));
}
@Test
@@ -101,9 +102,9 @@ public class AggregatorAnnotationTests {
MessageHandler aggregator = this.getAggregator(context, endpointName);
Object correlationStrategy = getPropertyValue(aggregator, "correlationStrategy");
Assert.assertTrue(correlationStrategy instanceof MethodInvokingCorrelationStrategy);
MethodInvokingCorrelationStrategy ReleaseStrategyAdapter = (MethodInvokingCorrelationStrategy) correlationStrategy;
DirectFieldAccessor processorAccessor = new DirectFieldAccessor(new DirectFieldAccessor(ReleaseStrategyAdapter)
.getPropertyValue("processor"));
MethodInvokingCorrelationStrategy releaseStrategyAdapter = (MethodInvokingCorrelationStrategy) correlationStrategy;
DirectFieldAccessor processorAccessor = new DirectFieldAccessor(new DirectFieldAccessor(new DirectFieldAccessor(releaseStrategyAdapter)
.getPropertyValue("processor")).getPropertyValue("delegate"));
Object targetObject = processorAccessor.getPropertyValue("targetObject");
assertSame(context.getBean(endpointName), targetObject);
Map<?, ?> handlerMethods = (Map<?, ?>) processorAccessor.getPropertyValue("handlerMethods");

View File

@@ -85,7 +85,7 @@ public class PNamespaceTests {
private TestBean prepare(EventDrivenConsumer edc) {
return TestUtils.getPropertyValue(serviceActivator,
"handler.processor.targetObject", TestBean.class);
"handler.processor.delegate.targetObject", TestBean.class);
}

View File

@@ -27,6 +27,7 @@ import org.junit.internal.matchers.TypeSafeMatcher;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.expression.EvaluationException;
@@ -55,6 +56,12 @@ public class ExpressionEvaluatingMessageProcessorTests {
@Test
public void testProcessMessageWithParameterCoercion() {
@SuppressWarnings("unused")
class TestTarget {
public String stringify(int number) {
return number+"";
}
}
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("#target.stringify(payload)");
processor.getEvaluationContext().setVariable("target", new TestTarget());
assertEquals("2", processor.processMessage(new StringMessage("2")));
@@ -62,6 +69,11 @@ public class ExpressionEvaluatingMessageProcessorTests {
@Test
public void testProcessMessageWithVoidResult() {
@SuppressWarnings("unused")
class TestTarget {
public void ping(String input) {
}
}
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("#target.ping(payload)");
processor.getEvaluationContext().setVariable("target", new TestTarget());
assertEquals(null, processor.processMessage(new StringMessage("2")));
@@ -69,7 +81,15 @@ public class ExpressionEvaluatingMessageProcessorTests {
@Test
public void testProcessMessageWithParameterCoercionToNonPrimitive() {
class TestTarget {
@SuppressWarnings("unused")
public String find(Resource[] resources) {
return Arrays.asList(resources).toString();
}
}
ExpressionEvaluatingMessageProcessor processor = new ExpressionEvaluatingMessageProcessor("#target.find(payload)");
processor.setBeanFactory(new GenericApplicationContext().getBeanFactory());
processor.getEvaluationContext().setVariable("target", new TestTarget());
String result = (String) processor.processMessage(new StringMessage("classpath:*.properties"));
assertTrue("Wrong result: "+result, result.contains("log4j.properties"));
@@ -187,23 +207,6 @@ public class ExpressionEvaluatingMessageProcessorTests {
}
}
@SuppressWarnings("unused")
private static class TestTarget {
public String stringify(int number) {
return number+"";
}
public String find(Resource[] resources) {
return Arrays.asList(resources).toString();
}
public void ping(String input) {
}
}
@SuppressWarnings("serial")
private static final class CheckedException extends Exception {
public CheckedException(String string) {

View File

@@ -49,7 +49,7 @@ import org.springframework.integration.core.StringMessage;
public class MethodInvokingMessageProcessorTests {
private static final Log logger = LogFactory.getLog(MethodInvokingMessageProcessorTests.class);
@Rule
public ExpectedException expected = ExpectedException.none();
@@ -58,14 +58,16 @@ public class MethodInvokingMessageProcessorTests {
class A {
@SuppressWarnings("unused")
public Message<String> myMethod(final Message<String> msg) {
return MessageBuilder.fromMessage(msg).setHeader("A", "A").build();
}
return MessageBuilder.fromMessage(msg).setHeader("A", "A").build();
}
}
class B extends A {}
class B extends A {
}
@SuppressWarnings("unused")
class C extends B {}
class C extends B {
}
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new B(), "myMethod");
Message<?> message = (Message<?>) processor.processMessage(new StringMessage(""));
@@ -77,18 +79,19 @@ public class MethodInvokingMessageProcessorTests {
class A {
@SuppressWarnings("unused")
public Message<String> myMethod(Message<String> msg) {
return MessageBuilder.fromMessage(msg).setHeader("A", "A").build();
}
return MessageBuilder.fromMessage(msg).setHeader("A", "A").build();
}
}
class B extends A {
public Message<String> myMethod(Message<String> msg) {
return MessageBuilder.fromMessage(msg).setHeader("B", "B").build();
}
return MessageBuilder.fromMessage(msg).setHeader("B", "B").build();
}
}
@SuppressWarnings("unused")
class C extends B {}
class C extends B {
}
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new B(), "myMethod");
Message<?> message = (Message<?>) processor.processMessage(new StringMessage(""));
@@ -99,20 +102,20 @@ public class MethodInvokingMessageProcessorTests {
class A {
@SuppressWarnings("unused")
public Message<String> myMethod(Message<String> msg) {
return MessageBuilder.fromMessage(msg).setHeader("A", "A").build();
}
return MessageBuilder.fromMessage(msg).setHeader("A", "A").build();
}
}
class B extends A {
public Message<String> myMethod(Message<String> msg) {
return MessageBuilder.fromMessage(msg).setHeader("B", "B").build();
}
return MessageBuilder.fromMessage(msg).setHeader("B", "B").build();
}
}
class C extends B {
public Message<String> myMethod(Message<String> msg) {
return MessageBuilder.fromMessage(msg).setHeader("C", "C").build();
}
return MessageBuilder.fromMessage(msg).setHeader("C", "C").build();
}
}
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new C(), "myMethod");
@@ -123,17 +126,18 @@ public class MethodInvokingMessageProcessorTests {
public void testHandlerInheritanceMethodImplInSubClassAndSuper() {
class A {
@SuppressWarnings("unused")
public Message<String> myMethod(Message<String> msg){
return MessageBuilder.fromMessage(msg).setHeader("A", "A").build();
}
public Message<String> myMethod(Message<String> msg) {
return MessageBuilder.fromMessage(msg).setHeader("A", "A").build();
}
}
class B extends A {}
class B extends A {
}
class C extends B {
public Message<String> myMethod(Message<String> msg) {
return MessageBuilder.fromMessage(msg).setHeader("C", "C").build();
}
return MessageBuilder.fromMessage(msg).setHeader("C", "C").build();
}
}
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new C(), "myMethod");
@@ -143,92 +147,102 @@ public class MethodInvokingMessageProcessorTests {
@Test
public void payloadAsMethodParameterAndObjectAsReturnValue() {
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(
new TestBean(), "acceptPayloadAndReturnObject");
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(),
"acceptPayloadAndReturnObject");
Object result = processor.processMessage(new StringMessage("testing"));
assertEquals("testing-1", result);
}
@Test
public void testPayloadCoercedToString() {
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(
new TestBean(), "acceptPayloadAndReturnObject");
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(),
"acceptPayloadAndReturnObject");
Object result = processor.processMessage(new GenericMessage<Integer>(123456789));
assertEquals("123456789-1", result);
}
@Test
public void payloadAsMethodParameterAndMessageAsReturnValue() {
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(
new TestBean(), "acceptPayloadAndReturnMessage");
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(),
"acceptPayloadAndReturnMessage");
Message<?> result = (Message<?>) processor.processMessage(new StringMessage("testing"));
assertEquals("testing-2", result.getPayload());
}
@Test
public void messageAsMethodParameterAndObjectAsReturnValue() {
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(
new TestBean(), "acceptMessageAndReturnObject");
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(),
"acceptMessageAndReturnObject");
Object result = processor.processMessage(new StringMessage("testing"));
assertEquals("testing-3", result);
}
@Test
public void messageAsMethodParameterAndMessageAsReturnValue() {
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(
new TestBean(), "acceptMessageAndReturnMessage");
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(),
"acceptMessageAndReturnMessage");
Message<?> result = (Message<?>) processor.processMessage(new StringMessage("testing"));
assertEquals("testing-4", result.getPayload());
}
@Test
public void messageSubclassAsMethodParameterAndMessageAsReturnValue() {
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(
new TestBean(), "acceptMessageSubclassAndReturnMessage");
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(),
"acceptMessageSubclassAndReturnMessage");
Message<?> result = (Message<?>) processor.processMessage(new StringMessage("testing"));
assertEquals("testing-5", result.getPayload());
}
@Test
public void messageSubclassAsMethodParameterAndMessageSubclassAsReturnValue() {
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(
new TestBean(), "acceptMessageSubclassAndReturnMessageSubclass");
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(),
"acceptMessageSubclassAndReturnMessageSubclass");
Message<?> result = (Message<?>) processor.processMessage(new StringMessage("testing"));
assertEquals("testing-6", result.getPayload());
}
@Test
public void payloadAndHeaderAnnotationMethodParametersAndObjectAsReturnValue() {
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(
new TestBean(), "acceptPayloadAndHeaderAndReturnObject");
Message<?> request = MessageBuilder.withPayload("testing")
.setHeader("number", new Integer(123)).build();
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(),
"acceptPayloadAndHeaderAndReturnObject");
Message<?> request = MessageBuilder.withPayload("testing").setHeader("number", new Integer(123)).build();
Object result = processor.processMessage(request);
assertEquals("testing-123", result);
}
@Test
public void testVoidMethodsIncludedbyDefault() {
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(), "testVoidReturningMethods");
assertNull(processor.processMessage(MessageBuilder.withPayload("Something").build()));
assertEquals(12, processor.processMessage(MessageBuilder.withPayload(12).build()));
}
@Test
public void testVoidMethodsIncludedbyDefault() {
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(),
"testVoidReturningMethods");
assertNull(processor.processMessage(MessageBuilder.withPayload("Something").build()));
assertEquals(12, processor.processMessage(MessageBuilder.withPayload(12).build()));
}
@Test
public void testVoidMethodsExcludedByFlag() {
Exception exception = null;
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new TestBean(), "testVoidReturningMethods", true);
assertEquals(12, processor.processMessage(MessageBuilder.withPayload(12).build()));
try {
processor.processMessage(MessageBuilder.withPayload("not_a_number").build());
fail();
}
catch(MessageHandlingException ex) {
// the only void method expects a number
exception = ex;
}
assertNotNull(exception);
}
@Test
public void testVoidMethodsExcludedByFlag() {
@SuppressWarnings("unused")
class VoidMethodsBean {
public void testVoidReturningMethods(String s) {
// do nothing
}
public int testVoidReturningMethods(int i) {
return i;
}
}
Exception exception = null;
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(new VoidMethodsBean(),
"testVoidReturningMethods", true);
assertEquals(12, processor.processMessage(MessageBuilder.withPayload(12).build()));
try {
processor.processMessage(MessageBuilder.withPayload("not_a_number").build());
fail();
}
catch (MessageHandlingException ex) {
// the only void method expects a number
exception = ex;
}
assertNotNull(exception);
}
@Test
public void messageOnlyWithAnnotatedMethod() throws Exception {
@@ -267,6 +281,7 @@ public class MethodInvokingMessageProcessorTests {
@Test
public void testProcessMessageBadExpression() throws Exception {
// TODO: should this be MessageHandlingException or NumberFormatException?
expected.expect(new ExceptionCauseMatcher(NumberFormatException.class));
AnnotatedTestService service = new AnnotatedTestService();
Method method = service.getClass().getMethod("integerMethod", Integer.class);
@@ -297,8 +312,7 @@ public class MethodInvokingMessageProcessorTests {
AnnotatedTestService service = new AnnotatedTestService();
Method method = service.getClass().getMethod("messageAndHeader", Message.class, Integer.class);
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(service, method);
Message<String> message = MessageBuilder.withPayload("foo")
.setHeader("number", 42).build();
Message<String> message = MessageBuilder.withPayload("foo").setHeader("number", 42).build();
Object result = processor.processMessage(message);
assertEquals("foo-42", result);
}
@@ -308,9 +322,8 @@ public class MethodInvokingMessageProcessorTests {
AnnotatedTestService service = new AnnotatedTestService();
Method method = service.getClass().getMethod("twoHeaders", String.class, Integer.class);
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(service, method);
Message<String> message = MessageBuilder.withPayload("foo")
.setHeader("prop", "bar")
.setHeader("number", 42).build();
Message<String> message = MessageBuilder.withPayload("foo").setHeader("prop", "bar").setHeader("number", 42)
.build();
Object result = processor.processMessage(message);
assertEquals("bar-42", result);
}
@@ -334,7 +347,7 @@ public class MethodInvokingMessageProcessorTests {
assertEquals(String.class, bean.lastArg.getClass());
assertEquals("true", bean.lastArg);
}
@Test
public void testOverloadedNonVoidReturningMethodsWithExactMatchForType() {
AmbiguousMethodBean bean = new AmbiguousMethodBean();
@@ -344,20 +357,24 @@ public class MethodInvokingMessageProcessorTests {
assertEquals(String.class, bean.lastArg.getClass());
assertEquals("true", bean.lastArg);
}
private static class ExceptionCauseMatcher extends TypeSafeMatcher<Exception> {
private Throwable cause;
private Class<? extends Exception> type;
public ExceptionCauseMatcher(Class<? extends Exception> type) {
this.type = type;
}
@Override
public boolean matchesSafely(Exception item) {
logger.debug(item);
cause = item.getCause();
assertNotNull("There is no cause for "+item, cause);
assertNotNull("There is no cause for " + item, cause);
return type.isAssignableFrom(cause.getClass());
}
public void describeTo(Description description) {
description.appendText("cause to be ").appendValue(type).appendText("but was ").appendValue(cause);
}
@@ -368,11 +385,12 @@ public class MethodInvokingMessageProcessorTests {
public String error(String input) {
throw new UnsupportedOperationException("Expected test exception");
}
public String checked(String input) throws Exception {
throw new CheckedException("Expected test exception");
}
}
@SuppressWarnings("serial")
public static final class CheckedException extends Exception {
public CheckedException(String string) {
@@ -411,17 +429,16 @@ public class MethodInvokingMessageProcessorTests {
return s + "-" + n;
}
public void testVoidReturningMethods(String s) {
// do nothing
}
public void testVoidReturningMethods(String s) {
// do nothing
}
public int testVoidReturningMethods(int i) {
return i;
}
public int testVoidReturningMethods(int i) {
return i;
}
}
@SuppressWarnings("unused")
private static class AnnotatedTestService {
@@ -437,15 +454,16 @@ public class MethodInvokingMessageProcessorTests {
return prop + "-" + num.toString();
}
public Integer optionalHeader(@Header(required=false) Integer num) {
public Integer optionalHeader(@Header(required = false) Integer num) {
return num;
}
public Integer requiredHeader(@Header(value="num", required=true) Integer num) {
public Integer requiredHeader(@Header(value = "num", required = true) Integer num) {
return num;
}
public String optionalAndRequiredHeader(@Header(required=false) String prop, @Header(value="num", required=true) Integer num) {
public String optionalAndRequiredHeader(@Header(required = false) String prop,
@Header(value = "num", required = true) Integer num) {
return prop + num;
}
@@ -464,10 +482,9 @@ public class MethodInvokingMessageProcessorTests {
}
/**
* Method names create ambiguities, but the MethodResolver implementation
* should filter out based on the annotation or the 'requiresReply' flag.
* Method names create ambiguities, but the MethodResolver implementation should filter out based on the annotation
* or the 'requiresReply' flag.
*/
@SuppressWarnings("unused")
private static class AmbiguousMethodBean {
@@ -491,8 +508,8 @@ public class MethodInvokingMessageProcessorTests {
}
/**
* Method names create ambiguities, but the MethodResolver implementation
* should filter out based on the annotation or the 'requiresReply' flag.
* Method names create ambiguities, but the MethodResolver implementation should filter out based on the annotation
* or the 'requiresReply' flag.
*/
@SuppressWarnings("unused")
private static class OverloadedMethodBean {