From f2529d1dc249a783731f2748618ae9fc9ac2dc5c Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Wed, 1 Jul 2009 23:43:20 +0000 Subject: [PATCH] INT-656 Removed the restriction in HandlerMethodUtils for having no more than one param lacking the header or headers annotations. It now allows parameters that are assignable to Map as well. Added several tests for Properties and Map objects expecting to receive Message header values. --- .../handler/HandlerMethodUtils.java | 10 +- ...arameterMessageMapperFromMessageTests.java | 13 +- .../message/PayloadAndHeaderMappingTests.java | 416 ++++++++++++++++++ 3 files changed, 430 insertions(+), 9 deletions(-) create mode 100644 org.springframework.integration/src/test/java/org/springframework/integration/message/PayloadAndHeaderMappingTests.java 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); + } + } + +}