HttpMessageConverterUtils.java
package org.springframework.web;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.http.MediaType.APPLICATION_XML;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.PropertyResolver;
import org.springframework.http.MediaType;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.util.ClassUtils;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.accept.FixedContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.accept.ParameterContentNegotiationStrategy;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public final class HttpMessageConverterUtils {
private HttpMessageConverterUtils() {
}
/**
* Determine whether a JAXB binder is present on the classpath and can be loaded. Will return
* <tt>false</tt> if either the {@link javax.xml.bind.Binder} or one of its dependencies is not
* present or cannot be loaded.
*
* @param classLoader classLoader
* @return isJaxb2Present
*/
public static boolean isJaxb2Present(final ClassLoader classLoader) {
return ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
}
/**
* Determine whether Jackson 2.x is present on the classpath and can be loaded. Will return
* <tt>false</tt> if either the {@code com.fasterxml.jackson.databind.ObjectMapper},
* {@code com.fasterxml.jackson.core.JsonGenerator} or one of its dependencies is not present
* or cannot be loaded.
*
* @param classLoader classLoader
* @return isJackson2Present
*/
public static boolean isJackson2Present(final ClassLoader classLoader) {
return ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
}
/**
* Determine whether Jackson 1.x is present on the classpath and can be loaded. Will return
* <tt>false</tt> if either the {@code org.codehaus.jackson.map.ObjectMapper},
* {@code org.codehaus.jackson.JsonGenerator} or one of its dependencies is not present or
* cannot be loaded.
*
* @param classLoader classLoader
* @return isJacksonPresent
*/
@Deprecated
public static boolean isJacksonPresent(final ClassLoader classLoader) {
return ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", classLoader)
&& ClassUtils.isPresent("org.codehaus.jackson.JsonGenerator", classLoader);
}
/**
* Returns default {@link HttpMessageConverter} instances, i.e.:
*
* <ul>
* <li>{@linkplain ByteArrayHttpMessageConverter}</li>
* <li>{@linkplain StringHttpMessageConverter}</li>
* <li>{@linkplain ResourceHttpMessageConverter}</li>
* <li>{@linkplain Jaxb2RootElementHttpMessageConverter} (when JAXB is present)</li>
* <li>{@linkplain MappingJackson2HttpMessageConverter} (when Jackson 2.x is present)</li>
* <li>{org.springframework.http.converter.json.MappingJacksonHttpMessageConverter}
* (when Jackson 1.x is present and 2.x not)</li>
* </ul>
*
* <p>
* Note: It does not return all of the default converters defined in Spring, but just thus
* usable for exception responses.
* </p>
*
* @param propertyResolver propertyResolver
* @param objectMapper objectMapper
* @return httpMessageConverters
*/
public static List<HttpMessageConverter<?>> defaultHttpMessageConverters(
final PropertyResolver propertyResolver,
final Object objectMapper
) {
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
final List<HttpMessageConverter<?>> converters = new ArrayList<>();
final StringHttpMessageConverter stringConverter =
new StringHttpMessageConverter(Charset.forName("UTF-8"));
stringConverter.setWriteAcceptCharset(false); // See SPR-7316
converters.add(new ByteArrayHttpMessageConverter());
converters.add(stringConverter);
converters.add(new ResourceHttpMessageConverter());
if (isJaxb2Present(classLoader)) {
converters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (isJackson2Present(classLoader)) {
if (objectMapper == null) {
converters.add(new MappingJackson2HttpMessageConverter( //
cn.home1.oss.lib.common.Jackson2Utils.setupObjectMapper( //
propertyResolver, //
Jackson2ObjectMapperBuilder.json().build()) //
) //
);
} else {
converters.add(new MappingJackson2HttpMessageConverter( //
(com.fasterxml.jackson.databind.ObjectMapper) objectMapper) //
);
}
} else if (isJacksonPresent(classLoader)) {
try {
final String className = "org.springframework.http.converter.json.MappingJacksonHttpMessageConverter";
final Class<?> clazz = Class.forName(className);
converters.add((HttpMessageConverter<?>) clazz.newInstance());
} catch (final ClassNotFoundException ex) {
// Ignore it, this class is not available since Spring 4.1.0.
log.trace("MappingJacksonHttpMessageConverter is not available since Spring 4.1.0.", ex);
} catch (InstantiationException | IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
}
return converters;
}
public static ContentNegotiationManager defaultContentNegotiationManager() {
return defaultContentNegotiationManager(APPLICATION_JSON);
}
public static ContentNegotiationManager defaultContentNegotiationManager(final MediaType defaultContentType) {
final ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager( //
new HeaderContentNegotiationStrategy(), //
new ParameterContentNegotiationStrategy( //
ImmutableMap.of("json", APPLICATION_JSON, "xml", APPLICATION_XML) //
), //
new FixedContentNegotiationStrategy(defaultContentType) //
);
return contentNegotiationManager;
}
}