From 990610fdb6db0c2e3977478a62fbba5446e0d5dd Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Tue, 8 Dec 2009 20:43:25 +0000 Subject: [PATCH] INT-894 Added validation to avoid multiple conflicting annotations, and added GatewayProxyMessageMappingTests. --- .../handler/ArgumentArrayMessageMapper.java | 41 ++-- .../GatewayProxyMessageMappingTests.java | 179 ++++++++++++++++++ ...entArrayMessageMapperFromMessageTests.java | 3 +- 3 files changed, 207 insertions(+), 16 deletions(-) create mode 100644 org.springframework.integration/src/test/java/org/springframework/integration/gateway/GatewayProxyMessageMappingTests.java diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java b/org.springframework.integration/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java index 375dc0dcd8..477c37ad83 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/handler/ArgumentArrayMessageMapper.java @@ -44,6 +44,7 @@ import org.springframework.integration.annotation.Header; import org.springframework.integration.annotation.Headers; import org.springframework.integration.annotation.Payload; import org.springframework.integration.core.Message; +import org.springframework.integration.core.MessagingException; import org.springframework.integration.message.InboundMessageMapper; import org.springframework.integration.message.MessageBuilder; import org.springframework.integration.message.MessageHandlingException; @@ -215,7 +216,7 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper type = annotation.annotationType(); if (type.equals(Payload.class) || type.equals(Header.class) || type.equals(Headers.class)) { if (match != null) { - throw new IllegalArgumentException("At most one parameter annotation can be provided for message mapping, " + + throw new MessagingException("At most one parameter annotation can be provided for message mapping, " + "but found two: [" + match.annotationType().getName() + "] and [" + annotation.annotationType().getName() + "]"); } match = annotation; @@ -226,7 +227,7 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper mapArgumentsToMessage(Object[] arguments, Message message) { - boolean mappedMessageOrPayload = false; + MethodParameter messageOrPayloadParameter = null; Map messageArgumentsMap = new LinkedHashMap(); for (int i = 0; i < this.parameterList.size(); i++) { Object argumentValue = arguments[i]; @@ -235,14 +236,14 @@ public class ArgumentArrayMessageMapper implements InboundMessageMapper) { messageArgumentsMap.put("message", argumentValue); } else { messageArgumentsMap.put("payload", argumentValue); - } - mappedMessageOrPayload = true; + } + messageOrPayloadParameter = methodParameter; + } + else if (Map.class.isAssignableFrom(methodParameter.getParameterType())) { + if (Map.class.isAssignableFrom(messageOrPayloadParameter.getParameterType()) + && messageOrPayloadParameter.getParameterAnnotation(Payload.class) == null) { + throw new MessagingException("Ambiguous method parameters; found more than one " + + "Map-typed parameter and neither one contains a @Payload annotation"); + } + messageArgumentsMap.put("headers", argumentValue); } else { this.throwExceptionForMultipleMessageOrPayloadParameters(methodParameter); } } - Assert.isTrue(mappedMessageOrPayload, "unable to determine a Message or payload parameter on method [" + method + "]"); + Assert.isTrue(messageOrPayloadParameter != null, "unable to determine a Message or payload parameter on method [" + method + "]"); return messageArgumentsMap; } private void throwExceptionForMultipleMessageOrPayloadParameters(MethodParameter methodParameter) { - throw new IllegalStateException( + throw new MessagingException( "At most one parameter may be mapped to the payload or Message, " + "found more than one on method [" + methodParameter.getMethod() + "]"); } private Message buildMessageFromArgumentMap(Map messageArgumentsMap) { MessageBuilder builder = null; - Map headers = null; Message message = (Message) messageArgumentsMap.get("message"); if (message != null) { - Object payload = message.getPayload(); - headers = message.getHeaders(); - builder = MessageBuilder.withPayload(payload).copyHeaders(headers); + builder = MessageBuilder.fromMessage(message); } else { builder = MessageBuilder.withPayload(messageArgumentsMap.get("payload")); } + Object headers = messageArgumentsMap.get("headers"); + if (headers != null && headers instanceof Map) { + builder.copyHeadersIfAbsent((Map) headers); + } for (Object headerName : messageArgumentsMap.keySet()) { - if (!headerName.equals("payload") && !headerName.equals("message")) { // everything else is a header + if (!headerName.equals("payload") && !headerName.equals("message") && !headerName.equals("headers")) { + // everything else is a header builder.setHeader((String) headerName, messageArgumentsMap.get(headerName)); } } diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/gateway/GatewayProxyMessageMappingTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/gateway/GatewayProxyMessageMappingTests.java new file mode 100644 index 0000000000..6506b36602 --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/gateway/GatewayProxyMessageMappingTests.java @@ -0,0 +1,179 @@ +/* + * 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.gateway; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.integration.annotation.Header; +import org.springframework.integration.annotation.Headers; +import org.springframework.integration.annotation.Payload; +import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.core.Message; +import org.springframework.integration.core.MessagingException; + +/** + * @author Mark Fisher + * @since 2.0 + */ +public class GatewayProxyMessageMappingTests { + + private final QueueChannel channel = new QueueChannel(); + + private volatile TestGateway gateway = null; + + + @Before + public void initializeGateway() throws Exception { + GatewayProxyFactoryBean factoryBean = new GatewayProxyFactoryBean(); + factoryBean.setServiceInterface(TestGateway.class); + factoryBean.setDefaultRequestChannel(channel); + factoryBean.afterPropertiesSet(); + this.gateway = (TestGateway) factoryBean.getObject(); + } + + + @Test + public void payloadAndHeaderMapWithoutAnnotations() throws Exception { + Map m = new HashMap(); + m.put("k1", "v1"); + m.put("k2", "v2"); + gateway.payloadAndHeaderMapWithoutAnnotations("foo", m); + Message result = channel.receive(0); + assertNotNull(result); + assertEquals("foo", result.getPayload()); + assertEquals("v1", result.getHeaders().get("k1")); + assertEquals("v2", result.getHeaders().get("k2")); + } + + @Test + public void payloadAndHeaderMapWithAnnotations() throws Exception { + Map m = new HashMap(); + m.put("k1", "v1"); + m.put("k2", "v2"); + gateway.payloadAndHeaderMapWithAnnotations("foo", m); + Message result = channel.receive(0); + assertNotNull(result); + assertEquals("foo", result.getPayload()); + assertEquals("v1", result.getHeaders().get("k1")); + assertEquals("v2", result.getHeaders().get("k2")); + } + + @Test + public void headerValuesAndPayloadWithAnnotations() throws Exception { + gateway.headerValuesAndPayloadWithAnnotations("headerValue1", "payloadValue", "headerValue2"); + Message result = channel.receive(0); + assertNotNull(result); + assertEquals("payloadValue", result.getPayload()); + assertEquals("headerValue1", result.getHeaders().get("k1")); + assertEquals("headerValue2", result.getHeaders().get("k2")); + } + + @Test + public void mapOnly() throws Exception { + Map map = new HashMap(); + map.put("k1", "v1"); + map.put("k2", "v2"); + gateway.mapOnly(map); + Message result = channel.receive(0); + assertNotNull(result); + assertEquals(map, result.getPayload()); + assertNull(result.getHeaders().get("k1")); + assertNull(result.getHeaders().get("k2")); + } + + @Test + public void twoMapsAndOneAnnotatedWithPayload() { + Map map1 = new HashMap(); + Map map2 = new HashMap(); + map1.put("k1", "v1"); + map2.put("k2", "v2"); + gateway.twoMapsAndOneAnnotatedWithPayload(map1, map2); + Message result = channel.receive(0); + assertNotNull(result); + assertEquals(map1, result.getPayload()); + assertEquals("v2", result.getHeaders().get("k2")); + assertNull(result.getHeaders().get("k1")); + } + + @Test(expected = MessagingException.class) + public void twoMapsWithoutAnnotations() { + Map map1 = new HashMap(); + Map map2 = new HashMap(); + map1.put("k1", "v1"); + map2.put("k2", "v2"); + gateway.twoMapsWithoutAnnotations(map1, map2); + } + + @Test(expected = MessagingException.class) + public void twoPayloads() throws Exception { + gateway.twoPayloads("won't", "work"); + } + + @Test(expected = MessagingException.class) + public void payloadAndHeaderAnnotationsOnSameParameter() throws Exception { + gateway.payloadAndHeaderAnnotationsOnSameParameter("oops"); + } + + @Test(expected = MessagingException.class) + public void payloadAndHeadersAnnotationsOnSameParameter() throws Exception { + gateway.payloadAndHeadersAnnotationsOnSameParameter(new HashMap()); + } + + @Test(expected = MessagingException.class) + public void payloadWithExpression() throws Exception { + gateway.payloadWithExpression("test"); + } + + + public static interface TestGateway { + + void payloadAndHeaderMapWithoutAnnotations(String s, Map map); + + void payloadAndHeaderMapWithAnnotations(@Payload String s, @Headers Map map); + + void headerValuesAndPayloadWithAnnotations(@Header("k1") String x, @Payload String s, @Header("k2") String y); + + void mapOnly(Map map); + + void twoMapsAndOneAnnotatedWithPayload(@Payload Map payload, Map headers); + + // invalid + void twoMapsWithoutAnnotations(Map m1, Map m2); + + // invalid + void twoPayloads(@Payload String s1, @Payload String s2); + + // invalid + void payloadAndHeaderAnnotationsOnSameParameter(@Payload @Header("x") String s); + + // invalid + void payloadAndHeadersAnnotationsOnSameParameter(@Payload @Headers Map map); + + // invalid + void payloadWithExpression(@Payload("oops") String s); + + } + +} diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/handler/ArgumentArrayMessageMapperFromMessageTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/handler/ArgumentArrayMessageMapperFromMessageTests.java index b46d7dc9b7..02a8737609 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/handler/ArgumentArrayMessageMapperFromMessageTests.java +++ b/org.springframework.integration/src/test/java/org/springframework/integration/handler/ArgumentArrayMessageMapperFromMessageTests.java @@ -31,6 +31,7 @@ import org.springframework.integration.annotation.Header; import org.springframework.integration.annotation.Headers; import org.springframework.integration.annotation.Payload; import org.springframework.integration.core.Message; +import org.springframework.integration.core.MessagingException; import org.springframework.integration.message.MessageBuilder; import org.springframework.integration.message.MessageHandlingException; import org.springframework.integration.message.StringMessage; @@ -280,7 +281,7 @@ public class ArgumentArrayMessageMapperFromMessageTests { Assert.assertTrue(args[1].equals("monday")); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = MessagingException.class) public void fromMessageInvalidMethodWithMultipleMappingAnnotations() throws Exception { Method method = MultipleMappingAnnotationTestBean.class.getMethod("test", String.class); ArgumentArrayMessageMapper mapper = new ArgumentArrayMessageMapper(method);