diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/HttpRequestExecutingMessageHandler.java b/spring-integration-http/src/main/java/org/springframework/integration/http/HttpRequestExecutingMessageHandler.java index e7a6249639..991533e7b1 100755 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/HttpRequestExecutingMessageHandler.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/HttpRequestExecutingMessageHandler.java @@ -19,6 +19,7 @@ package org.springframework.integration.http; import java.io.Serializable; import java.net.URI; import java.nio.charset.Charset; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -46,9 +47,12 @@ import org.springframework.integration.core.MessageHandler; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; import org.springframework.integration.mapping.HeaderMapper; import org.springframework.integration.support.MessageBuilder; +import org.springframework.integration.support.converter.MessageConversionException; import org.springframework.integration.util.SimpleBeanResolver; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestTemplate; @@ -266,6 +270,7 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe return new HttpEntity(requestMessage, headers); } + @SuppressWarnings({ "unchecked", "rawtypes"}) private MediaType resolveContentType(Object content) { MediaType contentType = null; if (content instanceof byte[]) { @@ -275,11 +280,17 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe contentType = MediaType.TEXT_XML; } else { - if (content instanceof Map && isFormData((Map) content)) { - contentType = MediaType.APPLICATION_FORM_URLENCODED; - } - if (contentType == null && content instanceof Serializable) { - contentType = new MediaType("application", "x-java-serialized-object"); + if (content instanceof Map){ + Map multiValueMap = (Map) content; + if (!(content instanceof MultiValueMap)){ + multiValueMap = this.convertToMultipartValueMap((Map) content); + } + if (this.isMultipart((MultiValueMap)multiValueMap)){ + contentType = MediaType.MULTIPART_FORM_DATA; + } else { + contentType = MediaType.APPLICATION_FORM_URLENCODED; + //contentType = new MediaType("application", "x-java-serialized-object"); + } } } if (contentType == null) { @@ -292,17 +303,52 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe private MediaType resolveContentType(String content, String charset) { return new MediaType("text", "plain", Charset.forName(charset)); } - + + @SuppressWarnings("unchecked") + private MultiValueMap convertToMultipartValueMap(Map simpleContentMap){ + MultiValueMap multipartValueMap = new LinkedMultiValueMap(); + try { + for (String key : simpleContentMap.keySet()) { + Object value = simpleContentMap.get(key); + if (value != null){ + if (value instanceof Object[]){ + Object[] valueArray = (Object[]) value; + for (Object objectValue : valueArray) { + if (objectValue != null){ + multipartValueMap.add(key, objectValue); + } + } + } + else if (value instanceof Collection){ + Collection stringCollection = (Collection) value; + for (Object objectValue : stringCollection) { + if (objectValue != null){ + multipartValueMap.add(key, objectValue); + } + } + } + else { + multipartValueMap.add(key, value); + } + } + } + } catch (ClassCastException cce) { + throw new MessageConversionException("Content map contains unsupported type for 'key'.", cce); + } + + return multipartValueMap; + } /** * If all keys are Strings, we'll consider the Map to be form data. */ - private boolean isFormData(Map map) { - for (Object key : map.keySet()) { - if (!(key instanceof String)) { - return false; + private boolean isMultipart(MultiValueMap> map) { + for (List listValues : map.values()) { + for (Object listValue : listValues) { + if (!(listValue instanceof String)) { + return true; + } } } - return true; + return false; } - } diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/HttpRequestExecutingMessageHandlerTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/HttpRequestExecutingMessageHandlerTests.java new file mode 100644 index 0000000000..bc090b91cf --- /dev/null +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/HttpRequestExecutingMessageHandlerTests.java @@ -0,0 +1,155 @@ +/* + * 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.http; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import org.springframework.util.MultiValueMap; +import org.springframework.util.ReflectionUtils; + +/** + * @author Oleg Zhurakousky + * + */ +public class HttpRequestExecutingMessageHandlerTests { + + @SuppressWarnings("unchecked") + @Test + public void validateMapWithObjectsConversionToMvp() throws Exception { + HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("localhost"); + Method convertToMultipartValueMap = ReflectionUtils.findMethod(handler.getClass(), "convertToMultipartValueMap", Map.class); + convertToMultipartValueMap.setAccessible(true); + Map simpleMap = new HashMap(); + simpleMap.put("city", "Philadelphia"); + simpleMap.put("state", "PA"); + MultiValueMap multiValueMap = (MultiValueMap) convertToMultipartValueMap.invoke(handler, simpleMap); + assertEquals("Philadelphia", multiValueMap.get("city").iterator().next()); + assertEquals("PA", multiValueMap.get("state").iterator().next()); + } + + @SuppressWarnings("unchecked") + @Test + public void validateMapWithArraysConversionToMvp() throws Exception { + HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("localhost"); + Method convertToMultipartValueMap = ReflectionUtils.findMethod(handler.getClass(), "convertToMultipartValueMap", Map.class); + convertToMultipartValueMap.setAccessible(true); + Map simpleMap = new HashMap(); + simpleMap.put("city", new String[]{"Philadelphia", "Ambler"}); + simpleMap.put("state", "PA"); + MultiValueMap multiValueMap = (MultiValueMap) convertToMultipartValueMap.invoke(handler, simpleMap); + assertEquals("Philadelphia", multiValueMap.get("city").get(0)); + assertEquals("Ambler", multiValueMap.get("city").get(1)); + assertEquals("PA", multiValueMap.get("state").iterator().next()); + } + + @SuppressWarnings("unchecked") + @Test + public void validateMapWithObjectArraysConversionToMvp() throws Exception { + HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("localhost"); + Method convertToMultipartValueMap = ReflectionUtils.findMethod(handler.getClass(), "convertToMultipartValueMap", Map.class); + convertToMultipartValueMap.setAccessible(true); + Map simpleMap = new HashMap(); + City philadelphia = new City(); + City ambler = new City(); + simpleMap.put("city", new City[]{philadelphia, ambler}); + simpleMap.put("state", "PA"); + MultiValueMap multiValueMap = (MultiValueMap) convertToMultipartValueMap.invoke(handler, simpleMap); + assertEquals(philadelphia, multiValueMap.get("city").get(0)); + assertEquals(ambler, multiValueMap.get("city").get(1)); + assertEquals("PA", multiValueMap.get("state").iterator().next()); + } + @SuppressWarnings("unchecked") + @Test + public void validateMapWithObjectCollectionConversionToMvp() throws Exception { + HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("localhost"); + Method convertToMultipartValueMap = ReflectionUtils.findMethod(handler.getClass(), "convertToMultipartValueMap", Map.class); + convertToMultipartValueMap.setAccessible(true); + Map simpleMap = new HashMap(); + City philadelphia = new City(); + City ambler = new City(); + List cities = new LinkedList(); + cities.add(philadelphia); + cities.add(ambler); + simpleMap.put("city", cities); + simpleMap.put("state", "PA"); + MultiValueMap multiValueMap = (MultiValueMap) convertToMultipartValueMap.invoke(handler, simpleMap); + assertEquals(philadelphia, multiValueMap.get("city").get(0)); + assertEquals(ambler, multiValueMap.get("city").get(1)); + assertEquals("PA", multiValueMap.get("state").iterator().next()); + } + + @Test + public void validateMapWithNullValuesInCollectionConversionToMvp() throws Exception { + HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("localhost"); + Method convertToMultipartValueMap = ReflectionUtils.findMethod(handler.getClass(), "convertToMultipartValueMap", Map.class); + convertToMultipartValueMap.setAccessible(true); + Map simpleMap = new HashMap(); + City philadelphia = new City(); + List cities = new LinkedList(); + cities.add(philadelphia); + cities.add(null); + simpleMap.put("city", cities); + simpleMap.put("state", "PA"); + MultiValueMap multiValueMap = (MultiValueMap) convertToMultipartValueMap.invoke(handler, simpleMap); + assertEquals(1, multiValueMap.get("city").size()); + assertEquals(philadelphia, multiValueMap.get("city").get(0)); + assertEquals("PA", multiValueMap.get("state").iterator().next()); + } + @Test + public void validateMapWithNullValuesInArrayConversionToMvp() throws Exception { + HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("localhost"); + Method convertToMultipartValueMap = ReflectionUtils.findMethod(handler.getClass(), "convertToMultipartValueMap", Map.class); + convertToMultipartValueMap.setAccessible(true); + Map simpleMap = new HashMap(); + + City philadelphia = new City(); + City[] cities = new City[]{philadelphia, null}; + simpleMap.put("city", cities); + simpleMap.put("state", "PA"); + MultiValueMap multiValueMap = (MultiValueMap) convertToMultipartValueMap.invoke(handler, simpleMap); + assertEquals(1, multiValueMap.get("city").size()); + assertEquals(philadelphia, multiValueMap.get("city").get(0)); + assertEquals("PA", multiValueMap.get("state").iterator().next()); + } + + @Test(expected=InvocationTargetException.class) + public void validateMapWithNonStrigKeysConversionToMvp() throws Exception { + HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("localhost"); + Method convertToMultipartValueMap = ReflectionUtils.findMethod(handler.getClass(), "convertToMultipartValueMap", Map.class); + convertToMultipartValueMap.setAccessible(true); + Map simpleMap = new HashMap(); + City philadelphia = new City(); + City ambler = new City(); + List cities = new LinkedList(); + cities.add(philadelphia); + cities.add(ambler); + simpleMap.put(1, cities); + simpleMap.put(2, "PA"); + convertToMultipartValueMap.invoke(handler, simpleMap); + } + + public static class City{} +}