diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/handler/HandlerMethodUtils.java b/org.springframework.integration/src/main/java/org/springframework/integration/handler/HandlerMethodUtils.java index 762ed7f45f..0f2d135ead 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/handler/HandlerMethodUtils.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/handler/HandlerMethodUtils.java @@ -21,6 +21,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.springframework.aop.support.AopUtils; import org.springframework.integration.annotation.Header; @@ -49,11 +50,14 @@ abstract class HandlerMethodUtils { } Class[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length > 1) { - // at most one parameter can be lacking @Header or @Headers + // at most one parameter can be expecting a Message or payload. boolean foundPayloadParam = false; Annotation[][] allParamAnnotations = method.getParameterAnnotations(); - for (Annotation[] paramAnnotations : allParamAnnotations) { - if (!containsHeaderAnnotation(paramAnnotations)) { + for (int i = 0; i < parameterTypes.length; i++) { + Class currentType = parameterTypes[i]; + Annotation[] paramAnnotations = allParamAnnotations[i]; + // it's possible that a Map is the payload type at runtime, but we can't know that here + if (!containsHeaderAnnotation(paramAnnotations) && !Map.class.isAssignableFrom(currentType)) { if (foundPayloadParam) { return false; } diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperFromMessageTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperFromMessageTests.java index 61bbdf360a..846651dd99 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperFromMessageTests.java +++ b/org.springframework.integration/src/test/java/org/springframework/integration/message/MethodParameterMessageMapperFromMessageTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2009 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. @@ -222,10 +222,10 @@ public class MethodParameterMessageMapperFromMessageTests { public Properties propertiesHeaders(@Headers Properties properties) { return properties; } - - public Object propertiesHeadersAndPayload(Properties headers, Object payload) { - return payload; - } + + public Object propertiesHeadersAndPayload(Properties headers, Object payload) { + return payload; + } @SuppressWarnings("unchecked") public Map mapPayload(Map map) { @@ -236,7 +236,7 @@ public class MethodParameterMessageMapperFromMessageTests { public Map mapHeaders(@Headers Map map) { return map; } - + @SuppressWarnings("unchecked") public Object mapHeadersAndPayload(Map headers, Object payload) { return payload; @@ -246,4 +246,5 @@ public class MethodParameterMessageMapperFromMessageTests { return i; } } + } diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/message/PayloadAndHeaderMappingTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/message/PayloadAndHeaderMappingTests.java new file mode 100644 index 0000000000..c3806a8014 --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/message/PayloadAndHeaderMappingTests.java @@ -0,0 +1,416 @@ +/* + * Copyright 2002-2009 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.message; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.integration.annotation.Header; +import org.springframework.integration.annotation.Headers; +import org.springframework.integration.core.Message; +import org.springframework.integration.handler.ServiceActivatingHandler; + +/** + * @author Mark Fisher + */ +public class PayloadAndHeaderMappingTests { + + private TestBean bean; + + + @Before + public void setup() { + bean = new TestBean(); + } + + + @Test + public void headerPropertiesAndObjectPayload() throws Exception { + MessageHandler handler = this.getHandler("headerPropertiesAndObjectPayload", Properties.class, Object.class); + Object payload = "test"; + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + headers.put("baz", 99); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertTrue(bean.lastHeaders.containsKey("bar")); + assertFalse(bean.lastHeaders.containsKey("baz")); + } + + @Test + public void stringPayloadAndHeaderProperties() throws Exception { + MessageHandler handler = this.getHandler("stringPayloadAndHeaderProperties", String.class, Properties.class); + Object payload = "test"; + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + headers.put("baz", 99); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertTrue(bean.lastHeaders.containsKey("bar")); + assertFalse(bean.lastHeaders.containsKey("baz")); + } + + @Test + public void headerMapAndObjectPayload() throws Exception { + MessageHandler handler = this.getHandler("headerMapAndObjectPayload", Map.class, Object.class); + Object payload = "test"; + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + headers.put("baz", 99); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertTrue(bean.lastHeaders.containsKey("bar")); + assertTrue(bean.lastHeaders.containsKey("baz")); + } + + @Test + public void objectPayloadAndHeaderMap() throws Exception { + MessageHandler handler = this.getHandler("objectPayloadAndHeaderMap", Object.class, Map.class); + Object payload = "test"; + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + headers.put("baz", 99); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertTrue(bean.lastHeaders.containsKey("bar")); + assertTrue(bean.lastHeaders.containsKey("baz")); + } + + @Test + public void payloadMapAndHeaderString() throws Exception { + MessageHandler handler = this.getHandler("payloadMapAndHeaderString", Map.class, String.class); + Map payload = new HashMap(); + payload.put("abc", 1); + payload.put("xyz", "test"); + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertFalse(bean.lastHeaders.containsKey("bar")); + } + + @Test + public void payloadMapAndHeaderStrings() throws Exception { + MessageHandler handler = this.getHandler("payloadMapAndHeaderStrings", Map.class, String.class, String.class); + Map payload = new HashMap(); + payload.put("abc", 1); + payload.put("xyz", "test"); + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + headers.put("baz", "3"); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertTrue(bean.lastHeaders.containsKey("bar")); + assertFalse(bean.lastHeaders.containsKey("baz")); + } + + @Test + public void objectPayloadHeaderMapAndStringHeaders() throws Exception { + MessageHandler handler = this.getHandler("objectPayloadHeaderMapAndStringHeaders", + String.class, Map.class, String.class, Object.class); + Object payload = "test"; + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + headers.put("baz", 99); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertEquals("1", bean.lastHeaders.get("foo")); + assertTrue(bean.lastHeaders.containsKey("bar")); + assertEquals("2", bean.lastHeaders.get("bar")); + assertTrue(bean.lastHeaders.containsKey("baz")); + assertTrue(bean.lastHeaders.containsKey("foo2")); + assertEquals("1", bean.lastHeaders.get("foo2")); + assertTrue(bean.lastHeaders.containsKey("bar2")); + assertEquals("2", bean.lastHeaders.get("bar2")); + } + + @Test + public void payloadMapAndHeaderMap() throws Exception { + MessageHandler handler = this.getHandler("payloadMapAndHeaderMap", Map.class, Map.class); + Map payload = new HashMap(); + payload.put("abc", 1); + payload.put("xyz", "test"); + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + headers.put("baz", 99); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertTrue(bean.lastHeaders.containsKey("bar")); + assertTrue(bean.lastHeaders.containsKey("baz")); + } + + @Test + public void headerMapAndPayloadMap() throws Exception { + MessageHandler handler = this.getHandler("headerMapAndPayloadMap", Map.class, Map.class); + Map payload = new HashMap(); + payload.put("abc", 1); + payload.put("xyz", "test"); + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + headers.put("baz", 99); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertTrue(bean.lastHeaders.containsKey("bar")); + assertTrue(bean.lastHeaders.containsKey("baz")); + } + + @Test + public void payloadMapAndHeaderProperties() throws Exception { + MessageHandler handler = this.getHandler("payloadMapAndHeaderProperties", Map.class, Properties.class); + Map payload = new HashMap(); + payload.put("abc", 1); + payload.put("xyz", "test"); + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + headers.put("baz", 99); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertTrue(bean.lastHeaders.containsKey("bar")); + assertFalse(bean.lastHeaders.containsKey("baz")); + } + + @Test + public void headerPropertiesPayloadMapAndStringHeader() throws Exception { + MessageHandler handler = this.getHandler("headerPropertiesPayloadMapAndStringHeader", + Properties.class, Map.class, String.class); + Map payload = new HashMap(); + payload.put("abc", 1); + payload.put("xyz", "test"); + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + headers.put("baz", 99); + Message message = MessageBuilder.withPayload(payload).copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payload, bean.lastPayload); + assertTrue(bean.lastHeaders.containsKey("foo")); + assertEquals("1", bean.lastHeaders.get("foo")); + assertTrue(bean.lastHeaders.containsKey("bar")); + assertTrue(bean.lastHeaders.containsKey("foo2")); + assertEquals("1", bean.lastHeaders.get("foo2")); + assertFalse(bean.lastHeaders.containsKey("baz")); + } + + @Test + public void twoMapsNoAnnotations() throws Exception { + MessageHandler handler = this.getHandler("twoMapsNoAnnotations", Map.class, Map.class); + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + Message message = MessageBuilder.withPayload("test").copyHeaders(headers).build(); + handler.handleMessage(message); + assertNull(bean.lastPayload); + assertEquals("1", bean.lastHeaders.get("foo")); + assertEquals("2", bean.lastHeaders.get("bar")); + assertEquals("1", bean.lastHeaders.get("foo2")); + assertEquals("2", bean.lastHeaders.get("bar2")); + } + + @Test + public void twoMapsNoAnnotationsAndObject() throws Exception { + MessageHandler handler = this.getHandler("twoMapsNoAnnotationsAndObject", + Map.class, Object.class, Map.class); + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + Message message = MessageBuilder.withPayload("test").copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals("test", bean.lastPayload); + assertEquals("1", bean.lastHeaders.get("foo")); + assertEquals("2", bean.lastHeaders.get("bar")); + assertEquals("1", bean.lastHeaders.get("foo2")); + assertEquals("2", bean.lastHeaders.get("bar2")); + } + + @Test + public void twoMapsNoAnnotationsAndObjectWithMapPayload() throws Exception { + MessageHandler handler = this.getHandler("twoMapsNoAnnotationsAndObject", + Map.class, Object.class, Map.class); + Map payloadMap = new HashMap(); + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + Message message = MessageBuilder.withPayload(payloadMap) + .copyHeaders(headers).build(); + handler.handleMessage(message); + assertEquals(payloadMap, bean.lastPayload); + assertEquals("1", bean.lastHeaders.get("foo")); + assertEquals("2", bean.lastHeaders.get("bar")); + assertEquals("1", bean.lastHeaders.get("foo2")); + assertEquals("2", bean.lastHeaders.get("bar2")); + } + + @Test + public void twoMapsNoAnnotationsAndAnnotatedString() throws Exception { + MessageHandler handler = this.getHandler("twoMapsNoAnnotationsAndAnnotatedString", + Map.class, Map.class, String.class); + Map headers = new HashMap(); + headers.put("foo", "1"); + headers.put("bar", "2"); + Message message = MessageBuilder.withPayload("test") + .copyHeaders(headers).build(); + handler.handleMessage(message); + assertNull(bean.lastPayload); + assertEquals("1", bean.lastHeaders.get("foo")); + assertEquals("2", bean.lastHeaders.get("bar")); + assertEquals("1", bean.lastHeaders.get("foo2")); + assertEquals("2", bean.lastHeaders.get("bar2")); + assertEquals("1", bean.lastHeaders.get("foo3")); + } + + + private ServiceActivatingHandler getHandler(String methodName, Class... types) throws Exception { + return new ServiceActivatingHandler(bean, TestBean.class.getMethod(methodName, types)); + } + + + @SuppressWarnings("unchecked") + private static class TestBean { + + private volatile Map lastHeaders; + + private volatile Object lastPayload; + + + public void headerPropertiesAndObjectPayload(Properties headers, Object payload) { + this.lastHeaders = headers; + this.lastPayload = payload; + } + + public void stringPayloadAndHeaderProperties(String payload, Properties headers) { + this.lastHeaders = headers; + this.lastPayload = payload; + } + + public void headerMapAndObjectPayload(Map headers, Object payload) { + this.lastHeaders = headers; + this.lastPayload = payload; + } + + public void objectPayloadAndHeaderMap(Object payload, Map headers) { + this.lastHeaders = headers; + this.lastPayload = payload; + } + + public void objectPayloadHeaderMapAndStringHeaders( + @Header("foo") String header1, Map headers, @Header("bar") String header2, Object payload) { + this.lastHeaders = new HashMap(); + this.lastHeaders.put("foo2", header1); + this.lastHeaders.put("bar2", header2); + this.lastHeaders.putAll(headers); + this.lastPayload = payload; + this.lastPayload = payload; + } + + public void payloadMapAndHeaderString(Map payload, @Header("foo") String header) { + this.lastHeaders = new HashMap(); + this.lastHeaders.put("foo", header); + this.lastPayload = payload; + } + + public void payloadMapAndHeaderStrings(Map payload, @Header("foo") String header1, @Header("bar") String header2) { + this.lastHeaders = new HashMap(); + this.lastHeaders.put("foo", header1); + this.lastHeaders.put("bar", header2); + this.lastPayload = payload; + } + + public void payloadMapAndHeaderMap(Map payload, @Headers Map headers) { + this.lastHeaders = headers; + this.lastPayload = payload; + } + + public void headerMapAndPayloadMap(@Headers Map headers, Map payload) { + this.lastHeaders = headers; + this.lastPayload = payload; + } + + public void payloadMapAndHeaderProperties(Map payload, @Headers Properties headers) { + this.lastHeaders = headers; + this.lastPayload = payload; + } + + public void headerPropertiesPayloadMapAndStringHeader(@Headers Properties headers, Map payload, @Header("foo") String header) { + this.lastHeaders = headers; + this.lastHeaders.put("foo2", header); + this.lastPayload = payload; + } + + public void twoMapsNoAnnotations(Map map1, Map map2) { + this.lastHeaders = new HashMap(map1); + for (Map.Entry entry : map2.entrySet()) { + this.lastHeaders.put(entry.getKey() + "2", entry.getValue()); + } + } + + public void twoMapsNoAnnotationsAndObject(Map map1, Object o, Map map2) { + this.lastPayload = o; + this.lastHeaders = new HashMap(map1); + for (Map.Entry entry : map2.entrySet()) { + this.lastHeaders.put(entry.getKey() + "2", entry.getValue()); + } + } + + public void twoMapsNoAnnotationsAndAnnotatedString(Map map1, Map map2, @Header("foo") String s) { + this.lastHeaders = new HashMap(map1); + for (Map.Entry entry : map2.entrySet()) { + this.lastHeaders.put(entry.getKey() + "2", entry.getValue()); + } + this.lastHeaders.put("foo3", s); + } + } + +}