Apply HttpMessageConverter auto-config to form part converters
Closes gh-3525
This commit is contained in:
parent
30f24eac0a
commit
f770dbab52
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.web;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -24,9 +25,11 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||
|
||||
|
@ -45,6 +48,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupp
|
|||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @see #HttpMessageConverters(HttpMessageConverter...)
|
||||
* @see #HttpMessageConverters(Collection)
|
||||
* @see #getConverters()
|
||||
|
@ -97,25 +101,37 @@ public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>>
|
|||
*/
|
||||
public HttpMessageConverters(boolean addDefaultConverters,
|
||||
Collection<HttpMessageConverter<?>> converters) {
|
||||
List<HttpMessageConverter<?>> combined = getCombinedConverters(converters,
|
||||
addDefaultConverters ? getDefaultConverters()
|
||||
: Collections.<HttpMessageConverter<?>>emptyList());
|
||||
combined = postProcessConverters(combined);
|
||||
this.converters = Collections.unmodifiableList(combined);
|
||||
}
|
||||
|
||||
private List<HttpMessageConverter<?>> getCombinedConverters(
|
||||
Collection<HttpMessageConverter<?>> converters,
|
||||
List<HttpMessageConverter<?>> defaultConverters) {
|
||||
List<HttpMessageConverter<?>> combined = new ArrayList<HttpMessageConverter<?>>();
|
||||
List<HttpMessageConverter<?>> processing = new ArrayList<HttpMessageConverter<?>>(
|
||||
converters);
|
||||
if (addDefaultConverters) {
|
||||
for (HttpMessageConverter<?> defaultConverter : getDefaultConverters()) {
|
||||
Iterator<HttpMessageConverter<?>> iterator = processing.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
HttpMessageConverter<?> candidate = iterator.next();
|
||||
if (isReplacement(defaultConverter, candidate)) {
|
||||
combined.add(candidate);
|
||||
iterator.remove();
|
||||
}
|
||||
for (HttpMessageConverter<?> defaultConverter : defaultConverters) {
|
||||
Iterator<HttpMessageConverter<?>> iterator = processing.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
HttpMessageConverter<?> candidate = iterator.next();
|
||||
if (isReplacement(defaultConverter, candidate)) {
|
||||
combined.add(candidate);
|
||||
iterator.remove();
|
||||
}
|
||||
combined.add(defaultConverter);
|
||||
}
|
||||
combined.add(defaultConverter);
|
||||
if (defaultConverter instanceof AllEncompassingFormHttpMessageConverter) {
|
||||
configurePartConverters(
|
||||
(AllEncompassingFormHttpMessageConverter) defaultConverter,
|
||||
converters);
|
||||
}
|
||||
}
|
||||
combined.addAll(0, processing);
|
||||
combined = postProcessConverters(combined);
|
||||
this.converters = Collections.unmodifiableList(combined);
|
||||
return combined;
|
||||
}
|
||||
|
||||
private boolean isReplacement(HttpMessageConverter<?> defaultConverter,
|
||||
|
@ -128,6 +144,28 @@ public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>>
|
|||
return ClassUtils.isAssignableValue(defaultConverter.getClass(), candidate);
|
||||
}
|
||||
|
||||
private void configurePartConverters(
|
||||
AllEncompassingFormHttpMessageConverter formConverter,
|
||||
Collection<HttpMessageConverter<?>> converters) {
|
||||
List<HttpMessageConverter<?>> partConverters = extractPartConverters(
|
||||
formConverter);
|
||||
List<HttpMessageConverter<?>> combinedConverters = getCombinedConverters(
|
||||
converters, partConverters);
|
||||
combinedConverters = postProcessPartConverters(combinedConverters);
|
||||
formConverter.setPartConverters(combinedConverters);
|
||||
}
|
||||
|
||||
private List<HttpMessageConverter<?>> extractPartConverters(
|
||||
AllEncompassingFormHttpMessageConverter formConverter) {
|
||||
Field field = ReflectionUtils.findField(
|
||||
AllEncompassingFormHttpMessageConverter.class, "partConverters");
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<HttpMessageConverter<?>> partConverters = (List<HttpMessageConverter<?>>) ReflectionUtils
|
||||
.getField(field, formConverter);
|
||||
return partConverters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that can be used to post-process the {@link HttpMessageConverter} list
|
||||
* before it is used.
|
||||
|
@ -139,6 +177,19 @@ public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>>
|
|||
return converters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that can be used to post-process the {@link HttpMessageConverter} list
|
||||
* before it is used to configure the part converters of
|
||||
* {@link AllEncompassingFormHttpMessageConverter}.
|
||||
* @param converters a mutable list of the converters that will be used.
|
||||
* @return the final converts list to use
|
||||
* @since 1.3.0
|
||||
*/
|
||||
protected List<HttpMessageConverter<?>> postProcessPartConverters(
|
||||
List<HttpMessageConverter<?>> converters) {
|
||||
return converters;
|
||||
}
|
||||
|
||||
private List<HttpMessageConverter<?>> getDefaultConverters() {
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
if (ClassUtils.isPresent("org.springframework.web.servlet.config.annotation."
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.web;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -32,6 +33,7 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
|
|||
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -100,6 +102,19 @@ public class HttpMessageConvertersTests {
|
|||
assertEquals(converter2, converters.getConverters().get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertersAreAddedToFormPartConverter() {
|
||||
HttpMessageConverter<?> converter1 = mock(HttpMessageConverter.class);
|
||||
HttpMessageConverter<?> converter2 = mock(HttpMessageConverter.class);
|
||||
List<HttpMessageConverter<?>> converters = new HttpMessageConverters(converter1,
|
||||
converter2).getConverters();
|
||||
List<HttpMessageConverter<?>> partConverters = extractFormPartConverters(
|
||||
converters);
|
||||
assertTrue(partConverters.contains(converter1));
|
||||
assertEquals(converter1, partConverters.get(0));
|
||||
assertEquals(converter2, partConverters.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessConverters() throws Exception {
|
||||
HttpMessageConverters converters = new HttpMessageConverters() {
|
||||
|
@ -129,4 +144,52 @@ public class HttpMessageConvertersTests {
|
|||
MappingJackson2HttpMessageConverter.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessPartConverters() throws Exception {
|
||||
HttpMessageConverters converters = new HttpMessageConverters() {
|
||||
@Override
|
||||
protected List<HttpMessageConverter<?>> postProcessPartConverters(
|
||||
List<HttpMessageConverter<?>> converters) {
|
||||
for (Iterator<HttpMessageConverter<?>> iterator = converters
|
||||
.iterator(); iterator.hasNext();) {
|
||||
if (iterator
|
||||
.next() instanceof MappingJackson2XmlHttpMessageConverter) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
return converters;
|
||||
};
|
||||
};
|
||||
List<Class<?>> converterClasses = new ArrayList<Class<?>>();
|
||||
for (HttpMessageConverter<?> converter : extractFormPartConverters(
|
||||
converters.getConverters())) {
|
||||
converterClasses.add(converter.getClass());
|
||||
}
|
||||
assertThat(converterClasses,
|
||||
equalTo(Arrays.<Class<?>>asList(ByteArrayHttpMessageConverter.class,
|
||||
StringHttpMessageConverter.class,
|
||||
ResourceHttpMessageConverter.class,
|
||||
SourceHttpMessageConverter.class,
|
||||
MappingJackson2HttpMessageConverter.class)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<HttpMessageConverter<?>> extractFormPartConverters(
|
||||
List<HttpMessageConverter<?>> converters) {
|
||||
AllEncompassingFormHttpMessageConverter formConverter = findFormConverter(
|
||||
converters);
|
||||
return (List<HttpMessageConverter<?>>) ReflectionTestUtils.getField(formConverter,
|
||||
"partConverters");
|
||||
}
|
||||
|
||||
private AllEncompassingFormHttpMessageConverter findFormConverter(
|
||||
Collection<HttpMessageConverter<?>> converters) {
|
||||
for (HttpMessageConverter<?> converter : converters) {
|
||||
if (converter instanceof AllEncompassingFormHttpMessageConverter) {
|
||||
return (AllEncompassingFormHttpMessageConverter) converter;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue