diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/AnnotationMethodMessageMapper.java b/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/AnnotationMethodMessageMapper.java
index 5eaf72d517..b1a0bfb917 100644
--- a/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/AnnotationMethodMessageMapper.java
+++ b/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/AnnotationMethodMessageMapper.java
@@ -24,7 +24,6 @@ import org.springframework.core.GenericTypeResolver;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
-import org.springframework.integration.ConfigurationException;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageHandlingException;
import org.springframework.integration.message.MessageHeaders;
@@ -35,17 +34,16 @@ import org.springframework.util.StringUtils;
/**
* A {@link MessageMapper} implementation for annotated handler methods.
* Method parameters are matched against the Message payload as well as its
- * header attributes and properties. If a method parameter is annotated with
- * {@link HeaderAttribute @HeaderAttribute} or {@link HeaderProperty @HeaderProperty},
- * the annotation's value will be used as an attribute/property key. If such an
- * annotation contains no value, then the parameter name will be used as long as
+ * headers. If a method parameter is annotated with {@link Header @Header},
+ * the annotation's value will be used as a header name. If such an annotation
+ * contains no value, then the parameter name will be used as long as
* the information is available in the class file (requires compilation with
* debug settings for parameter names). If neither annotation is present, then
* the parameter will typically match the Message payload. However, if a Map or
* Properties object is expected, and the paylaod is not itself assignable to
- * that type, then the MessageHeader attributes will be passed in the case of
- * a Map-typed parameter, or the MessageHeader properties will be passed in the
- * case of a Properties-typed parameter.
+ * that type, then the MessageHeaders' values will be passed in the case of
+ * a Map-typed parameter, or the MessageHeaders' String-based values will be
+ * passed in the case of a Properties-typed parameter.
*
* @author Mark Fisher
*/
@@ -79,27 +77,16 @@ public class AnnotationMethodMessageMapper implements MessageMapper {
MethodParameter methodParam = new MethodParameter(this.method, i);
methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
GenericTypeResolver.resolveParameterType(methodParam, this.method.getDeclaringClass());
- Object[] paramAnns = methodParam.getParameterAnnotations();
- String attributeName = null;
- String propertyName = null;
- for (int j = 0; j < paramAnns.length; j++) {
- Object paramAnn = paramAnns[j];
- if (HeaderAttribute.class.isInstance(paramAnn)) {
- HeaderAttribute headerAttribute = (HeaderAttribute) paramAnn;
- attributeName = this.resolveParameterNameIfNecessary(headerAttribute.value(), methodParam);
- parameterMetadata[i] = new MethodParameterMetadata(HeaderAttribute.class, attributeName, headerAttribute.required());
- }
- else if (HeaderProperty.class.isInstance(paramAnn)) {
- HeaderProperty headerProperty = (HeaderProperty) paramAnn;
- propertyName = this.resolveParameterNameIfNecessary(headerProperty.value(), methodParam);
- parameterMetadata[i] = new MethodParameterMetadata(HeaderProperty.class, propertyName, headerProperty.required());
+ Object[] paramAnnotations = methodParam.getParameterAnnotations();
+ String headerName = null;
+ for (int j = 0; j < paramAnnotations.length; j++) {
+ if (Header.class.isInstance(paramAnnotations[j])) {
+ Header headerAnnotation = (Header) paramAnnotations[j];
+ headerName = this.resolveParameterNameIfNecessary(headerAnnotation.value(), methodParam);
+ parameterMetadata[i] = new MethodParameterMetadata(Header.class, headerName, headerAnnotation.required());
}
}
- if (attributeName != null && propertyName != null) {
- throw new ConfigurationException("The @HeaderAttribute and @HeaderProperty annotations " +
- "are mutually exclusive. They should not both be provided on the same parameter.");
- }
- if (attributeName == null && propertyName == null) {
+ if (headerName == null) {
parameterMetadata[i] = new MethodParameterMetadata(methodParam.getParameterType(), null, false);
}
}
@@ -121,19 +108,11 @@ public class AnnotationMethodMessageMapper implements MessageMapper {
for (int i = 0; i < this.parameterMetadata.length; i++) {
MethodParameterMetadata metadata = this.parameterMetadata[i];
Class> expectedType = metadata.type;
- if (expectedType.equals(HeaderAttribute.class)) {
+ if (expectedType.equals(Header.class)) {
Object value = message.getHeaders().get(metadata.key);
if (value == null && metadata.required) {
throw new MessageHandlingException(message,
- "required attribute '" + metadata.key + "' not available");
- }
- args[i] = value;
- }
- else if (expectedType.equals(HeaderProperty.class)) {
- Object value = message.getHeaders().get(metadata.key);
- if (value == null && metadata.required) {
- throw new MessageHandlingException(message,
- "required property '" + metadata.key + "' not available");
+ "required header '" + metadata.key + "' not available");
}
args[i] = value;
}
diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/HeaderAttribute.java b/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/Header.java
similarity index 79%
rename from org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/HeaderAttribute.java
rename to org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/Header.java
index 31b8004036..88c7d89896 100644
--- a/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/HeaderAttribute.java
+++ b/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/Header.java
@@ -24,17 +24,17 @@ import java.lang.annotation.Target;
/**
* Annotation indicating that a method parameter's value should be
- * retrieved from an attribute in the message header. The value of
- * the annotation provides the attribute key, and the optional
- * 'required' property specifies whether the attribute value must
- * be available within the header.
+ * retrieved from the message headers. The value of the annotation
+ * provides the header name, and the optional 'required' property
+ * specifies whether the attribute value must be available within
+ * the header. The default value for 'required' is true.
*
* @author Mark Fisher
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
-public @interface HeaderAttribute {
+public @interface Header {
String value() default "";
diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/HeaderProperty.java b/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/HeaderProperty.java
deleted file mode 100644
index d650eff6a6..0000000000
--- a/org.springframework.integration/src/main/java/org/springframework/integration/handler/annotation/HeaderProperty.java
+++ /dev/null
@@ -1,43 +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.handler.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation indicating that a method parameter's value should be
- * retrieved from a property in the message header. The value of
- * the annotation provides the property key, and the optional
- * 'required' property specifies whether the property value must
- * be available within the header.
- *
- * @author Mark Fisher
- */
-@Target(ElementType.PARAMETER)
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface HeaderProperty {
-
- String value() default "";
-
- boolean required() default true;
-
-}
diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/util/AbstractMethodInvokingAdapter.java b/org.springframework.integration/src/main/java/org/springframework/integration/util/AbstractMethodInvokingAdapter.java
index 85fd4ad48d..55a034e777 100644
--- a/org.springframework.integration/src/main/java/org/springframework/integration/util/AbstractMethodInvokingAdapter.java
+++ b/org.springframework.integration/src/main/java/org/springframework/integration/util/AbstractMethodInvokingAdapter.java
@@ -26,7 +26,7 @@ import org.springframework.core.Ordered;
import org.springframework.integration.ConfigurationException;
/**
- * An base class for adapters that invoke a specified method and target object.
+ * A base class for adapters that invoke a specified method and target object.
* Either a {@link Method} reference or a 'methodName' may be provided, but both
* are not necessary. In fact, while preference is given to a {@link Method}
* reference if available, an Exception will be thrown if a non-matching
diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/handler/annotation/AnnotationMethodMessageMapperTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/handler/annotation/AnnotationMethodMessageMapperTests.java
index b9604146fb..8e8073c960 100644
--- a/org.springframework.integration/src/test/java/org/springframework/integration/handler/annotation/AnnotationMethodMessageMapperTests.java
+++ b/org.springframework.integration/src/test/java/org/springframework/integration/handler/annotation/AnnotationMethodMessageMapperTests.java
@@ -41,8 +41,8 @@ import org.springframework.integration.message.StringMessage;
public class AnnotationMethodMessageMapperTests {
@Test
- public void testOptionalAttribute() throws Exception {
- Method method = TestHandler.class.getMethod("optionalAttribute", Integer.class);
+ public void testOptionalHeader() throws Exception {
+ Method method = TestHandler.class.getMethod("optionalHeader", Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
Object[] args = (Object[]) mapper.mapMessage(new StringMessage("foo"));
assertEquals(1, args.length);
@@ -50,15 +50,15 @@ public class AnnotationMethodMessageMapperTests {
}
@Test(expected=MessageHandlingException.class)
- public void testRequiredAttributeNotProvided() throws Exception {
- Method method = TestHandler.class.getMethod("requiredAttribute", Integer.class);
+ public void testRequiredHeaderNotProvided() throws Exception {
+ Method method = TestHandler.class.getMethod("requiredHeader", Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
mapper.mapMessage(new StringMessage("foo"));
}
@Test
- public void testRequiredAttributeProvided() throws Exception {
- Method method = TestHandler.class.getMethod("requiredAttribute", Integer.class);
+ public void testRequiredHeaderProvided() throws Exception {
+ Method method = TestHandler.class.getMethod("requiredHeader", Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
Message message = MessageBuilder.fromPayload("foo")
.setHeader("num", new Integer(123)).build();
@@ -67,31 +67,39 @@ public class AnnotationMethodMessageMapperTests {
assertEquals(new Integer(123), args[0]);
}
- @Test
- public void testOptionalProperty() throws Exception {
- Method method = TestHandler.class.getMethod("optionalProperty", String.class);
- AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
- Object[] args = (Object[]) mapper.mapMessage(new StringMessage("foo"));
- assertEquals(1, args.length);
- assertNull(args[0]);
- }
-
@Test(expected=MessageHandlingException.class)
- public void testRequiredPropertyNotProvided() throws Exception {
- Method method = TestHandler.class.getMethod("requiredProperty", String.class);
- AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
- mapper.mapMessage(new StringMessage("foo"));
- }
-
- @Test
- public void testRequiredPropertyProvided() throws Exception {
- Method method = TestHandler.class.getMethod("requiredProperty", String.class);
+ public void testOptionalAndRequiredHeaderWithOnlyOptionalHeaderProvided() throws Exception {
+ Method method = TestHandler.class.getMethod("optionalAndRequiredHeader", String.class, Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
Message message = MessageBuilder.fromPayload("foo")
- .setHeader("prop", "bar").build();
+ .setHeader("prop", "bar").build();
+ mapper.mapMessage(message);
+ }
+
+ @Test
+ public void testOptionalAndRequiredHeaderWithOnlyRequiredHeaderProvided() throws Exception {
+ Method method = TestHandler.class.getMethod("optionalAndRequiredHeader", String.class, Integer.class);
+ AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
+ Message message = MessageBuilder.fromPayload("foo")
+ .setHeader("num", new Integer(123)).build();
Object[] args = (Object[]) mapper.mapMessage(message);
- assertEquals(1, args.length);
+ assertEquals(2, args.length);
+ assertNull(args[0]);
+ assertEquals(123, args[1]);
+ }
+
+ @Test
+ public void testOptionalAndRequiredHeaderWithBothHeadersProvided() throws Exception {
+ Method method = TestHandler.class.getMethod("optionalAndRequiredHeader", String.class, Integer.class);
+ AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
+ Message message = MessageBuilder.fromPayload("foo")
+ .setHeader("num", new Integer(123))
+ .setHeader("prop", "bar")
+ .build();
+ Object[] args = (Object[]) mapper.mapMessage(message);
+ assertEquals(2, args.length);
assertEquals("bar", args[0]);
+ assertEquals(123, args[1]);
}
@Test
@@ -210,7 +218,7 @@ public class AnnotationMethodMessageMapperTests {
@Test
public void testMessageAndHeaderWithAdapter() throws Exception {
TestHandler handler = new TestHandler();
- Method method = handler.getClass().getMethod("messageAndAttribute", Message.class, Integer.class);
+ Method method = handler.getClass().getMethod("messageAndHeader", Message.class, Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(handler);
@@ -223,9 +231,9 @@ public class AnnotationMethodMessageMapperTests {
}
@Test
- public void testHeaderAndPropertyWithAdapter() throws Exception {
+ public void testMultipleHeadersWithAdapter() throws Exception {
TestHandler handler = new TestHandler();
- Method method = handler.getClass().getMethod("propertyAndAttribute", String.class, Integer.class);
+ Method method = handler.getClass().getMethod("twoHeaders", String.class, Integer.class);
AnnotationMethodMessageMapper mapper = new AnnotationMethodMessageMapper(method);
DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter();
adapter.setObject(handler);
@@ -247,33 +255,28 @@ public class AnnotationMethodMessageMapperTests {
}
@Handler
- public String messageAndAttribute(Message> message, @HeaderAttribute("number") Integer num) {
+ public String messageAndHeader(Message> message, @Header("number") Integer num) {
return (String) message.getPayload() + "-" + num.toString();
}
@Handler
- public String propertyAndAttribute(@HeaderProperty String prop, @HeaderAttribute("number") Integer num) {
+ public String twoHeaders(@Header String prop, @Header("number") Integer num) {
return prop + "-" + num.toString();
}
@Handler
- public Integer optionalAttribute(@HeaderAttribute(required=false) Integer num) {
+ public Integer optionalHeader(@Header(required=false) Integer num) {
return num;
}
@Handler
- public Integer requiredAttribute(@HeaderAttribute(value="num", required=true) Integer num) {
+ public Integer requiredHeader(@Header(value="num", required=true) Integer num) {
return num;
}
@Handler
- public String optionalProperty(@HeaderProperty(required=false) String prop) {
- return prop;
- }
-
- @Handler
- public String requiredProperty(@HeaderProperty(value="prop", required=true) String prop) {
- return prop;
+ public String optionalAndRequiredHeader(@Header(required=false) String prop, @Header(value="num", required=true) Integer num) {
+ return prop + num;
}
@Handler
diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/router/RouterMessageHandlerAdapterTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/router/RouterMessageHandlerAdapterTests.java
index 7448c0ca8d..8d79dfc9d0 100644
--- a/org.springframework.integration/src/test/java/org/springframework/integration/router/RouterMessageHandlerAdapterTests.java
+++ b/org.springframework.integration/src/test/java/org/springframework/integration/router/RouterMessageHandlerAdapterTests.java
@@ -26,17 +26,16 @@ import java.util.List;
import org.junit.Test;
-import org.springframework.integration.ConfigurationException;
import org.springframework.integration.channel.ChannelRegistry;
import org.springframework.integration.channel.ChannelRegistryAware;
import org.springframework.integration.channel.DefaultChannelRegistry;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
-import org.springframework.integration.handler.annotation.HeaderAttribute;
-import org.springframework.integration.handler.annotation.HeaderProperty;
+import org.springframework.integration.handler.annotation.Header;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageBuilder;
+import org.springframework.integration.message.MessageHandlingException;
import org.springframework.integration.message.StringMessage;
/**
@@ -75,7 +74,7 @@ public class RouterMessageHandlerAdapterTests {
@Test
public void testChannelNameResolutionByHeader() throws Exception {
SingleChannelNameRoutingTestBean testBean = new SingleChannelNameRoutingTestBean();
- Method routingMethod = testBean.getClass().getMethod("routeByProperty", String.class);
+ Method routingMethod = testBean.getClass().getMethod("routeByHeader", String.class);
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
Message message = MessageBuilder.fromPayload("bar")
.setHeader("returnAddress", "baz").build();
@@ -94,10 +93,10 @@ public class RouterMessageHandlerAdapterTests {
assertEquals("bar", message2.getPayload());
}
- @Test(expected=ConfigurationException.class)
- public void testFailsWhenPropertyAndAttributeAreBothProvided() throws Exception {
- InvalidRoutingTestBean testBean = new InvalidRoutingTestBean();
- Method routingMethod = testBean.getClass().getMethod("tooManyAnnotations", String.class);
+ @Test(expected=MessageHandlingException.class)
+ public void testFailsWhenRequireddHeaderIsNotProvided() throws Exception {
+ SingleChannelNameRoutingTestBean testBean = new SingleChannelNameRoutingTestBean();
+ Method routingMethod = testBean.getClass().getMethod("routeByHeader", String.class);
RouterMessageHandlerAdapter adapter = new RouterMessageHandlerAdapter(testBean, routingMethod);
adapter.afterPropertiesSet();
adapter.handle(new GenericMessage("testing"));
@@ -542,11 +541,7 @@ public class RouterMessageHandlerAdapterTests {
return name + "-channel";
}
- public String routeByProperty(@HeaderProperty("returnAddress") String name) {
- return name + "-channel";
- }
-
- public String routeByAttribute(@HeaderAttribute("returnAddress") String name) {
+ public String routeByHeader(@Header("returnAddress") String name) {
return name + "-channel";
}
@@ -673,12 +668,4 @@ public class RouterMessageHandlerAdapterTests {
}
}
- public static class InvalidRoutingTestBean {
-
- public String tooManyAnnotations(@HeaderProperty("foo") @HeaderAttribute("bar") String name) {
- return name + "-channel";
- }
-
- }
-
}
diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/transformer/AnnotationMethodTransformerAdapterTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/transformer/AnnotationMethodTransformerAdapterTests.java
index 78fd163bbb..cc106ad838 100644
--- a/org.springframework.integration/src/test/java/org/springframework/integration/transformer/AnnotationMethodTransformerAdapterTests.java
+++ b/org.springframework.integration/src/test/java/org/springframework/integration/transformer/AnnotationMethodTransformerAdapterTests.java
@@ -25,8 +25,7 @@ import java.util.Properties;
import org.junit.Test;
import org.springframework.integration.annotation.Transformer;
-import org.springframework.integration.handler.annotation.HeaderAttribute;
-import org.springframework.integration.handler.annotation.HeaderProperty;
+import org.springframework.integration.handler.annotation.Header;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageBuilder;
@@ -72,11 +71,11 @@ public class AnnotationMethodTransformerAdapterTests {
}
@Test
- public void testHeaderAttributeAnnotation() throws Exception {
+ public void testHeaderAnnotation() throws Exception {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
- adapter.setMethod(testBean.getClass().getMethod("attributeTest", String.class, Integer.class));
+ adapter.setMethod(testBean.getClass().getMethod("headerTest", String.class, Integer.class));
Message message = MessageBuilder.fromPayload("foo")
.setHeader("number", 123).build();
Message> result = adapter.handle(message);
@@ -88,22 +87,21 @@ public class AnnotationMethodTransformerAdapterTests {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
- adapter.setMethod(testBean.getClass().getMethod("attributeTest", String.class, Integer.class));
+ adapter.setMethod(testBean.getClass().getMethod("headerTest", String.class, Integer.class));
Message message = MessageBuilder.fromPayload("foo")
.setHeader("wrong", 123).build();
adapter.handle(message);
}
@Test
- public void testHeaderAnnotation() throws Exception {
+ public void testOptionalHeaderAnnotation() throws Exception {
TestBean testBean = new TestBean();
AnnotationMethodTransformerAdapter adapter = new AnnotationMethodTransformerAdapter();
adapter.setObject(testBean);
- adapter.setMethod(testBean.getClass().getMethod("propertyTest", String.class, String.class));
- Message message = MessageBuilder.fromPayload("foo")
- .setHeader("suffix", "bar").build();
+ adapter.setMethod(testBean.getClass().getMethod("optionalHeaderTest", String.class, Integer.class));
+ Message message = MessageBuilder.fromPayload("foo").build();
Message> result = adapter.handle(message);
- assertEquals("foobar", result.getPayload());
+ assertEquals("foonull", result.getPayload());
}
@Test
@@ -153,13 +151,13 @@ public class AnnotationMethodTransformerAdapterTests {
}
@Transformer
- public String attributeTest(String s, @HeaderAttribute("number") Integer num) {
+ public String headerTest(String s, @Header("number") Integer num) {
return s + num;
}
@Transformer
- public String propertyTest(String s, @HeaderProperty("suffix") String suffix) {
- return s + suffix;
+ public String optionalHeaderTest(String s, @Header(value="number", required=false) Integer num) {
+ return s + num;
}
@Transformer