diff --git a/build.gradle b/build.gradle index b7707ffb62..4c5fe0045d 100644 --- a/build.gradle +++ b/build.gradle @@ -697,6 +697,7 @@ project("spring-web") { testCompile("org.apache.taglibs:taglibs-standard-jstlel:1.2.1") { exclude group: "org.apache.taglibs", module: "taglibs-standard-spec" } + testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:${jackson2Version}") testRuntime("com.sun.mail:javax.mail:1.5.2") } diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java index 7a42c8f0bd..0169a3bb2b 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java @@ -389,11 +389,12 @@ public class Jackson2ObjectMapperBuilder { } /** - * Specify one or more modules by class (or class name in XML), - * to be registered with the {@link ObjectMapper}. - *
Modules specified here will be registered in combination with + * Specify one or more modules by class to be registered with + * the {@link ObjectMapper}. + *
Modules specified here will be registered after * Spring's autodetection of JSR-310 and Joda-Time, or Jackson's - * finding of modules (see {@link #findModulesViaServiceLoader}). + * finding of modules (see {@link #findModulesViaServiceLoader}), + * allowing to eventually override their configuration. *
Specify either this or {@link #modules}, not both.
* @see com.fasterxml.jackson.databind.Module
*/
@@ -481,6 +482,29 @@ public class Jackson2ObjectMapperBuilder {
public void configure(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "ObjectMapper must not be null");
+ 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
+ objectMapper.registerModule(module);
+ }
+ }
+ else {
+ // Combination of modules by class presence in the classpath and class names specified
+ if (this.findModulesViaServiceLoader) {
+ // Jackson 2.2+
+ objectMapper.registerModules(ObjectMapper.findModules(this.moduleClassLoader));
+ }
+ else {
+ registerWellKnownModulesIfAvailable(objectMapper);
+ }
+ if (this.modulesToInstall != null) {
+ for (Class extends Module> module : this.modulesToInstall) {
+ objectMapper.registerModule(BeanUtils.instantiate(module));
+ }
+ }
+ }
+
if (this.dateFormat != null) {
objectMapper.setDateFormat(this.dateFormat);
}
@@ -511,29 +535,6 @@ public class Jackson2ObjectMapperBuilder {
configureFeature(objectMapper, 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
- 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) {
- objectMapper.registerModule(BeanUtils.instantiate(module));
- }
- }
- if (this.findModulesViaServiceLoader) {
- // Jackson 2.2+
- objectMapper.registerModules(ObjectMapper.findModules(this.moduleClassLoader));
- }
- else {
- registerWellKnownModulesIfAvailable(objectMapper);
- }
- }
-
if (this.propertyNamingStrategy != null) {
objectMapper.setPropertyNamingStrategy(this.propertyNamingStrategy);
}
diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java
index b6d7cb57ad..4288b03b97 100644
--- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java
+++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperFactoryBean.java
@@ -346,11 +346,12 @@ public class Jackson2ObjectMapperFactoryBean implements FactoryBean Modules specified here will be registered after
* Spring's autodetection of JSR-310 and Joda-Time, or Jackson's
- * finding of modules (see {@link #setFindModulesViaServiceLoader}).
+ * finding of modules (see {@link #setFindModulesViaServiceLoader}),
+ * allowing to eventually override their configuration.
* Specify either this or {@link #setModules}, not both.
* @since 4.0.1
* @see com.fasterxml.jackson.databind.Module
diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java
index c0f1abd77e..79d28e73d8 100644
--- a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java
+++ b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java
@@ -16,7 +16,9 @@
package org.springframework.http.converter.json;
+import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
@@ -28,6 +30,8 @@ import java.util.TimeZone;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
@@ -44,12 +48,17 @@ import com.fasterxml.jackson.databind.deser.Deserializers;
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.module.SimpleSerializers;
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 com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat;
+import com.fasterxml.jackson.datatype.joda.ser.DateTimeSerializer;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormat;
import org.junit.Test;
import org.springframework.beans.FatalBeanException;
@@ -211,6 +220,32 @@ public class Jackson2ObjectMapperBuilderTests {
assertTrue(serializers.findSerializer(null, SimpleType.construct(Integer.class), null) == serializer1);
}
+ @Test
+ public void defaultModules() throws JsonProcessingException, UnsupportedEncodingException {
+ ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
+ DateTime dateTime = DateTime.parse("2011-12-03T10:15:30");
+ assertEquals("1322903730000", new String(objectMapper.writeValueAsBytes(dateTime), "UTF-8"));
+ }
+
+ @Test // SPR-12634
+ public void customizeDefaultModules() throws JsonProcessingException, UnsupportedEncodingException {
+ ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
+ .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
+ .modulesToInstall(CustomModule.class).build();
+ DateTime dateTime = DateTime.parse("2011-12-03T10:15:30");
+ assertEquals("\"2011-12-03\"", new String(objectMapper.writeValueAsBytes(dateTime), "UTF-8"));
+ }
+
+ @Test // SPR-12634
+ public void customizeDefaultModulesWithSerializer() throws JsonProcessingException, UnsupportedEncodingException {
+ ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
+ .serializerByType(DateTime.class, new DateTimeSerializer(new JacksonJodaDateFormat(DateTimeFormat.forPattern("YYYY-MM-dd").withZoneUTC())))
+ .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).build();
+ DateTime dateTime = DateTime.parse("2011-12-03T10:15:30");
+ assertEquals("\"2011-12-03\"", new String(objectMapper.writeValueAsBytes(dateTime), "UTF-8"));
+ }
+
+
private static SerializerFactoryConfig getSerializerFactoryConfig(ObjectMapper objectMapper) {
return ((BasicSerializerFactory) objectMapper.getSerializerFactory()).getFactoryConfig();
}
@@ -231,6 +266,7 @@ public class Jackson2ObjectMapperBuilderTests {
public void serializerByType() {
JsonSerializer