INT-1044 added support for form data Maps in POST requests
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* 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.
|
||||
@@ -20,12 +20,18 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.integration.core.Message;
|
||||
@@ -107,6 +113,7 @@ public class DefaultOutboundRequestMapper implements OutboundRequestMapper {
|
||||
return this.createRequestFromMessage(message, url, requestMethod);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private HttpRequest createRequestFromPayload(Object payload, URL url, String requestMethod) throws Exception {
|
||||
ByteArrayOutputStream requestBody = new ByteArrayOutputStream();
|
||||
String contentType = null;
|
||||
@@ -160,6 +167,7 @@ public class DefaultOutboundRequestMapper implements OutboundRequestMapper {
|
||||
return parameterMap;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private String writeToRequestBody(Object object, ByteArrayOutputStream byteStream) throws Exception {
|
||||
String contentType = null;
|
||||
if (object instanceof byte[]) {
|
||||
@@ -170,17 +178,89 @@ public class DefaultOutboundRequestMapper implements OutboundRequestMapper {
|
||||
byteStream.write(((String) object).getBytes(this.charset));
|
||||
contentType = "text/plain; charset=" + this.charset;
|
||||
}
|
||||
else if (object instanceof Serializable) {
|
||||
byteStream.write(this.serializeObject((Serializable) object));
|
||||
contentType = "application/x-java-serialized-object";
|
||||
}
|
||||
else {
|
||||
if (object instanceof Map && isFormData((Map) object)) {
|
||||
byte[] data = this.formDataAsBytes((Map) object);
|
||||
if (data != null) {
|
||||
byteStream.write(data);
|
||||
contentType = "application/x-www-form-urlencoded";
|
||||
}
|
||||
}
|
||||
if (contentType == null && object instanceof Serializable) {
|
||||
byteStream.write(this.serializeObject((Serializable) object));
|
||||
contentType = "application/x-java-serialized-object";
|
||||
}
|
||||
}
|
||||
if (contentType == null) {
|
||||
throw new IllegalArgumentException("payload must be a byte array, " +
|
||||
"String, or Serializable object for a 'POST' or 'PUT' request");
|
||||
"String, Map, or Serializable object for a 'POST' or 'PUT' request");
|
||||
}
|
||||
return contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* If all keys are Strings, we'll consider the Map to be form data.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isFormData(Map map) {
|
||||
for (Object key : map.keySet()) {
|
||||
if (!(key instanceof String)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private byte[] formDataAsBytes(Map form) throws UnsupportedEncodingException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Iterator<?> nameIterator = form.keySet().iterator();
|
||||
while (nameIterator.hasNext()) {
|
||||
Object next = nameIterator.next();
|
||||
Assert.isTrue(next instanceof String, "Form map keys must be Strings.");
|
||||
String name = (String) next;
|
||||
Object value = form.get(name);
|
||||
if (value == null) {
|
||||
builder.append(URLEncoder.encode(name, this.charset));
|
||||
}
|
||||
else {
|
||||
List<String> values = null;
|
||||
if (value instanceof String) {
|
||||
values = Collections.singletonList((String) value);
|
||||
}
|
||||
else if (value instanceof String[]) {
|
||||
values = Arrays.asList((String[]) value);
|
||||
}
|
||||
else {
|
||||
if (!(value instanceof Iterable)) {
|
||||
return null;
|
||||
}
|
||||
Iterator iterator = ((Iterable) value).iterator();
|
||||
values = new ArrayList<String>();
|
||||
while (iterator.hasNext()) {
|
||||
Object nextValue = iterator.next();
|
||||
if (!(nextValue instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
values.add((String) nextValue);
|
||||
}
|
||||
}
|
||||
Iterator<String> valueIterator = values.iterator();
|
||||
builder.append(URLEncoder.encode(name, this.charset));
|
||||
while (valueIterator.hasNext()) {
|
||||
builder.append('=' + URLEncoder.encode(valueIterator.next(), this.charset));
|
||||
if (valueIterator.hasNext()) {
|
||||
builder.append('&' + URLEncoder.encode(name, this.charset));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nameIterator.hasNext()) {
|
||||
builder.append('&');
|
||||
}
|
||||
}
|
||||
return builder.toString().getBytes(this.charset);
|
||||
}
|
||||
|
||||
private byte[] serializeObject(Serializable object) throws IOException {
|
||||
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
|
||||
ObjectOutputStream objectStream = new ObjectOutputStream(byteStream);
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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 org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class DefaultOutboundRequestMapperTests {
|
||||
|
||||
@Test
|
||||
public void simpleStringValueFormData() throws Exception {
|
||||
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
|
||||
Map<String, String> form = new LinkedHashMap<String, String>();
|
||||
form.put("a", "1");
|
||||
form.put("b", "2");
|
||||
form.put("c", "3");
|
||||
Message<?> message = MessageBuilder.withPayload(form).build();
|
||||
HttpRequest request = mapper.fromMessage(message);
|
||||
String bodyText = request.getBody().toString("UTF-8");
|
||||
assertEquals("a=1&b=2&c=3", bodyText);
|
||||
assertEquals("application/x-www-form-urlencoded", request.getContentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void stringArrayValueFormData() throws Exception {
|
||||
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
|
||||
Map form = new LinkedHashMap();
|
||||
form.put("a", new String[] { "1", "2", "3" });
|
||||
form.put("b", "4");
|
||||
form.put("c", new String[] { "5" });
|
||||
form.put("d", "6");
|
||||
Message<?> message = MessageBuilder.withPayload(form).build();
|
||||
HttpRequest request = mapper.fromMessage(message);
|
||||
String bodyText = request.getBody().toString("UTF-8");
|
||||
assertEquals("a=1&a=2&a=3&b=4&c=5&d=6", bodyText);
|
||||
assertEquals("application/x-www-form-urlencoded", request.getContentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void stringListValueFormData() throws Exception {
|
||||
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
|
||||
Map form = new LinkedHashMap();
|
||||
List<String> listA = new ArrayList<String>();
|
||||
listA.add("1");
|
||||
listA.add("2");
|
||||
form.put("a", listA);
|
||||
form.put("b", Collections.EMPTY_LIST);
|
||||
form.put("c", Collections.singletonList("3"));
|
||||
Message<?> message = MessageBuilder.withPayload(form).build();
|
||||
HttpRequest request = mapper.fromMessage(message);
|
||||
String bodyText = request.getBody().toString("UTF-8");
|
||||
assertEquals("a=1&a=2&b&c=3", bodyText);
|
||||
assertEquals("application/x-www-form-urlencoded", request.getContentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void nameOnlyWithNullValues() throws Exception {
|
||||
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
|
||||
Map form = new LinkedHashMap();
|
||||
form.put("a", null);
|
||||
form.put("b", "foo");
|
||||
form.put("c", null);
|
||||
Message<?> message = MessageBuilder.withPayload(form).build();
|
||||
HttpRequest request = mapper.fromMessage(message);
|
||||
String bodyText = request.getBody().toString("UTF-8");
|
||||
assertEquals("a&b=foo&c", bodyText);
|
||||
assertEquals("application/x-www-form-urlencoded", request.getContentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void encodedFormData() throws Exception {
|
||||
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
|
||||
Map<String, String> form = new LinkedHashMap<String, String>();
|
||||
form.put("a", "1 + 2 + 3");
|
||||
form.put("b", "4+5");
|
||||
form.put("c", "97%");
|
||||
Message<?> message = MessageBuilder.withPayload(form).build();
|
||||
HttpRequest request = mapper.fromMessage(message);
|
||||
String bodyText = request.getBody().toString("UTF-8");
|
||||
assertEquals("a=1+%2B+2+%2B+3&b=4%2B5&c=97%25", bodyText);
|
||||
assertEquals("application/x-www-form-urlencoded", request.getContentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void nonFormDataInMap() throws Exception {
|
||||
DefaultOutboundRequestMapper mapper = new DefaultOutboundRequestMapper(new URL("http://example.org"));
|
||||
Map<String, TestBean> form = new LinkedHashMap<String, TestBean>();
|
||||
form.put("A", new TestBean());
|
||||
form.put("B", new TestBean());
|
||||
Message<?> message = MessageBuilder.withPayload(form).build();
|
||||
HttpRequest request = mapper.fromMessage(message);
|
||||
byte[] body = request.getBody().toByteArray();
|
||||
ByteArrayInputStream byteStream = new ByteArrayInputStream(body);
|
||||
Object result = new ObjectInputStream(byteStream).readObject();
|
||||
assertEquals(LinkedHashMap.class, result.getClass());
|
||||
Map<String, TestBean> resultMap = (Map<String, TestBean>) result;
|
||||
assertEquals(2, resultMap.size());
|
||||
assertEquals(TestBean.class, resultMap.get("A").getClass());
|
||||
assertEquals(TestBean.class, resultMap.get("B").getClass());
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class TestBean implements Serializable {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user