diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml
index b7fc565c62..16d865e228 100644
--- a/spring-boot-autoconfigure/pom.xml
+++ b/spring-boot-autoconfigure/pom.xml
@@ -36,6 +36,11 @@
jackson-datatype-joda
true
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ true
+
org.flywaydb
flyway-core
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java
new file mode 100644
index 0000000000..61e47ec533
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfiguration.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2012-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.boot.autoconfigure.jackson;
+
+import java.util.Collection;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.BeanFactoryUtils;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnJava;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnJava.JavaVersion;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.web.HttpMapperProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+import com.fasterxml.jackson.databind.Module;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.joda.JodaModule;
+import com.fasterxml.jackson.datatype.jsr310.JSR310Module;
+
+/**
+ * Auto configuration for Jackson. The following auto-configuration will get applied:
+ *
+ * - an {@link ObjectMapper} in case none is already configured.
+ * - the {@link JodaModule} registered if it's on the classpath.
+ * - the {@link JSR310Module} registered if it's on the classpath and the application is
+ * running on Java 8 or better.
+ * - auto-registration for all {@link Module} beans with all {@link ObjectMapper} beans
+ * (including the defaulted ones).
+ *
+ *
+ * @author Oliver Gierke
+ * @since 1.1.0
+ */
+@Configuration
+@ConditionalOnClass(ObjectMapper.class)
+@EnableConfigurationProperties(HttpMapperProperties.class)
+public class JacksonAutoConfiguration {
+
+ @Autowired
+ private HttpMapperProperties properties = new HttpMapperProperties();
+
+ @Autowired
+ private ListableBeanFactory beanFactory;
+
+ @Bean
+ @ConditionalOnMissingBean
+ @Primary
+ public ObjectMapper jacksonObjectMapper() {
+
+ ObjectMapper objectMapper = new ObjectMapper();
+
+ if (this.properties.isJsonSortKeys()) {
+ objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
+ }
+
+ return objectMapper;
+ }
+
+ @PostConstruct
+ public void init() {
+
+ Collection mappers = BeanFactoryUtils
+ .beansOfTypeIncludingAncestors(this.beanFactory, ObjectMapper.class)
+ .values();
+ Collection modules = BeanFactoryUtils.beansOfTypeIncludingAncestors(
+ this.beanFactory, Module.class).values();
+
+ for (ObjectMapper mapper : mappers) {
+ mapper.registerModules(modules);
+ }
+ }
+
+ @Configuration
+ @ConditionalOnClass(JodaModule.class)
+ static class JodaModuleAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ JodaModule jacksonJodaModule() {
+ return new JodaModule();
+ }
+ }
+
+ @Configuration
+ @ConditionalOnJava(JavaVersion.EIGHT)
+ @ConditionalOnClass(JSR310Module.class)
+ static class Jsr310ModuleAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ JSR310Module jacksonJsr310Module() {
+ return new JSR310Module();
+ }
+ }
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfiguration.java
index d6b56f4860..5c64e7e1f9 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfiguration.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfiguration.java
@@ -17,38 +17,34 @@
package org.springframework.boot.autoconfigure.web;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import javax.annotation.PostConstruct;
-
-import org.springframework.beans.factory.BeanFactoryUtils;
-import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Primary;
+import org.springframework.context.annotation.Import;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
-import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link HttpMessageConverter}s.
- *
+ *
* @author Dave Syer
* @author Christian Dupuis
* @author Piotr Maj
+ * @author Oliver Gierke
*/
@Configuration
@ConditionalOnClass(HttpMessageConverter.class)
+@Import(JacksonAutoConfiguration.class)
public class HttpMessageConvertersAutoConfiguration {
@Autowired(required = false)
@@ -70,33 +66,6 @@ public class HttpMessageConvertersAutoConfiguration {
@Autowired
private HttpMapperProperties properties = new HttpMapperProperties();
- @Autowired
- private ListableBeanFactory beanFactory;
-
- @PostConstruct
- public void init() {
- Collection mappers = BeanFactoryUtils
- .beansOfTypeIncludingAncestors(this.beanFactory, ObjectMapper.class)
- .values();
- Collection modules = BeanFactoryUtils.beansOfTypeIncludingAncestors(
- this.beanFactory, Module.class).values();
- for (ObjectMapper mapper : mappers) {
- mapper.registerModules(modules);
- }
- }
-
- @Bean
- @ConditionalOnMissingBean
- @Primary
- public ObjectMapper jacksonObjectMapper() {
- ObjectMapper objectMapper = new ObjectMapper();
- if (this.properties.isJsonSortKeys()) {
- objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,
- true);
- }
- return objectMapper;
- }
-
@Bean
@ConditionalOnMissingBean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
@@ -106,7 +75,5 @@ public class HttpMessageConvertersAutoConfiguration {
converter.setPrettyPrint(this.properties.isJsonPrettyPrint());
return converter;
}
-
}
-
}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java
new file mode 100644
index 0000000000..455a5c46a1
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jackson/JacksonAutoConfigurationTests.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2012-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.boot.autoconfigure.jackson;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.hamcrest.Matchers;
+import org.joda.time.LocalDateTime;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.Module;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.datatype.joda.JodaModule;
+
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for {@link JacksonAutoConfiguration}.
+ *
+ * @author Dave Syer
+ * @author Oliver Gierke
+ */
+public class JacksonAutoConfigurationTests {
+
+ AnnotationConfigApplicationContext context;
+
+ @Before
+ public void setUp() {
+ this.context = new AnnotationConfigApplicationContext();
+ }
+
+ @After
+ public void tearDown() {
+ if (this.context != null) {
+ this.context.close();
+ }
+ }
+
+ @Test
+ public void registersJodaModuleAutomatically() {
+
+ this.context.register(JacksonAutoConfiguration.class);
+ this.context.refresh();
+
+ Collection modules = this.context.getBeansOfType(Module.class).values();
+ assertThat(modules, is(Matchers. iterableWithSize(1)));
+ assertThat(modules.iterator().next(), is(instanceOf(JodaModule.class)));
+
+ ObjectMapper objectMapper = this.context.getBean(ObjectMapper.class);
+ assertThat(objectMapper.canSerialize(LocalDateTime.class), is(true));
+ }
+
+ @Test
+ public void customJacksonModules() throws Exception {
+
+ this.context = new AnnotationConfigApplicationContext();
+ this.context.register(ModulesConfig.class, JacksonAutoConfiguration.class);
+ this.context.refresh();
+
+ ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
+
+ @SuppressWarnings({ "unchecked", "unused" })
+ ObjectMapper result = verify(mapper).registerModules(
+ (Iterable) argThat(hasItem(this.context.getBean("jacksonModule",
+ Module.class))));
+ }
+
+ @Test
+ public void doubleModuleRegistration() throws Exception {
+
+ this.context = new AnnotationConfigApplicationContext();
+ this.context.register(DoubleModulesConfig.class,
+ HttpMessageConvertersAutoConfiguration.class);
+ this.context.refresh();
+
+ ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
+ assertEquals("{\"foo\":\"bar\"}", mapper.writeValueAsString(new Foo()));
+ }
+
+ @Configuration
+ protected static class ModulesConfig {
+
+ @Bean
+ public Module jacksonModule() {
+ return new SimpleModule();
+ }
+
+ @Bean
+ @Primary
+ public ObjectMapper objectMapper() {
+ return Mockito.mock(ObjectMapper.class);
+ }
+ }
+
+ @Configuration
+ protected static class DoubleModulesConfig {
+
+ @Bean
+ public Module jacksonModule() {
+ SimpleModule module = new SimpleModule();
+ module.addSerializer(Foo.class, new JsonSerializer() {
+
+ @Override
+ public void serialize(Foo value, JsonGenerator jgen,
+ SerializerProvider provider) throws IOException,
+ JsonProcessingException {
+ jgen.writeStartObject();
+ jgen.writeStringField("foo", "bar");
+ jgen.writeEndObject();
+ }
+ });
+ return module;
+ }
+
+ @Bean
+ @Primary
+ public ObjectMapper objectMapper() {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.registerModule(jacksonModule());
+ return mapper;
+ }
+ }
+
+ protected static class Foo {
+
+ private String name;
+
+ private Foo() {
+
+ }
+
+ static Foo create() {
+ return new Foo();
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ }
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfigurationTests.java
index b050baf773..7679216d1a 100644
--- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfigurationTests.java
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/HttpMessageConvertersAutoConfigurationTests.java
@@ -16,38 +16,23 @@
package org.springframework.boot.autoconfigure.web;
-import java.io.IOException;
-
-import org.joda.time.LocalDateTime;
import org.junit.After;
import org.junit.Test;
-import org.mockito.Mockito;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.hasItem;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.verify;
/**
* Tests for {@link HttpMessageConvertersAutoConfiguration}.
- *
+ *
* @author Dave Syer
+ * @author Oliver Gierke
*/
public class HttpMessageConvertersAutoConfigurationTests {
@@ -62,52 +47,22 @@ public class HttpMessageConvertersAutoConfigurationTests {
@Test
public void customJacksonConverter() throws Exception {
+
this.context = new AnnotationConfigApplicationContext();
this.context.register(JacksonConfig.class,
HttpMessageConvertersAutoConfiguration.class);
this.context.refresh();
+
MappingJackson2HttpMessageConverter converter = this.context
.getBean(MappingJackson2HttpMessageConverter.class);
assertEquals(this.context.getBean(ObjectMapper.class),
converter.getObjectMapper());
+
HttpMessageConverters converters = this.context
.getBean(HttpMessageConverters.class);
assertTrue(converters.getConverters().contains(converter));
}
- @Test
- public void defaultJacksonModules() throws Exception {
- this.context = new AnnotationConfigApplicationContext();
- this.context.register(HttpMessageConvertersAutoConfiguration.class);
- this.context.refresh();
- ObjectMapper objectMapper = this.context.getBean(ObjectMapper.class);
- assertThat(objectMapper.canSerialize(LocalDateTime.class), equalTo(true));
- }
-
- @Test
- public void customJacksonModules() throws Exception {
- this.context = new AnnotationConfigApplicationContext();
- this.context.register(ModulesConfig.class,
- HttpMessageConvertersAutoConfiguration.class);
- this.context.refresh();
- ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
-
- @SuppressWarnings({ "unchecked", "unused" })
- ObjectMapper result = verify(mapper).registerModules(
- (Iterable) argThat(hasItem(this.context.getBean("jacksonModule",
- Module.class))));
- }
-
- @Test
- public void doubleModuleRegistration() throws Exception {
- this.context = new AnnotationConfigApplicationContext();
- this.context.register(DoubleModulesConfig.class,
- HttpMessageConvertersAutoConfiguration.class);
- this.context.refresh();
- ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
- assertEquals("{\"foo\":\"bar\"}", mapper.writeValueAsString(new Foo()));
- }
-
@Configuration
protected static class JacksonConfig {
@@ -122,75 +77,5 @@ public class HttpMessageConvertersAutoConfigurationTests {
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
-
}
-
- @Configuration
- protected static class ModulesConfig {
-
- @Bean
- public Module jacksonModule() {
- return new SimpleModule();
- }
-
- @Bean
- @Primary
- public ObjectMapper objectMapper() {
- return Mockito.mock(ObjectMapper.class);
- }
-
- }
-
- @Configuration
- protected static class DoubleModulesConfig {
-
- @Bean
- public Module jacksonModule() {
- SimpleModule module = new SimpleModule();
- module.addSerializer(Foo.class, new JsonSerializer() {
-
- @Override
- public void serialize(Foo value, JsonGenerator jgen,
- SerializerProvider provider) throws IOException,
- JsonProcessingException {
- jgen.writeStartObject();
- jgen.writeStringField("foo", "bar");
- jgen.writeEndObject();
- }
- });
- return module;
- }
-
- @Bean
- @Primary
- public ObjectMapper objectMapper() {
- ObjectMapper mapper = new ObjectMapper();
- mapper.registerModule(jacksonModule());
- return mapper;
- }
-
- }
-
- protected static class Foo {
-
- private String name;
-
- private Foo() {
-
- }
-
- static Foo create() {
- return new Foo();
- }
-
- public String getName() {
- return this.name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- }
-
}
diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index d9871684ba..a19ec3870a 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -370,6 +370,11 @@
jackson-datatype-joda
${jackson.version}
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ ${jackson.version}
+
com.gemstone.gemfire
gemfire