From d77785c418a1c295236079efb87bce4905d0f172 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Wed, 5 May 2010 16:24:08 +0000 Subject: [PATCH] INT-1011 Added 'overwrite' attribute for individual header sub-elements and renamed the top-level attribute to 'default-overwrite' (top level is a fallback if the sub-element does not provide a value). --- .../xml/HeaderEnricherParserSupport.java | 40 ++- .../transformer/HeaderEnricher.java | 77 +++-- .../config/xml/spring-integration-2.0.xsd | 33 +- .../HeaderEnricherOverwriteTests-context.xml | 106 ++++++ .../xml/HeaderEnricherOverwriteTests.java | 311 ++++++++++++++++++ 5 files changed, 528 insertions(+), 39 deletions(-) create mode 100644 org.springframework.integration/src/test/java/org/springframework/integration/config/xml/HeaderEnricherOverwriteTests-context.xml create mode 100644 org.springframework.integration/src/test/java/org/springframework/integration/config/xml/HeaderEnricherOverwriteTests.java diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/HeaderEnricherParserSupport.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/HeaderEnricherParserSupport.java index fef9c98037..7e3f8e95b3 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/HeaderEnricherParserSupport.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/HeaderEnricherParserSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -23,7 +23,6 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedMap; @@ -49,10 +48,6 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar return IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher"; } - protected boolean shouldOverwrite(Element element) { - return "true".equals(element.getAttribute("overwrite").toLowerCase()); - } - protected final void addElementToHeaderMapping(String elementName, String headerName) { this.addElementToHeaderMapping(elementName, headerName, null); } @@ -70,7 +65,7 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar ManagedMap headers = new ManagedMap(); this.processHeaders(element, headers, parserContext); builder.addConstructorArgValue(headers); - builder.addPropertyValue("overwrite", this.shouldOverwrite(element)); // TODO: should be a per-header config setting + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-overwrite"); } protected void processHeaders(Element element, ManagedMap headers, ParserContext parserContext) { @@ -123,25 +118,28 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar parserContext.getReaderContext().error( "Exactly one of the 'ref', 'value', or 'expression' attributes is required.", element); } + Object headerSource = parserContext.extractSource(headerElement); + BeanDefinitionBuilder valueHolderBuilder = null; if (isValue) { if (hasMethod) { parserContext.getReaderContext().error( "The 'method' attribute cannot be used with the 'value' attribute.", element); } Object headerValue = (headerType != null) ? - new TypedStringValue(value, headerType) : value; - headers.put(headerName, headerValue); + new TypedStringValue(value, headerType) : value; + valueHolderBuilder = BeanDefinitionBuilder.genericBeanDefinition( + IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$StaticValueHolder"); + valueHolderBuilder.addConstructorArgValue(headerValue); } else if (isExpression) { if (hasMethod) { parserContext.getReaderContext().error( "The 'method' attribute cannot be used with the 'expression' attribute.", element); } - BeanDefinitionBuilder expressionBuilder = BeanDefinitionBuilder.genericBeanDefinition( + valueHolderBuilder = BeanDefinitionBuilder.genericBeanDefinition( IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$ExpressionHolder"); - expressionBuilder.addConstructorArgValue(expression); - expressionBuilder.addConstructorArgValue(headerType); - headers.put(headerName, expressionBuilder.getBeanDefinition()); + valueHolderBuilder.addConstructorArgValue(expression); + valueHolderBuilder.addConstructorArgValue(headerType); } else { if (StringUtils.hasText(headerElement.getAttribute("type"))) { @@ -149,16 +147,22 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar "The 'type' attribute cannot be used with the 'ref' attribute.", element); } if (hasMethod) { - BeanDefinitionBuilder methodExpressionBuilder = BeanDefinitionBuilder.genericBeanDefinition( + valueHolderBuilder = BeanDefinitionBuilder.genericBeanDefinition( IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$MethodExpressionHolder"); - methodExpressionBuilder.addConstructorArgReference(ref); - methodExpressionBuilder.addConstructorArgValue(method); - headers.put(headerName, methodExpressionBuilder.getBeanDefinition()); + valueHolderBuilder.addConstructorArgReference(ref); + valueHolderBuilder.addConstructorArgValue(method); } else { - headers.put(headerName, new RuntimeBeanReference(ref)); + valueHolderBuilder = BeanDefinitionBuilder.genericBeanDefinition( + IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$StaticValueHolder"); + valueHolderBuilder.addConstructorArgReference(ref); } } + if (valueHolderBuilder == null) { + parserContext.getReaderContext().error("failed to parse header sub-element", headerSource); + } + IntegrationNamespaceUtils.setValueIfAttributeDefined(valueHolderBuilder, headerElement, "overwrite"); + headers.put(headerName, valueHolderBuilder.getBeanDefinition()); } } } diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/transformer/HeaderEnricher.java b/org.springframework.integration/src/main/java/org/springframework/integration/transformer/HeaderEnricher.java index 62d17b41bf..9a590a31ea 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/transformer/HeaderEnricher.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/transformer/HeaderEnricher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -43,38 +43,36 @@ import org.springframework.util.Assert; */ public class HeaderEnricher implements Transformer { - private final Map headersToAdd; + private final Map headersToAdd; - private volatile boolean overwrite; + private volatile boolean defaultOverwrite = false; /** * Create a HeaderEnricher with the given map of headers. */ - public HeaderEnricher(Map headersToAdd) { + public HeaderEnricher(Map headersToAdd) { Assert.notNull(headersToAdd, "headersToAdd must not be null"); this.headersToAdd = headersToAdd; } - public void setOverwrite(boolean overwrite) { - this.overwrite = overwrite; + public void setDefaultOverwrite(boolean defaultOverwrite) { + this.defaultOverwrite = defaultOverwrite; } public Message transform(Message message) { try { Map headerMap = new HashMap(message.getHeaders()); - for (Map.Entry entry : this.headersToAdd.entrySet()) { + for (Map.Entry entry : this.headersToAdd.entrySet()) { String key = entry.getKey(); - if (this.overwrite || headerMap.get(key) == null) { - Object value = entry.getValue(); - if (value instanceof ExpressionHolder) { - value = ((ExpressionHolder) value).evaluate(message); - } - else if (value instanceof MethodExpressionHolder) { - value = ((MethodExpressionHolder) value).evaluate(message); - } - headerMap.put(key, value); + ValueHolder valueHolder = entry.getValue(); + Boolean shouldOverwrite = valueHolder.isOverwrite(); + if (shouldOverwrite == null) { + shouldOverwrite = this.defaultOverwrite; + } + if (shouldOverwrite || headerMap.get(key) == null) { + headerMap.put(key, valueHolder.evaluate(message)); } } return MessageBuilder.withPayload(message.getPayload()).copyHeaders(headerMap).build(); @@ -85,7 +83,46 @@ public class HeaderEnricher implements Transformer { } - static class ExpressionHolder { + public static interface ValueHolder { + + Object evaluate(Message message); + + Boolean isOverwrite(); + + } + + + static abstract class AbstractValueHolder implements ValueHolder { + + // null indicates no explicit setting; use header-enricher's 'default-overwrite' value + private volatile Boolean overwrite = null; + + public void setOverwrite(Boolean overwrite) { + this.overwrite = overwrite; + } + + public Boolean isOverwrite() { + return this.overwrite; + } + + } + + + static class StaticValueHolder extends AbstractValueHolder { + + private final Object value; + + public StaticValueHolder(Object value) { + this.value = value; + } + + public Object evaluate(Message message) { + return this.value; + } + } + + + static class ExpressionHolder extends AbstractValueHolder { private static final ExpressionParser parser = new SpelExpressionParser(); @@ -109,7 +146,7 @@ public class HeaderEnricher implements Transformer { } - private Object evaluate(Message message) throws ParseException, EvaluationException { + public Object evaluate(Message message) throws ParseException, EvaluationException { return (this.expectedType != null) ? this.expression.getValue(this.evaluationContext, message, this.expectedType) : this.expression.getValue(this.evaluationContext, message); @@ -117,7 +154,7 @@ public class HeaderEnricher implements Transformer { } - static class MethodExpressionHolder { + static class MethodExpressionHolder extends AbstractValueHolder { private final MethodInvokingMessageProcessor processor; @@ -125,7 +162,7 @@ public class HeaderEnricher implements Transformer { this.processor = new MethodInvokingMessageProcessor(targetObject, method); } - private Object evaluate(Message message) { + public Object evaluate(Message message) { return this.processor.processMessage(message); } } diff --git a/org.springframework.integration/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd b/org.springframework.integration/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd index fe61961acb..b485099ce6 100644 --- a/org.springframework.integration/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd +++ b/org.springframework.integration/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd @@ -1185,6 +1185,16 @@ + + + + Boolean value to indicate whether this header value should overwrite an existing header value for the same name. + + + + + + @@ -1196,7 +1206,18 @@ - + + + + Specify the default boolean value for whether to overwrite existing header values. This will only take effect for + sub-elements that do not provide their own 'overwrite' attribute. If the 'default-overwrite' attribute is not + provided, then the specified header values will NOT overwrite any existing ones with the same header names. + + + + + + @@ -1291,6 +1312,16 @@ + + + + Boolean value to indicate whether this header value should overwrite an existing header value for the same name. + + + + + + diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/HeaderEnricherOverwriteTests-context.xml b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/HeaderEnricherOverwriteTests-context.xml new file mode 100644 index 0000000000..2cb93859bb --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/HeaderEnricherOverwriteTests-context.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + + + diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/HeaderEnricherOverwriteTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/HeaderEnricherOverwriteTests.java new file mode 100644 index 0000000000..c56f56f2d5 --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/HeaderEnricherOverwriteTests.java @@ -0,0 +1,311 @@ +/* + * Copyright 2002-2010 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.config.xml; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.integration.channel.PollableChannel; +import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.core.Message; +import org.springframework.integration.core.MessageChannel; +import org.springframework.integration.core.MessagePriority; +import org.springframework.integration.gateway.SimpleMessagingGateway; +import org.springframework.integration.message.MessageBuilder; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Mark Fisher + * @since 2.0 + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class HeaderEnricherOverwriteTests { + + @Autowired + private ApplicationContext context; + + + @Test + public void replyChannelExplicitOverwriteTrue() { + MessageChannel inputChannel = context.getBean("replyChannelExplicitOverwriteTrueInput", MessageChannel.class); + PollableChannel replyChannel = context.getBean("replyChannelExplicitOverwriteTrueOutput", PollableChannel.class); + QueueChannel replyChannelToOverwrite = new QueueChannel(); + Message message = MessageBuilder.withPayload("test").setReplyChannel(replyChannelToOverwrite).build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals(replyChannel, result.getHeaders().getReplyChannel()); + assertNull(replyChannelToOverwrite.receive(0)); + } + + @Test + public void replyChannelExplicitOverwriteFalse() { + MessageChannel inputChannel = context.getBean("replyChannelExplicitOverwriteFalseInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test").setReplyChannel(replyChannel).build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals(replyChannel, result.getHeaders().getReplyChannel()); + } + + @Test + public void replyChannelExplicitOverwriteFalseButNoExistingHeader() { + MessageChannel inputChannel = context.getBean( + "replyChannelExplicitOverwriteFalseButNoExistingHeaderInput", MessageChannel.class); + PollableChannel replyChannel = context.getBean( + "replyChannelExplicitOverwriteFalseButNoExistingHeaderOutput", PollableChannel.class); + Message message = MessageBuilder.withPayload("test").build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals(replyChannel, result.getHeaders().getReplyChannel()); + } + + @Test + public void replyChannelDefaultOverwriteTrue() { + MessageChannel inputChannel = context.getBean("replyChannelDefaultOverwriteTrueInput", MessageChannel.class); + PollableChannel replyChannel = context.getBean("replyChannelDefaultOverwriteTrueOutput", PollableChannel.class); + QueueChannel replyChannelToOverwrite = new QueueChannel(); + Message message = MessageBuilder.withPayload("test").setReplyChannel(replyChannelToOverwrite).build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals(replyChannel, result.getHeaders().getReplyChannel()); + assertNull(replyChannelToOverwrite.receive(0)); + } + + @Test + public void replyChannelDefaultOverwriteFalse() { + MessageChannel inputChannel = context.getBean("replyChannelDefaultOverwriteFalseInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test").setReplyChannel(replyChannel).build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals(replyChannel, result.getHeaders().getReplyChannel()); + } + + @Test + public void replyChannelDefaultOverwriteTrueButExplicitOverwriteFalse() { + MessageChannel inputChannel = context.getBean("replyChannelDefaultOverwriteTrueButExplicitOverwriteFalseInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test").setReplyChannel(replyChannel).build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals(replyChannel, result.getHeaders().getReplyChannel()); + } + + @Test + public void replyChannelDefaultOverwriteFalseButNoExistingHeader() { + MessageChannel inputChannel = context.getBean( + "replyChannelDefaultOverwriteFalseButNoExistingHeaderInput", MessageChannel.class); + PollableChannel replyChannel = context.getBean( + "replyChannelDefaultOverwriteFalseButNoExistingHeaderOutput", PollableChannel.class); + Message message = MessageBuilder.withPayload("test").build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals(replyChannel, result.getHeaders().getReplyChannel()); + } + + @Test + public void priorityExplicitOverwriteTrue() { + SimpleMessagingGateway gateway = new SimpleMessagingGateway(); + gateway.setRequestChannel(context.getBean("priorityExplicitOverwriteTrueInput", MessageChannel.class)); + Message result = gateway.sendAndReceiveMessage("test"); + assertNotNull(result); + assertEquals(MessagePriority.HIGH, result.getHeaders().getPriority()); + } + + @Test + public void priorityExplicitOverwriteFalse() { + MessageChannel input = context.getBean("priorityExplicitOverwriteFalseInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test") + .setReplyChannel(replyChannel) + .setPriority(MessagePriority.HIGHEST) + .build(); + input.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals(MessagePriority.HIGHEST, result.getHeaders().getPriority()); + } + + @Test + public void customExplicitOverwriteTrue() { + MessageChannel inputChannel = context.getBean("customExplicitOverwriteTrueInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test") + .setReplyChannel(replyChannel) + .setHeader("foo", "bar") + .build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals("zzz", result.getHeaders().get("foo")); + } + + @Test + public void customExplicitOverwriteFalse() { + MessageChannel inputChannel = context.getBean("customExplicitOverwriteFalseInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test") + .setReplyChannel(replyChannel) + .setHeader("foo", "bar") + .build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals("bar", result.getHeaders().get("foo")); + } + + @Test + public void customExplicitOverwriteFalseButNoExistingHeader() { + MessageChannel inputChannel = context.getBean("customExplicitOverwriteFalseButNoExistingHeaderInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test") + .setReplyChannel(replyChannel) + .build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals("zzz", result.getHeaders().get("foo")); + } + + @Test + public void expressionExplicitOverwriteTrue() { + MessageChannel inputChannel = context.getBean("expressionExplicitOverwriteTrueInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test") + .setReplyChannel(replyChannel) + .setHeader("foo", "bar") + .build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals("123", result.getHeaders().get("foo")); + } + + @Test + public void expressionExplicitOverwriteFalse() { + MessageChannel inputChannel = context.getBean("expressionExplicitOverwriteFalseInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test") + .setReplyChannel(replyChannel) + .setHeader("foo", "bar") + .build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals("bar", result.getHeaders().get("foo")); + } + + @Test + public void expressionExplicitOverwriteFalseButNoExistingHeader() { + MessageChannel inputChannel = context.getBean("expressionExplicitOverwriteFalseButNoExistingHeaderInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test") + .setReplyChannel(replyChannel) + .build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals("123", result.getHeaders().get("foo")); + } + + @Test + public void beanExplicitOverwriteTrue() { + MessageChannel inputChannel = context.getBean("beanExplicitOverwriteTrueInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test") + .setReplyChannel(replyChannel) + .setHeader("foo", "bar") + .build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals("ABC", result.getHeaders().get("foo")); + } + + @Test + public void beanExplicitOverwriteFalse() { + MessageChannel inputChannel = context.getBean("beanExplicitOverwriteFalseInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test") + .setReplyChannel(replyChannel) + .setHeader("foo", "bar") + .build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals("bar", result.getHeaders().get("foo")); + } + + @Test + public void beanExplicitOverwriteFalseButNoExistingHeader() { + MessageChannel inputChannel = context.getBean("beanExplicitOverwriteFalseButNoExistingHeaderInput", MessageChannel.class); + QueueChannel replyChannel = new QueueChannel(); + Message message = MessageBuilder.withPayload("test") + .setReplyChannel(replyChannel) + .build(); + inputChannel.send(message); + Message result = replyChannel.receive(0); + assertNotNull(result); + assertEquals("TEST", result.getPayload()); + assertEquals("ABC", result.getHeaders().get("foo")); + } + + + public static class TestBean { + + private final String text; + + public TestBean(String text) { + this.text = text; + } + + public String text() { + return this.text; + } + } + +}