diff --git a/spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java index a881340cad..02ba3b6fce 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -42,26 +42,37 @@ import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; /** - * Implementation of {@link HttpMessageConverter} that can handle form data, including multipart form data (i.e. file - * uploads). + * Implementation of {@link HttpMessageConverter} to read and write 'normal' HTML + * forms and also to write (but not read) multipart data (e.g. file uploads). * - *

This converter can write the {@code application/x-www-form-urlencoded} and {@code multipart/form-data} media - * types, and read the {@code application/x-www-form-urlencoded}) media type (but not {@code multipart/form-data}). + *

In other words this converter can read and write the + * {@code "application/x-www-form-urlencoded"} media type as + * {@link MultiValueMap MultiValueMap<String, String>} and it can also + * write (but not read) the {@code "multipart/form-data"} media type as + * {@link MultiValueMap MultiValueMap<String, Object>}. * - *

In other words, this converter can read and write 'normal' HTML forms (as {@link MultiValueMap - * MultiValueMap<String, String>}), and it can write multipart form (as {@link MultiValueMap - * MultiValueMap<String, Object>}. When writing multipart, this converter uses other {@link HttpMessageConverter - * HttpMessageConverters} to write the respective MIME parts. By default, basic converters are registered (supporting - * {@code Strings} and {@code Resources}, for instance); these can be overridden by setting the {@link - * #setPartConverters(java.util.List) partConverters} property. + *

When writing multipart data this converter uses other + * {@link HttpMessageConverter HttpMessageConverters} to write the respective + * MIME parts. By default basic converters are registered (for {@code Strings} + * and {@code Resources}). These can be overridden through the + * {@link #setPartConverters(java.util.List) partConverters} property. * - *

For example, the following snippet shows how to submit an HTML form:

 RestTemplate template =
- * new RestTemplate(); // FormHttpMessageConverter is configured by default MultiValueMap<String, String> form =
- * new LinkedMultiValueMap<String, String>(); form.add("field 1", "value 1"); form.add("field 2", "value 2");
- * form.add("field 2", "value 3"); template.postForLocation("http://example.com/myForm", form); 

The following - * snippet shows how to do a file upload:

 MultiValueMap<String, Object> parts = new
- * LinkedMultiValueMap<String, Object>(); parts.add("field 1", "value 1"); parts.add("file", new
- * ClassPathResource("myFile.jpg")); template.postForLocation("http://example.com/myFileUpload", parts); 
+ *

For example the following snippet shows how to submit an HTML form: + *

+ * RestTemplate template = new RestTemplate(); // FormHttpMessageConverter is configured by default
+ * MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
+ * form.add("field 1", "value 1"); form.add("field 2", "value 2");
+ * form.add("field 2", "value 3");
+ * template.postForLocation("http://example.com/myForm", form);
+ * 
+ * + *

The following snippet shows how to do a file upload: + *

+ * MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
+ * parts.add("field 1", "value 1");
+ * parts.add("file", new ClassPathResource("myFile.jpg"));
+ * template.postForLocation("http://example.com/myFileUpload", parts);
+ * 
* *

Some methods in this class were inspired by {@code org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity}. * @@ -77,7 +88,7 @@ public class FormHttpMessageConverter implements HttpMessageConverterBy default this is set to "UTF-8". + */ + public void setCharset(Charset charset) { + this.charset = charset; + } + + /** + * Set the list of {@link MediaType} objects supported by this converter. + */ + public void setSupportedMediaTypes(List supportedMediaTypes) { + this.supportedMediaTypes = supportedMediaTypes; + } + + @Override + public List getSupportedMediaTypes() { + return Collections.unmodifiableList(this.supportedMediaTypes); + } + + /** + * Set the message body converters to use. These converters are used to + * convert objects to MIME parts. */ public final void setPartConverters(List> partConverters) { Assert.notEmpty(partConverters, "'partConverters' must not be empty"); @@ -107,19 +140,14 @@ public class FormHttpMessageConverter implements HttpMessageConverter partConverter) { Assert.notNull(partConverter, "'partConverter' must not be NULL"); this.partConverters.add(partConverter); } - /** - * Sets the character set used for writing form data. - */ - public void setCharset(Charset charset) { - this.charset = charset; - } @Override public boolean canRead(Class clazz, MediaType mediaType) { @@ -155,18 +183,6 @@ public class FormHttpMessageConverter implements HttpMessageConverter supportedMediaTypes) { - this.supportedMediaTypes = supportedMediaTypes; - } - - @Override - public List getSupportedMediaTypes() { - return Collections.unmodifiableList(this.supportedMediaTypes); - } - @Override public MultiValueMap read(Class> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { @@ -197,6 +213,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter map, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { + if (!isMultipart(map, contentType)) { writeForm((MultiValueMap) map, contentType, outputMessage); } @@ -221,6 +238,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter form, MediaType contentType, HttpOutputMessage outputMessage) throws IOException { + Charset charset; if (contentType != null) { outputMessage.getHeaders().setContentType(contentType); @@ -255,6 +273,7 @@ public class FormHttpMessageConverter implements HttpMessageConverter parts, HttpOutputMessage outputMessage) throws IOException { + byte[] boundary = generateMultipartBoundary(); Map parameters = Collections.singletonMap("boundary", new String(boundary, "US-ASCII")); @@ -303,12 +322,12 @@ public class FormHttpMessageConverter implements HttpMessageConverter messageConverter : partConverters) { if (messageConverter.canWrite(partType, partContentType)) { - HttpOutputMessage multipartOutputMessage = new MultipartHttpOutputMessage(os); - multipartOutputMessage.getHeaders().setContentDispositionFormData(name, getFilename(partBody)); + HttpOutputMessage multipartMessage = new MultipartHttpOutputMessage(os); + multipartMessage.getHeaders().setContentDispositionFormData(name, getFilename(partBody)); if (!partHeaders.isEmpty()) { - multipartOutputMessage.getHeaders().putAll(partHeaders); + multipartMessage.getHeaders().putAll(partHeaders); } - ((HttpMessageConverter) messageConverter).write(partBody, partContentType, multipartOutputMessage); + ((HttpMessageConverter) messageConverter).write(partBody, partContentType, multipartMessage); return; } } @@ -337,9 +356,9 @@ public class FormHttpMessageConverter implements HttpMessageConverter