Commit 34cbcf5e authored by Phillip Webb's avatar Phillip Webb

Support better HttpMessageConverters manipulation

Add additional constructor and a protected postProcessConverters method
to make it easier to manipulate the final converter list that will
be used.

Fixes gh-1482
parent 0c0a0a77
...@@ -69,26 +69,54 @@ public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>> ...@@ -69,26 +69,54 @@ public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>>
* converters. * converters.
* @param additionalConverters additional converters to be added. Items are added just * @param additionalConverters additional converters to be added. Items are added just
* before any default converter of the same type (or at the front of the list if no * before any default converter of the same type (or at the front of the list if no
* default converter is found) The {@link #getConverters()} methods can be used for * default converter is found) The {@link #postProcessConverters(List)} method can be
* further converter manipulation. * used for further converter manipulation.
*/ */
public HttpMessageConverters(Collection<HttpMessageConverter<?>> additionalConverters) { public HttpMessageConverters(Collection<HttpMessageConverter<?>> additionalConverters) {
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>(); this(true, additionalConverters);
}
/**
* Create a new {@link HttpMessageConverters} instance with the specified converters.
* @param addDefaultConverters if default converters should be added
* @param converters converters to be added. Items are added just before any default
* converter of the same type (or at the front of the list if no default converter is
* found) The {@link #postProcessConverters(List)} method can be used for further
* converter manipulation.
*/
public HttpMessageConverters(boolean addDefaultConverters,
Collection<HttpMessageConverter<?>> converters) {
List<HttpMessageConverter<?>> combined = new ArrayList<HttpMessageConverter<?>>();
List<HttpMessageConverter<?>> processing = new ArrayList<HttpMessageConverter<?>>( List<HttpMessageConverter<?>> processing = new ArrayList<HttpMessageConverter<?>>(
additionalConverters); converters);
for (HttpMessageConverter<?> defaultConverter : getDefaultConverters()) { if (addDefaultConverters) {
Iterator<HttpMessageConverter<?>> iterator = processing.iterator(); for (HttpMessageConverter<?> defaultConverter : getDefaultConverters()) {
while (iterator.hasNext()) { Iterator<HttpMessageConverter<?>> iterator = processing.iterator();
HttpMessageConverter<?> candidate = iterator.next(); while (iterator.hasNext()) {
if (ClassUtils.isAssignableValue(defaultConverter.getClass(), candidate)) { HttpMessageConverter<?> candidate = iterator.next();
converters.add(candidate); if (ClassUtils.isAssignableValue(defaultConverter.getClass(),
iterator.remove(); candidate)) {
combined.add(candidate);
iterator.remove();
}
} }
combined.add(defaultConverter);
} }
converters.add(defaultConverter);
} }
converters.addAll(0, processing); combined.addAll(0, processing);
this.converters = Collections.unmodifiableList(converters); combined = postProcessConverters(combined);
this.converters = Collections.unmodifiableList(combined);
}
/**
* Method that can be used to post-process the {@link HttpMessageConverter} list
* before it is used.
* @param converters a mutable list of the converters that will be used.
* @return the final converts list to use
*/
protected List<HttpMessageConverter<?>> postProcessConverters(
List<HttpMessageConverter<?>> converters) {
return converters;
} }
private List<HttpMessageConverter<?>> getDefaultConverters() { private List<HttpMessageConverter<?>> getDefaultConverters() {
...@@ -127,8 +155,8 @@ public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>> ...@@ -127,8 +155,8 @@ public class HttpMessageConverters implements Iterable<HttpMessageConverter<?>>
} }
/** /**
* Return a mutable list of the converters in the order that they will be registered. * Return an immutable list of the converters in the order that they will be
* Values in the list cannot be modified once the bean has been initialized. * registered.
* @return the converters * @return the converters
*/ */
public List<HttpMessageConverter<?>> getConverters() { public List<HttpMessageConverter<?>> getConverters() {
......
...@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.web; ...@@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.web;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator;
import java.util.List; import java.util.List;
import org.junit.Rule; import org.junit.Rule;
...@@ -97,4 +98,30 @@ public class HttpMessageConvertersTests { ...@@ -97,4 +98,30 @@ public class HttpMessageConvertersTests {
assertEquals(converter2, converters.getConverters().get(1)); assertEquals(converter2, converters.getConverters().get(1));
} }
@Test
public void postProcessConverters() throws Exception {
HttpMessageConverters converters = new HttpMessageConverters() {
@Override
protected List<HttpMessageConverter<?>> postProcessConverters(
List<HttpMessageConverter<?>> converters) {
for (Iterator<HttpMessageConverter<?>> iterator = converters.iterator(); iterator
.hasNext();) {
if (iterator.next() instanceof Jaxb2RootElementHttpMessageConverter) {
iterator.remove();
}
}
return converters;
};
};
List<Class<?>> converterClasses = new ArrayList<Class<?>>();
for (HttpMessageConverter<?> converter : converters) {
converterClasses.add(converter.getClass());
}
assertThat(converterClasses, equalTo(Arrays.<Class<?>> asList(
ByteArrayHttpMessageConverter.class, StringHttpMessageConverter.class,
ResourceHttpMessageConverter.class, SourceHttpMessageConverter.class,
AllEncompassingFormHttpMessageConverter.class,
MappingJackson2HttpMessageConverter.class)));
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment