|
28 | 28 | import java.util.LinkedHashMap;
|
29 | 29 | import java.util.List;
|
30 | 30 | import java.util.Map;
|
31 |
| -import java.util.function.BiConsumer; |
32 | 31 |
|
33 | 32 | import org.springframework.core.io.Resource;
|
34 | 33 | import org.springframework.http.ContentDisposition;
|
|
51 | 50 | * Implementation of {@link HttpMessageConverter} to read and write 'normal' HTML
|
52 | 51 | * forms and also to write (but not read) multipart data (e.g. file uploads).
|
53 | 52 | *
|
54 |
| - * <p>In other words, this converter can read and write the |
55 |
| - * {@code "application/x-www-form-urlencoded"} media type as |
56 |
| - * {@code Map<String, String>} or as |
57 |
| - * {@link MultiValueMap MultiValueMap<String, String>}, and it can also |
58 |
| - * write (but not read) the {@code "multipart/form-data"} and |
59 |
| - * {@code "multipart/mixed"} media types as {@code Map<String, Object>} or as |
60 |
| - * {@link MultiValueMap MultiValueMap<String, Object>}. |
| 53 | + * <p> |
| 54 | + * The following table shows an overview of the supported media and class types. |
| 55 | + * <table border="1"> |
| 56 | + * <tr><th>Media type</th><th>Read</th><th>Write</th></tr> |
| 57 | + * <tr> |
| 58 | + * <td>{@code "application/x-www-form-urlencoded"}</td> |
| 59 | + * <td>{@link MultiValueMap MultiValueMap<String, String>}</td> |
| 60 | + * <td>{@link Map Map<String, String>}<br> |
| 61 | + * {@link MultiValueMap MultiValueMap<String, String>}</td> |
| 62 | + * </tr> |
| 63 | + * <tr> |
| 64 | + * <td>{@code "multipart/form-data"}<br> |
| 65 | + * {@code "multipart/mixed"}</td> |
| 66 | + * <td>Unsupported</td> |
| 67 | + * <td>{@link Map Map<String, Object>}<br> |
| 68 | + * {@link MultiValueMap MultiValueMap<String, Object>}</td> |
| 69 | + * </tr> |
| 70 | + * </table> |
61 | 71 | *
|
62 | 72 | * <h3>Multipart Data</h3>
|
63 | 73 | *
|
|
158 | 168 | * {@code org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity}.
|
159 | 169 | *
|
160 | 170 | * <p>As of 6.2, the {@code FormHttpMessageConverter} is parameterized over
|
161 |
| - * {@code Map<String, ?>}, whereas before it was {@code MultiValueMap<String, ?>}, |
162 |
| - * in order to support single-value maps. |
| 171 | + * {@code Map<String, ?>} in order to support writing single-value maps. |
| 172 | + * Before 6.2, this class was parameterized over {@code MultiValueMap<String, ?>}. |
163 | 173 | *
|
164 | 174 | * @author Arjen Poutsma
|
165 | 175 | * @author Rossen Stoyanchev
|
@@ -312,7 +322,7 @@ public void setMultipartCharset(Charset charset) {
|
312 | 322 |
|
313 | 323 | @Override
|
314 | 324 | public boolean canRead(Class<?> clazz, @Nullable MediaType mediaType) {
|
315 |
| - if (!Map.class.isAssignableFrom(clazz)) { |
| 325 | + if (!MultiValueMap.class.isAssignableFrom(clazz)) { |
316 | 326 | return false;
|
317 | 327 | }
|
318 | 328 | if (mediaType == null) {
|
@@ -354,32 +364,21 @@ public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
|
354 | 364 | Charset charset = (contentType != null && contentType.getCharset() != null ?
|
355 | 365 | contentType.getCharset() : this.charset);
|
356 | 366 | String body = StreamUtils.copyToString(inputMessage.getBody(), charset);
|
357 |
| - String[] pairs = StringUtils.tokenizeToStringArray(body, "&"); |
358 |
| - |
359 |
| - if (clazz == null || MultiValueMap.class.isAssignableFrom(clazz)) { |
360 |
| - MultiValueMap<String, String> result = new LinkedMultiValueMap<>(pairs.length); |
361 |
| - readToMap(pairs, charset, result::add); |
362 |
| - return result; |
363 |
| - } |
364 |
| - else { |
365 |
| - Map<String, String> result = CollectionUtils.newLinkedHashMap(pairs.length); |
366 |
| - readToMap(pairs, charset, result::putIfAbsent); |
367 |
| - return result; |
368 |
| - } |
369 |
| - } |
370 | 367 |
|
371 |
| - private static void readToMap(String[] pairs, Charset charset, BiConsumer<String, String> addFunction) { |
| 368 | + String[] pairs = StringUtils.tokenizeToStringArray(body, "&"); |
| 369 | + MultiValueMap<String, String> result = new LinkedMultiValueMap<>(pairs.length); |
372 | 370 | for (String pair : pairs) {
|
373 | 371 | int idx = pair.indexOf('=');
|
374 | 372 | if (idx == -1) {
|
375 |
| - addFunction.accept(URLDecoder.decode(pair, charset), null); |
| 373 | + result.add(URLDecoder.decode(pair, charset), null); |
376 | 374 | }
|
377 | 375 | else {
|
378 | 376 | String name = URLDecoder.decode(pair.substring(0, idx), charset);
|
379 | 377 | String value = URLDecoder.decode(pair.substring(idx + 1), charset);
|
380 |
| - addFunction.accept(name, value); |
| 378 | + result.add(name, value); |
381 | 379 | }
|
382 | 380 | }
|
| 381 | + return result; |
383 | 382 | }
|
384 | 383 |
|
385 | 384 | @Override
|
|
0 commit comments