提交 4e24d66f 编写于 作者: S Sebastien Deleuze

Create a builder for Jackson ObjectMapper

Jackson2ObjectMapperBuilder now allows to create ObjectMapper and XmlMapper
instances easily thanks to its fluent API.

This builder is used in Jackson message converters and views to instantiate default
ObjectMapper and XmlMapper.

This commit also add a createXmlMapper property to
Jackson2ObjectMapperFactoryBean in order to allow to create easily a XmlMapper
instance.

Issue: SPR-12243
上级 521bbfcf
......@@ -182,6 +182,7 @@ configure(allprojects) { project ->
"http://quartz-scheduler.org/api/2.2.0/",
"http://fasterxml.github.com/jackson-core/javadoc/2.3.0/",
"http://fasterxml.github.com/jackson-databind/javadoc/2.3.0/",
"http://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.3.0/",
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/"
] as String[]
}
......
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.converter.json;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* A builder used to create {@link ObjectMapper} instances with a fluent API.
*
* <p>Note that Jackson's JSR-310 and Joda-Time support modules will be registered automatically
* when available (and when Java 8 and Joda-Time themselves are available, respectively).
*
* <p>Tested against Jackson 2.2 and 2.3; compatible with Jackson 2.0 and higher.
*
* @author Sebastien Deleuze
* @since 4.1.1
*/
public class Jackson2ObjectMapperBuilder {
private static final boolean jackson2XmlPresent =
ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", getClassLoader());
private ObjectMapper objectMapper;
private boolean createXmlMapper = false;
private DateFormat dateFormat;
private JsonInclude.Include serializationInclusion;
private AnnotationIntrospector annotationIntrospector;
private final Map<Class<?>, JsonSerializer<?>>
serializers = new LinkedHashMap<Class<?>, JsonSerializer<?>>();
private final Map<Class<?>, JsonDeserializer<?>>
deserializers = new LinkedHashMap<Class<?>, JsonDeserializer<?>>();
private final Map<Object, Boolean> features = new HashMap<Object, Boolean>();
private List<Module> modules;
private Class<? extends Module>[] modulesToInstall;
private boolean findModulesViaServiceLoader;
private PropertyNamingStrategy propertyNamingStrategy;
private Jackson2ObjectMapperBuilder() {
}
private Jackson2ObjectMapperBuilder(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
/**
* Obtain a {@link Jackson2ObjectMapperBuilder} instance in order to build an {@link ObjectMapper} instance.
*/
public static Jackson2ObjectMapperBuilder json() {
return new Jackson2ObjectMapperBuilder();
}
/**
* Obtain a {@link Jackson2ObjectMapperBuilder} instance in order to build a {@link XmlMapper} instance.
*/
@SuppressWarnings("unchecked")
public static Jackson2ObjectMapperBuilder xml() {
return new Jackson2ObjectMapperBuilder().createXmlMapper(true);
}
/**
* Obtain a {@link Jackson2ObjectMapperBuilder} in order to customize the {@link ObjectMapper} parameter.
*/
public static Jackson2ObjectMapperBuilder instance(ObjectMapper objectMapper) {
return new Jackson2ObjectMapperBuilder(objectMapper);
}
private static ClassLoader getClassLoader() {
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
Assert.state(classLoader != null, "No classloader available");
return classLoader;
}
/**
* If set to true and no custom {@link ObjectMapper} has been set, a {@link XmlMapper}
* will be created using its default constructor.
*/
public Jackson2ObjectMapperBuilder createXmlMapper(boolean createXmlMapper) {
this.createXmlMapper = createXmlMapper;
return this;
}
/**
* Define the format for date/time with the given {@link DateFormat}.
* <p>Note: Setting this property makes the exposed {@link ObjectMapper}
* non-thread-safe, according to Jackson's thread safety rules.
* @see #simpleDateFormat(String)
*/
public Jackson2ObjectMapperBuilder dateFormat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
return this;
}
/**
* Define the date/time format with a {@link SimpleDateFormat}.
* <p>Note: Setting this property makes the exposed {@link ObjectMapper}
* non-thread-safe, according to Jackson's thread safety rules.
* @see #dateFormat(DateFormat)
*/
public Jackson2ObjectMapperBuilder simpleDateFormat(String format) {
this.dateFormat = new SimpleDateFormat(format);
return this;
}
/**
* Set an {@link AnnotationIntrospector} for both serialization and deserialization.
*/
public Jackson2ObjectMapperBuilder annotationIntrospector(AnnotationIntrospector annotationIntrospector) {
this.annotationIntrospector = annotationIntrospector;
return this;
}
/**
* Set a custom inclusion strategy for serialization.
* @see com.fasterxml.jackson.annotation.JsonInclude.Include
*/
public Jackson2ObjectMapperBuilder serializationInclusion(JsonInclude.Include serializationInclusion) {
this.serializationInclusion = serializationInclusion;
return this;
}
/**
* Configure custom serializers. Each serializer is registered for the type
* returned by {@link JsonSerializer#handledType()}, which must not be
* {@code null}.
* @see #serializersByType(Map)
*/
public Jackson2ObjectMapperBuilder serializers(JsonSerializer<?>... serializers) {
if (serializers != null) {
for (JsonSerializer<?> serializer : serializers) {
Class<?> handledType = serializer.handledType();
Assert.isTrue(handledType != null && handledType != Object.class,
"Unknown handled type in " + serializer.getClass().getName());
this.serializers.put(serializer.handledType(), serializer);
}
}
return this;
}
/**
* Configure custom serializers for the given types.
* @see #serializers(JsonSerializer...)
*/
public Jackson2ObjectMapperBuilder serializersByType(Map<Class<?>, JsonSerializer<?>> serializers) {
if (serializers != null) {
this.serializers.putAll(serializers);
}
return this;
}
/**
* Configure custom deserializers for the given types.
*/
public Jackson2ObjectMapperBuilder deserializersByType(Map<Class<?>, JsonDeserializer<?>> deserializers) {
if (deserializers != null) {
this.deserializers.putAll(deserializers);
}
return this;
}
/**
* Shortcut for {@link MapperFeature#AUTO_DETECT_FIELDS} option.
*/
public Jackson2ObjectMapperBuilder autoDetectFields(boolean autoDetectFields) {
this.features.put(MapperFeature.AUTO_DETECT_FIELDS, autoDetectFields);
return this;
}
/**
* Shortcut for {@link MapperFeature#AUTO_DETECT_SETTERS}/
* {@link MapperFeature#AUTO_DETECT_GETTERS} option.
*/
public Jackson2ObjectMapperBuilder autoDetectGettersSetters(boolean autoDetectGettersSetters) {
this.features.put(MapperFeature.AUTO_DETECT_GETTERS, autoDetectGettersSetters);
this.features.put(MapperFeature.AUTO_DETECT_SETTERS, autoDetectGettersSetters);
return this;
}
/**
* Shortcut for {@link DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES} option.
*/
public Jackson2ObjectMapperBuilder failOnUnknownProperties(boolean failOnUnknownProperties) {
this.features.put(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, failOnUnknownProperties);
return this;
}
/**
* Shortcut for {@link MapperFeature#DEFAULT_VIEW_INCLUSION} option.
*/
public Jackson2ObjectMapperBuilder defaultViewInclusion(boolean defaultViewInclusion) {
this.features.put(MapperFeature.DEFAULT_VIEW_INCLUSION, defaultViewInclusion);
return this;
}
/**
* Shortcut for {@link SerializationFeature#FAIL_ON_EMPTY_BEANS} option.
*/
public Jackson2ObjectMapperBuilder failOnEmptyBeans(boolean failOnEmptyBeans) {
this.features.put(SerializationFeature.FAIL_ON_EMPTY_BEANS, failOnEmptyBeans);
return this;
}
/**
* Shortcut for {@link SerializationFeature#INDENT_OUTPUT} option.
*/
public Jackson2ObjectMapperBuilder indentOutput(boolean indentOutput) {
this.features.put(SerializationFeature.INDENT_OUTPUT, indentOutput);
return this;
}
/**
* Specify features to enable.
* @see com.fasterxml.jackson.core.JsonParser.Feature
* @see com.fasterxml.jackson.core.JsonGenerator.Feature
* @see com.fasterxml.jackson.databind.SerializationFeature
* @see com.fasterxml.jackson.databind.DeserializationFeature
* @see com.fasterxml.jackson.databind.MapperFeature
*/
public Jackson2ObjectMapperBuilder featuresToEnable(Object... featuresToEnable) {
if (featuresToEnable != null) {
for (Object feature : featuresToEnable) {
this.features.put(feature, Boolean.TRUE);
}
}
return this;
}
/**
* Specify features to disable.
* @see com.fasterxml.jackson.core.JsonParser.Feature
* @see com.fasterxml.jackson.core.JsonGenerator.Feature
* @see com.fasterxml.jackson.databind.SerializationFeature
* @see com.fasterxml.jackson.databind.DeserializationFeature
* @see com.fasterxml.jackson.databind.MapperFeature
*/
public Jackson2ObjectMapperBuilder featuresToDisable(Object... featuresToDisable) {
if (featuresToDisable != null) {
for (Object feature : featuresToDisable) {
this.features.put(feature, Boolean.FALSE);
}
}
return this;
}
/**
* Set a complete list of modules to be registered with the {@link ObjectMapper}.
* <p>Note: If this is set, no finding of modules is going to happen - not by
* Jackson, and not by Spring either (see {@link #findModulesViaServiceLoader}).
* As a consequence, specifying an empty list here will suppress any kind of
* module detection.
* <p>Specify either this or {@link #modulesToInstall}, not both.
* @see com.fasterxml.jackson.databind.Module
*/
public Jackson2ObjectMapperBuilder modules(List<Module> modules) {
this.modules = new LinkedList<Module>(modules);
return this;
}
/**
* Specify one or more modules by class (or class name in XML),
* to be registered with the {@link ObjectMapper}.
* <p>Modules specified here will be registered in combination with
* Spring's autodetection of JSR-310 and Joda-Time, or Jackson's
* finding of modules (see {@link #findModulesViaServiceLoader}).
* <p>Specify either this or {@link #modules}, not both.
* @see com.fasterxml.jackson.databind.Module
*/
public Jackson2ObjectMapperBuilder modulesToInstall(Class<? extends Module>... modules) {
this.modulesToInstall = modules;
return this;
}
/**
* Set whether to let Jackson find available modules via the JDK ServiceLoader,
* based on META-INF metadata in the classpath. Requires Jackson 2.2 or higher.
* <p>If this mode is not set, Spring's Jackson2ObjectMapperBuilder itself
* will try to find the JSR-310 and Joda-Time support modules on the classpath -
* provided that Java 8 and Joda-Time themselves are available, respectively.
* @see com.fasterxml.jackson.databind.ObjectMapper#findModules()
*/
public Jackson2ObjectMapperBuilder findModulesViaServiceLoader(boolean findModules) {
this.findModulesViaServiceLoader = findModules;
return this;
}
/**
* Specify a {@link com.fasterxml.jackson.databind.PropertyNamingStrategy} to
* configure the {@link ObjectMapper} with.
*/
public Jackson2ObjectMapperBuilder propertyNamingStrategy(PropertyNamingStrategy propertyNamingStrategy) {
this.propertyNamingStrategy = propertyNamingStrategy;
return this;
}
/**
* Build a new {@link T} instance.
*/
@SuppressWarnings("unchecked")
public <T extends ObjectMapper> T build() {
if (this.objectMapper == null) {
if(this.createXmlMapper) {
ClassLoader cl = getClassLoader();
try {
Class<? extends ObjectMapper> xmlMapper = (Class<? extends ObjectMapper>)
cl.loadClass("com.fasterxml.jackson.dataformat.xml.XmlMapper");
this.objectMapper = BeanUtils.instantiate(xmlMapper);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException("Could not instantiate XmlMapper, it has not been found on the classpath");
}
}
else {
this.objectMapper = new ObjectMapper();
}
}
if (this.dateFormat != null) {
this.objectMapper.setDateFormat(this.dateFormat);
}
if (this.annotationIntrospector != null) {
this.objectMapper.setAnnotationIntrospector(this.annotationIntrospector);
}
if (this.serializationInclusion != null) {
this.objectMapper.setSerializationInclusion(this.serializationInclusion);
}
if (!this.serializers.isEmpty() || !this.deserializers.isEmpty()) {
SimpleModule module = new SimpleModule();
addSerializers(module);
addDeserializers(module);
this.objectMapper.registerModule(module);
}
for (Object feature : this.features.keySet()) {
configureFeature(feature, this.features.get(feature));
}
if (this.modules != null) {
// Complete list of modules given
for (Module module : this.modules) {
// Using Jackson 2.0+ registerModule method, not Jackson 2.2+ registerModules
this.objectMapper.registerModule(module);
}
}
else {
// Combination of modules by class names specified and class presence in the classpath
if (this.modulesToInstall != null) {
for (Class<? extends Module> module : this.modulesToInstall) {
this.objectMapper.registerModule(BeanUtils.instantiate(module));
}
}
if (this.findModulesViaServiceLoader) {
// Jackson 2.2+
this.objectMapper.registerModules(ObjectMapper.findModules(getClassLoader()));
}
else {
registerWellKnownModulesIfAvailable();
}
}
if (this.propertyNamingStrategy != null) {
this.objectMapper.setPropertyNamingStrategy(this.propertyNamingStrategy);
}
return (T)this.objectMapper;
}
@SuppressWarnings("unchecked")
private <T> void addSerializers(SimpleModule module) {
for (Class<?> type : this.serializers.keySet()) {
module.addSerializer((Class<? extends T>) type, (JsonSerializer<T>) this.serializers.get(type));
}
}
@SuppressWarnings("unchecked")
private <T> void addDeserializers(SimpleModule module) {
for (Class<?> type : this.deserializers.keySet()) {
module.addDeserializer((Class<T>) type, (JsonDeserializer<? extends T>) this.deserializers.get(type));
}
}
private void configureFeature(Object feature, boolean enabled) {
if (feature instanceof JsonParser.Feature) {
this.objectMapper.configure((JsonParser.Feature) feature, enabled);
}
else if (feature instanceof JsonGenerator.Feature) {
this.objectMapper.configure((JsonGenerator.Feature) feature, enabled);
}
else if (feature instanceof SerializationFeature) {
this.objectMapper.configure((SerializationFeature) feature, enabled);
}
else if (feature instanceof DeserializationFeature) {
this.objectMapper.configure((DeserializationFeature) feature, enabled);
}
else if (feature instanceof MapperFeature) {
this.objectMapper.configure((MapperFeature) feature, enabled);
}
else {
throw new FatalBeanException("Unknown feature class: " + feature.getClass().getName());
}
}
@SuppressWarnings("unchecked")
private void registerWellKnownModulesIfAvailable() {
ClassLoader cl = getClassLoader();
// Java 8 java.time package present?
if (ClassUtils.isPresent("java.time.LocalDate", cl)) {
try {
Class<? extends Module> jsr310Module = (Class<? extends Module>)
cl.loadClass("com.fasterxml.jackson.datatype.jsr310.JSR310Module");
this.objectMapper.registerModule(BeanUtils.instantiate(jsr310Module));
}
catch (ClassNotFoundException ex) {
// jackson-datatype-jsr310 not available
}
}
// Joda-Time present?
if (ClassUtils.isPresent("org.joda.time.LocalDate", cl)) {
try {
Class<? extends Module> jodaModule = (Class<? extends Module>)
cl.loadClass("com.fasterxml.jackson.datatype.joda.JodaModule");
this.objectMapper.registerModule(BeanUtils.instantiate(jodaModule));
}
catch (ClassNotFoundException ex) {
// jackson-datatype-joda not available
}
}
}
}
......@@ -37,6 +37,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.FatalBeanException;
......@@ -47,7 +48,8 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* A {@link FactoryBean} for creating a Jackson 2.x {@link ObjectMapper} with setters
* A {@link FactoryBean} for creating a Jackson 2.x {@link ObjectMapper} (default) or
* {@link XmlMapper} ({@code createXmlMapper} property set to true) with setters
* to enable or disable Jackson features from within XML configuration.
*
* <p>Example usage with
......@@ -126,6 +128,8 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
private ObjectMapper objectMapper;
private boolean createXmlMapper = false;
private DateFormat dateFormat;
private JsonInclude.Include serializationInclusion;
......@@ -150,13 +154,21 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
/**
* Set the ObjectMapper instance to use. If not set, the ObjectMapper will
* be created using its default constructor.
* Set the {@link ObjectMapper} instance to use. If not set, the {@link ObjectMapper}
* will be created using its default constructor.
*/
public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
/**
* If set to true and no custom {@link ObjectMapper} has been set, a {@link XmlMapper}
* will be created using its default constructor.
*/
public void setCreateXmlMapper(boolean createXmlMapper) {
this.createXmlMapper = createXmlMapper;
}
/**
* Define the format for date/time with the given {@link DateFormat}.
* <p>Note: Setting this property makes the exposed {@link ObjectMapper}
......@@ -244,6 +256,13 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
this.features.put(MapperFeature.AUTO_DETECT_SETTERS, autoDetectGettersSetters);
}
/**
* Shortcut for {@link DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES} option.
*/
public void setFailOnUnknownProperties(boolean failOnUnknownProperties) {
this.features.put(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, failOnUnknownProperties);
}
/**
* Shortcut for {@link MapperFeature#DEFAULT_VIEW_INCLUSION} option.
*/
......@@ -352,11 +371,27 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean<ObjectMapper
this.beanClassLoader = beanClassLoader;
}
@Override
@SuppressWarnings("unchecked")
public void afterPropertiesSet() {
if (this.objectMapper == null) {
this.objectMapper = new ObjectMapper();
if(this.createXmlMapper) {
ClassLoader cl = this.beanClassLoader;
if (cl == null) {
cl = getClass().getClassLoader();
}
try {
Class<? extends ObjectMapper> xmlMapper = (Class<? extends ObjectMapper>)
cl.loadClass("com.fasterxml.jackson.dataformat.xml.XmlMapper");
this.objectMapper = BeanUtils.instantiate(xmlMapper);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException("Could not instantiate XmlMapper", ex);
}
}
else {
this.objectMapper = new ObjectMapper();
}
}
if (this.dateFormat != null) {
......
......@@ -32,6 +32,8 @@ import org.springframework.http.MediaType;
* <p>By default, this converter supports {@code application/json}. This can be overridden by setting the
* {@link #setSupportedMediaTypes supportedMediaTypes} property.
*
* <p>The default constructor uses the default configuration provided by {@link Jackson2ObjectMapperBuilder}.
*
* <p>Compatible with Jackson 2.1 and higher.
*
* @author Arjen Poutsma
......@@ -47,13 +49,22 @@ public class MappingJackson2HttpMessageConverter extends AbstractJackson2HttpMes
/**
* Construct a new {@code MappingJackson2HttpMessageConverter}.
* Construct a new {@link MappingJackson2HttpMessageConverter} using default configuration
* provided by {@link Jackson2ObjectMapperBuilder}.
*/
public MappingJackson2HttpMessageConverter() {
super(new ObjectMapper(), new MediaType("application", "json", DEFAULT_CHARSET),
new MediaType("application", "*+json", DEFAULT_CHARSET));
this(Jackson2ObjectMapperBuilder.json().build());
}
/**
* Construct a new {@link MappingJackson2HttpMessageConverter} with a custom {@link ObjectMapper}.
* You can use {@link Jackson2ObjectMapperBuilder} to build it easily.
* @see Jackson2ObjectMapperBuilder#json()
*/
public MappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, new MediaType("application", "json", DEFAULT_CHARSET),
new MediaType("application", "*+json", DEFAULT_CHARSET));
}
/**
* Specify a custom prefix to use for this view's JSON output.
......
......@@ -16,23 +16,52 @@
package org.springframework.http.converter.xml;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.Assert;
/**
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverter}
* that can read and write XML using <a href="https://github.com/FasterXML/jackson-dataformat-xml">
* Jackson 2.x extension component for reading and writing XML encoded data</a>.
*
* <p>The default constructor uses the default configuration provided by {@link Jackson2ObjectMapperBuilder}.
*
* @author Sebastien Deleuze
* @since 4.1
*/
public class MappingJackson2XmlHttpMessageConverter extends AbstractJackson2HttpMessageConverter {
/**
* Construct a new {@code MappingJackson2XmlHttpMessageConverter} using default configuration
* provided by {@code Jackson2ObjectMapperBuilder}.
*/
public MappingJackson2XmlHttpMessageConverter() {
super(new XmlMapper(), new MediaType("application", "xml", DEFAULT_CHARSET));
this(Jackson2ObjectMapperBuilder.xml().build());
}
/**
* Construct a new {@code MappingJackson2XmlHttpMessageConverter} with a custom {@link ObjectMapper}
* (must be a {@link XmlMapper} instance).
* You can use {@link Jackson2ObjectMapperBuilder} to build it easily.
* @see Jackson2ObjectMapperBuilder#xml()
*/
public MappingJackson2XmlHttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, new MediaType("application", "xml", DEFAULT_CHARSET));
Assert.isAssignable(XmlMapper.class, objectMapper.getClass());
}
/**
* {@inheritDoc}
* The {@code objectMapper} parameter must be a {@link XmlMapper} instance.
*/
@Override
public void setObjectMapper(ObjectMapper objectMapper) {
Assert.isAssignable(XmlMapper.class, objectMapper.getClass());
super.setObjectMapper(objectMapper);
}
}
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.converter.json;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig;
import com.fasterxml.jackson.databind.deser.BasicDeserializerFactory;
import com.fasterxml.jackson.databind.deser.std.DateDeserializers;
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BasicSerializerFactory;
import com.fasterxml.jackson.databind.ser.Serializers;
import com.fasterxml.jackson.databind.ser.std.ClassSerializer;
import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
import com.fasterxml.jackson.databind.type.SimpleType;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.junit.Test;
import org.springframework.beans.FatalBeanException;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
/**
* Test class for {@link Jackson2ObjectMapperBuilder}.
*
* @author Sebastien Deleuze
*/
public class Jackson2ObjectMapperBuilderTests {
private static final String DATE_FORMAT = "yyyy-MM-dd";
@Test
public void settersWithNullValues() {
// Should not crash:
Jackson2ObjectMapperBuilder.json().serializers((JsonSerializer<?>[]) null)
.serializersByType(null).deserializersByType(null)
.featuresToEnable((Object[]) null).featuresToDisable((Object[]) null);
}
@Test(expected = FatalBeanException.class)
public void unknownFeature() {
Jackson2ObjectMapperBuilder.json().featuresToEnable(Boolean.TRUE).build();
}
@Test
public void defaultProperties() {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
assertNotNull(objectMapper);
assertTrue(objectMapper.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
assertTrue(objectMapper.isEnabled(MapperFeature.AUTO_DETECT_FIELDS));
assertTrue(objectMapper.isEnabled(MapperFeature.AUTO_DETECT_GETTERS));
assertTrue(objectMapper.isEnabled(MapperFeature.AUTO_DETECT_SETTERS));
assertFalse(objectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT));
assertTrue(objectMapper.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS));
}
@Test
public void propertiesShortcut() {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().autoDetectFields(false)
.defaultViewInclusion(true).failOnUnknownProperties(true).failOnEmptyBeans(false)
.autoDetectGettersSetters(false).indentOutput(true).build();
assertNotNull(objectMapper);
assertTrue(objectMapper.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
assertFalse(objectMapper.isEnabled(MapperFeature.AUTO_DETECT_FIELDS));
assertFalse(objectMapper.isEnabled(MapperFeature.AUTO_DETECT_GETTERS));
assertFalse(objectMapper.isEnabled(MapperFeature.AUTO_DETECT_SETTERS));
assertTrue(objectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT));
assertFalse(objectMapper.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS));
}
@Test
public void booleanSetters() {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
.featuresToEnable(MapperFeature.DEFAULT_VIEW_INCLUSION,
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
SerializationFeature.INDENT_OUTPUT)
.featuresToDisable(MapperFeature.AUTO_DETECT_FIELDS,
MapperFeature.AUTO_DETECT_GETTERS,
MapperFeature.AUTO_DETECT_SETTERS,
SerializationFeature.FAIL_ON_EMPTY_BEANS).build();
assertNotNull(objectMapper);
assertTrue(objectMapper.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
assertFalse(objectMapper.isEnabled(MapperFeature.AUTO_DETECT_FIELDS));
assertFalse(objectMapper.isEnabled(MapperFeature.AUTO_DETECT_GETTERS));
assertFalse(objectMapper.isEnabled(MapperFeature.AUTO_DETECT_SETTERS));
assertTrue(objectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT));
assertFalse(objectMapper.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS));
}
@Test
public void setNotNullSerializationInclusion() {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() ==
JsonInclude.Include.ALWAYS);
objectMapper = Jackson2ObjectMapperBuilder.json().serializationInclusion(JsonInclude.Include.NON_NULL).build();
assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_NULL);
}
@Test
public void setNotDefaultSerializationInclusion() {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.ALWAYS);
objectMapper = Jackson2ObjectMapperBuilder.json().serializationInclusion(JsonInclude.Include.NON_DEFAULT).build();
assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_DEFAULT);
}
@Test
public void setNotEmptySerializationInclusion() {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.ALWAYS);
objectMapper = Jackson2ObjectMapperBuilder.json().serializationInclusion(JsonInclude.Include.NON_EMPTY).build();
assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_EMPTY);
}
@Test
public void dateTimeFormatSetter() {
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().dateFormat(dateFormat).build();
assertEquals(dateFormat, objectMapper.getSerializationConfig().getDateFormat());
assertEquals(dateFormat, objectMapper.getDeserializationConfig().getDateFormat());
}
@Test
public void simpleDateFormatStringSetter() {
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().simpleDateFormat(DATE_FORMAT).build();
assertEquals(dateFormat, objectMapper.getSerializationConfig().getDateFormat());
assertEquals(dateFormat, objectMapper.getDeserializationConfig().getDateFormat());
}
@Test
public void setModules() {
NumberSerializer serializer1 = new NumberSerializer();
SimpleModule module = new SimpleModule();
module.addSerializer(Integer.class, serializer1);
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(Arrays.asList(new Module[]{module})).build();
Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next();
assertTrue(serializers.findSerializer(null, SimpleType.construct(Integer.class), null) == serializer1);
}
private static SerializerFactoryConfig getSerializerFactoryConfig(ObjectMapper objectMapper) {
return ((BasicSerializerFactory) objectMapper.getSerializerFactory()).getFactoryConfig();
}
private static DeserializerFactoryConfig getDeserializerFactoryConfig(ObjectMapper objectMapper) {
return ((BasicDeserializerFactory) objectMapper.getDeserializationContext().getFactory()).getFactoryConfig();
}
@Test
public void propertyNamingStrategy() {
PropertyNamingStrategy strategy = new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy();
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().propertyNamingStrategy(strategy).build();
assertSame(strategy, objectMapper.getSerializationConfig().getPropertyNamingStrategy());
assertSame(strategy, objectMapper.getDeserializationConfig().getPropertyNamingStrategy());
}
@Test
public void completeSetup() {
NopAnnotationIntrospector annotationIntrospector = NopAnnotationIntrospector.instance;
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.instance(new ObjectMapper());
Map<Class<?>, JsonDeserializer<?>>
deserializers = new HashMap<Class<?>, JsonDeserializer<?>>();
deserializers.put(Date.class, new DateDeserializers.DateDeserializer());
JsonSerializer<Class<?>> serializer1 = new ClassSerializer();
JsonSerializer<Number> serializer2 = new NumberSerializer();
builder.serializers(serializer1);
builder.serializersByType(Collections
.<Class<?>, JsonSerializer<?>>singletonMap(Boolean.class, serializer2));
builder.deserializersByType(deserializers);
builder.annotationIntrospector(annotationIntrospector);
builder.featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS,
DeserializationFeature.UNWRAP_ROOT_VALUE,
JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER,
JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
builder.featuresToDisable(MapperFeature.AUTO_DETECT_GETTERS,
MapperFeature.AUTO_DETECT_FIELDS, JsonParser.Feature.AUTO_CLOSE_SOURCE,
JsonGenerator.Feature.QUOTE_FIELD_NAMES);
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
ObjectMapper objectMapper = builder.build();
assertTrue(getSerializerFactoryConfig(objectMapper).hasSerializers());
assertTrue(getDeserializerFactoryConfig(objectMapper).hasDeserializers());
Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next();
assertTrue(serializers.findSerializer(null, SimpleType.construct(Class.class), null) == serializer1);
assertTrue(serializers.findSerializer(null, SimpleType.construct(Boolean.class), null) == serializer2);
assertNull(serializers.findSerializer(null, SimpleType.construct(Number.class), null));
assertTrue(annotationIntrospector == objectMapper.getSerializationConfig().getAnnotationIntrospector());
assertTrue(annotationIntrospector == objectMapper.getDeserializationConfig().getAnnotationIntrospector());
assertTrue(objectMapper.getSerializationConfig().isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS));
assertTrue(objectMapper.getDeserializationConfig().isEnabled(DeserializationFeature.UNWRAP_ROOT_VALUE));
assertTrue(objectMapper.getFactory().isEnabled(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER));
assertTrue(objectMapper.getFactory().isEnabled(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS));
assertFalse(objectMapper.getSerializationConfig().isEnabled(MapperFeature.AUTO_DETECT_GETTERS));
assertTrue(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.getDeserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
assertFalse(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.AUTO_DETECT_FIELDS));
assertFalse(objectMapper.getFactory().isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
assertFalse(objectMapper.getFactory().isEnabled(JsonGenerator.Feature.QUOTE_FIELD_NAMES));
assertTrue(objectMapper.getSerializationConfig().getSerializationInclusion() == JsonInclude.Include.NON_NULL);
}
@Test
public void xmlMapper() {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.xml().build();
assertNotNull(objectMapper);
assertEquals(XmlMapper.class, objectMapper.getClass());
}
@Test
public void createXmlMapper() {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json().indentOutput(true);
ObjectMapper jsonObjectMapper = builder.build();
ObjectMapper xmlObjectMapper = builder.createXmlMapper(true).build();
assertTrue(jsonObjectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT));
assertTrue(xmlObjectMapper.isEnabled(SerializationFeature.INDENT_OUTPUT));
assertTrue(xmlObjectMapper.getClass().isAssignableFrom(XmlMapper.class));
}
}
......@@ -260,6 +260,7 @@ public class Jackson2ObjectMapperFactoryBeanTests {
assertFalse(objectMapper.getSerializationConfig().isEnabled(MapperFeature.AUTO_DETECT_GETTERS));
assertTrue(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.getDeserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
assertFalse(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.AUTO_DETECT_FIELDS));
assertFalse(objectMapper.getFactory().isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
assertFalse(objectMapper.getFactory().isEnabled(JsonGenerator.Feature.QUOTE_FIELD_NAMES));
......@@ -276,4 +277,14 @@ public class Jackson2ObjectMapperFactoryBeanTests {
assertEquals(XmlMapper.class, this.factory.getObjectType());
}
@Test
public void createXmlMapper() {
this.factory.setCreateXmlMapper(true);
this.factory.afterPropertiesSet();
assertNotNull(this.factory.getObject());
assertTrue(this.factory.isSingleton());
assertEquals(XmlMapper.class, this.factory.getObjectType());
}
}
......@@ -253,8 +253,8 @@ public class MappingJackson2HttpMessageConverterTests {
String result = outputMessage.getBodyAsString(Charset.forName("UTF-8"));
assertThat(result, containsString("\"withView1\":\"with\""));
assertThat(result, containsString("\"withoutView\":\"without\""));
assertThat(result, not(containsString("\"withView2\":\"with\"")));
assertThat(result, containsString("\"withoutView\":\"without\""));
}
@Test
......@@ -286,8 +286,8 @@ public class MappingJackson2HttpMessageConverterTests {
assertThat(result, startsWith("callback("));
assertThat(result, endsWith(");"));
assertThat(result, containsString("\"withView1\":\"with\""));
assertThat(result, containsString("\"withoutView\":\"without\""));
assertThat(result, not(containsString("\"withView2\":\"with\"")));
assertThat(result, containsString("\"withoutView\":\"without\""));
}
......
......@@ -22,6 +22,7 @@ import java.lang.reflect.Method;
import java.nio.charset.Charset;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
......@@ -123,8 +124,14 @@ public class MappingJackson2XmlHttpMessageConverterTests {
String result = outputMessage.getBodyAsString(Charset.forName("UTF-8"));
assertThat(result, containsString("<withView1>with</withView1>"));
assertThat(result, containsString("<withoutView>without</withoutView>"));
assertThat(result, not(containsString("<withView2>with</withView2>")));
assertThat(result, containsString("<withoutView>without</withoutView>"));
}
@Test
public void customXmlMapper() {
new MappingJackson2XmlHttpMessageConverter(new MyXmlMapper());
// Assert no exception is thrown
}
private void writeInternal(Object object, HttpOutputMessage outputMessage)
......@@ -238,4 +245,8 @@ public class MappingJackson2XmlHttpMessageConverterTests {
}
}
private static class MyXmlMapper extends XmlMapper {
}
}
......@@ -103,7 +103,7 @@ public abstract class AbstractJackson2View extends AbstractView {
}
/**
* Whether to use the default pretty printer when writing JSON.
* Whether to use the default pretty printer when writing the output.
* This is a shortcut for setting up an {@code ObjectMapper} as follows:
* <pre class="code">
* ObjectMapper mapper = new ObjectMapper();
......
......@@ -30,6 +30,7 @@ import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
......@@ -44,6 +45,8 @@ import org.springframework.web.servlet.View;
* will be encoded as JSON. If the model contains only one key, you can have it extracted encoded as JSON
* alone via {@link #setExtractValueFromSingleKeyModel}.
*
* <p>The default constructor uses the default configuration provided by {@link Jackson2ObjectMapperBuilder}.
*
* <p>Compatible with Jackson 2.1 and higher.
*
* @author Jeremy Grelle
......@@ -76,10 +79,12 @@ public class MappingJackson2JsonView extends AbstractJackson2View {
/**
* Construct a new {@code MappingJackson2JsonView}, setting the content type to {@code application/json}.
* Construct a new {@code MappingJackson2JsonView} using default configuration
* provided by {@link Jackson2ObjectMapperBuilder} and setting the content type
* to {@code application/json}.
*/
public MappingJackson2JsonView() {
super(new ObjectMapper(), DEFAULT_CONTENT_TYPE);
super(Jackson2ObjectMapperBuilder.json().build(), DEFAULT_CONTENT_TYPE);
}
......
......@@ -21,6 +21,7 @@ import java.util.Map;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.json.AbstractJackson2View;
......@@ -33,6 +34,8 @@ import org.springframework.web.servlet.view.json.AbstractJackson2View;
* entry is used. Users can either specify a specific entry in the model via the
* {@link #setModelKey(String) sourceKey} property.
*
* <p>The default constructor uses the default configuration provided by {@link Jackson2ObjectMapperBuilder}.
*
* <p>Compatible with Jackson 2.1 and higher.
*
* @author Sebastien Deleuze
......@@ -46,8 +49,13 @@ public class MappingJackson2XmlView extends AbstractJackson2View {
private String modelKey;
/**
* Construct a new {@code MappingJackson2XmlView} using default configuration
* provided by {@link Jackson2ObjectMapperBuilder} and setting the content type
* to {@code application/xml}.
*/
public MappingJackson2XmlView() {
super(new XmlMapper(), DEFAULT_CONTENT_TYPE);
super(Jackson2ObjectMapperBuilder.xml().build(), DEFAULT_CONTENT_TYPE);
}
......
......@@ -78,13 +78,13 @@ public class AnnotationDrivenBeanDefinitionParserTests {
@Test
public void testPathMatchingConfiguration() {
loadBeanDefinitions("mvc-config-path-matching.xml");
RequestMappingHandlerMapping hm = appContext.getBean(RequestMappingHandlerMapping.class);
assertNotNull(hm);
loadBeanDefinitions("mvc-config-path-matching.xml");
RequestMappingHandlerMapping hm = appContext.getBean(RequestMappingHandlerMapping.class);
assertNotNull(hm);
assertTrue(hm.useSuffixPatternMatch());
assertFalse(hm.useTrailingSlashMatch());
assertTrue(hm.useRegisteredSuffixPatternMatch());
assertThat(hm.getUrlPathHelper(), Matchers.instanceOf(TestPathHelper.class));
assertThat(hm.getUrlPathHelper(), Matchers.instanceOf(TestPathHelper.class));
assertThat(hm.getPathMatcher(), Matchers.instanceOf(TestPathMatcher.class));
List<String> fileExtensions = hm.getContentNegotiationManager().getAllFileExtensions();
assertThat(fileExtensions, Matchers.contains("xml"));
......
......@@ -16,6 +16,10 @@
package org.springframework.web.servlet.config;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import static org.junit.Assert.*;
import java.lang.annotation.Retention;
......@@ -44,6 +48,8 @@ import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.mock.web.test.MockRequestDispatcher;
......@@ -162,8 +168,19 @@ public class MvcNamespaceTests {
assertNotNull(adapter);
assertEquals(false, new DirectFieldAccessor(adapter).getPropertyValue("ignoreDefaultModelOnRedirect"));
List<HttpMessageConverter<?>> messageConverters = adapter.getMessageConverters();
assertTrue(messageConverters.size() > 0);
List<HttpMessageConverter<?>> converters = adapter.getMessageConverters();
assertTrue(converters.size() > 0);
for(HttpMessageConverter<?> converter : converters) {
if(converter instanceof AbstractJackson2HttpMessageConverter) {
ObjectMapper objectMapper = ((AbstractJackson2HttpMessageConverter)converter).getObjectMapper();
assertTrue(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.getSerializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.getDeserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
if(converter instanceof MappingJackson2XmlHttpMessageConverter) {
assertEquals(XmlMapper.class, objectMapper.getClass());
}
}
}
assertNotNull(appContext.getBean(FormattingConversionServiceFactoryBean.class));
assertNotNull(appContext.getBean(ConversionService.class));
......
......@@ -16,14 +16,15 @@
package org.springframework.web.servlet.config.annotation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import com.fasterxml.jackson.databind.DeserializationFeature;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
......@@ -72,6 +73,8 @@ import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import static org.junit.Assert.*;
/**
* A test fixture with a sub-class of {@link WebMvcConfigurationSupport} that also
* implements the various {@link WebMvcConfigurer} extension points.
......@@ -157,6 +160,14 @@ public class WebMvcConfigurationSupportExtensionTests {
// Message converters
assertEquals(1, adapter.getMessageConverters().size());
assertEquals(MappingJackson2HttpMessageConverter.class, adapter.getMessageConverters().get(0).getClass());
ObjectMapper objectMapper = ((MappingJackson2HttpMessageConverter)adapter.getMessageConverters().get(0)).getObjectMapper();
assertTrue(objectMapper.getDeserializationConfig()
.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.getSerializationConfig()
.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.getDeserializationConfig()
.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(adapter);
......
......@@ -21,6 +21,10 @@ import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.joda.time.DateTime;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
......@@ -36,6 +40,9 @@ import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.HttpEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.stereotype.Controller;
......@@ -150,7 +157,19 @@ public class WebMvcConfigurationSupportTests {
public void requestMappingHandlerAdapter() throws Exception {
ApplicationContext context = initContext(WebConfig.class);
RequestMappingHandlerAdapter adapter = context.getBean(RequestMappingHandlerAdapter.class);
assertEquals(9, adapter.getMessageConverters().size());
List<HttpMessageConverter<?>> converters = adapter.getMessageConverters();
assertEquals(9, converters.size());
for(HttpMessageConverter<?> converter : converters) {
if(converter instanceof AbstractJackson2HttpMessageConverter) {
ObjectMapper objectMapper = ((AbstractJackson2HttpMessageConverter)converter).getObjectMapper();
assertTrue(objectMapper.getDeserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.getSerializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION));
assertTrue(objectMapper.getDeserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES));
if(converter instanceof MappingJackson2XmlHttpMessageConverter) {
assertEquals(XmlMapper.class, objectMapper.getClass());
}
}
}
ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
assertNotNull(initializer);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册