Allow Jackson features to be configured via the environment
Enhance JacksonAutoConfiguration to configure features on the ObjectMapper it creates based on the following configuration properties: spring.jackson.deserialization.* = true|false spring.jackson.generator.* = true|false spring.jackson.mapper.* = true|false spring.jackson.parser.* = true|false spring.jackson.serialization.* = true|false The final part of each property name maps onto an enum. The enums are: deserialization: com.fasterxml.jackson.databind.DeserializationFeature generator: com.fasterxml.jackson.core.JsonGenerator.Feature mapper: com.fasterxml.jackson.databind.MapperFeature parser: com.fasterxml.jackson.core.JsonParser.Feature serialization: com.fasterxml.jackson.databind.SerializationFeature Closes gh-1227
This commit is contained in:
parent
26ac68df05
commit
4b25b0e7a2
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.boot.autoconfigure.jackson;
|
package org.springframework.boot.autoconfigure.jackson;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
|
@ -33,6 +34,10 @@ import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.MapperFeature;
|
||||||
import com.fasterxml.jackson.databind.Module;
|
import com.fasterxml.jackson.databind.Module;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
|
@ -51,6 +56,7 @@ import com.fasterxml.jackson.datatype.jsr310.JSR310Module;
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Andy Wilkinson
|
||||||
* @since 1.1.0
|
* @since 1.1.0
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
|
|
@ -75,24 +81,73 @@ public class JacksonAutoConfiguration {
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnClass(ObjectMapper.class)
|
@ConditionalOnClass(ObjectMapper.class)
|
||||||
@EnableConfigurationProperties(HttpMapperProperties.class)
|
@EnableConfigurationProperties({ HttpMapperProperties.class, JacksonProperties.class })
|
||||||
static class JacksonObjectMapperAutoConfiguration {
|
static class JacksonObjectMapperAutoConfiguration {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private HttpMapperProperties properties = new HttpMapperProperties();
|
private HttpMapperProperties httpMapperProperties = new HttpMapperProperties();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JacksonProperties jacksonProperties = new JacksonProperties();
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Primary
|
@Primary
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public ObjectMapper jacksonObjectMapper() {
|
public ObjectMapper jacksonObjectMapper() {
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
if (this.properties.isJsonSortKeys()) {
|
|
||||||
|
if (this.httpMapperProperties.isJsonSortKeys()) {
|
||||||
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,
|
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configureDeserializationFeatures(objectMapper);
|
||||||
|
configureSerializationFeatures(objectMapper);
|
||||||
|
configureMapperFeatures(objectMapper);
|
||||||
|
configureParserFeatures(objectMapper);
|
||||||
|
configureGeneratorFeatures(objectMapper);
|
||||||
|
|
||||||
return objectMapper;
|
return objectMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void configureDeserializationFeatures(ObjectMapper objectMapper) {
|
||||||
|
for (Entry<DeserializationFeature, Boolean> entry : this.jacksonProperties
|
||||||
|
.getDeserialization().entrySet()) {
|
||||||
|
objectMapper.configure(entry.getKey(), isFeatureEnabled(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureSerializationFeatures(ObjectMapper objectMapper) {
|
||||||
|
for (Entry<SerializationFeature, Boolean> entry : this.jacksonProperties
|
||||||
|
.getSerialization().entrySet()) {
|
||||||
|
objectMapper.configure(entry.getKey(), isFeatureEnabled(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureMapperFeatures(ObjectMapper objectMapper) {
|
||||||
|
for (Entry<MapperFeature, Boolean> entry : this.jacksonProperties.getMapper()
|
||||||
|
.entrySet()) {
|
||||||
|
objectMapper.configure(entry.getKey(), isFeatureEnabled(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureParserFeatures(ObjectMapper objectMapper) {
|
||||||
|
for (Entry<JsonParser.Feature, Boolean> entry : this.jacksonProperties
|
||||||
|
.getParser().entrySet()) {
|
||||||
|
objectMapper.configure(entry.getKey(), isFeatureEnabled(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureGeneratorFeatures(ObjectMapper objectMapper) {
|
||||||
|
for (Entry<JsonGenerator.Feature, Boolean> entry : this.jacksonProperties
|
||||||
|
.getGenerator().entrySet()) {
|
||||||
|
objectMapper.configure(entry.getKey(), isFeatureEnabled(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isFeatureEnabled(Entry<?, Boolean> entry) {
|
||||||
|
return entry.getValue() != null && entry.getValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* 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.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.MapperFeature;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration properties to configure Jackson
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties(prefix = "spring.jackson")
|
||||||
|
public class JacksonProperties {
|
||||||
|
|
||||||
|
private Map<SerializationFeature, Boolean> serialization = new HashMap<SerializationFeature, Boolean>();
|
||||||
|
|
||||||
|
private Map<DeserializationFeature, Boolean> deserialization = new HashMap<DeserializationFeature, Boolean>();
|
||||||
|
|
||||||
|
private Map<MapperFeature, Boolean> mapper = new HashMap<MapperFeature, Boolean>();
|
||||||
|
|
||||||
|
private Map<JsonParser.Feature, Boolean> parser = new HashMap<JsonParser.Feature, Boolean>();
|
||||||
|
|
||||||
|
private Map<JsonGenerator.Feature, Boolean> generator = new HashMap<JsonGenerator.Feature, Boolean>();
|
||||||
|
|
||||||
|
public Map<SerializationFeature, Boolean> getSerialization() {
|
||||||
|
return this.serialization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<DeserializationFeature, Boolean> getDeserialization() {
|
||||||
|
return this.deserialization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<MapperFeature, Boolean> getMapper() {
|
||||||
|
return this.mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<JsonParser.Feature, Boolean> getParser() {
|
||||||
|
return this.parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<JsonGenerator.Feature, Boolean> getGenerator() {
|
||||||
|
return this.generator;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -25,16 +25,21 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
|
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
|
||||||
|
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
|
import com.fasterxml.jackson.databind.MapperFeature;
|
||||||
import com.fasterxml.jackson.databind.Module;
|
import com.fasterxml.jackson.databind.Module;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
import com.fasterxml.jackson.datatype.joda.JodaModule;
|
import com.fasterxml.jackson.datatype.joda.JodaModule;
|
||||||
|
|
@ -44,7 +49,9 @@ import static org.hamcrest.Matchers.hasItem;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Matchers.argThat;
|
import static org.mockito.Matchers.argThat;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
|
@ -101,6 +108,128 @@ public class JacksonAutoConfigurationTests {
|
||||||
assertEquals("{\"foo\":\"bar\"}", mapper.writeValueAsString(new Foo()));
|
assertEquals("{\"foo\":\"bar\"}", mapper.writeValueAsString(new Foo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enableSerializationFeature() throws Exception {
|
||||||
|
this.context.register(JacksonAutoConfiguration.class);
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context,
|
||||||
|
"spring.jackson.serialization.indent_output:true");
|
||||||
|
this.context.refresh();
|
||||||
|
ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
|
||||||
|
assertFalse(SerializationFeature.INDENT_OUTPUT.enabledByDefault());
|
||||||
|
assertTrue(mapper.getSerializationConfig().hasSerializationFeatures(
|
||||||
|
SerializationFeature.INDENT_OUTPUT.getMask()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disableSerializationFeature() throws Exception {
|
||||||
|
this.context.register(JacksonAutoConfiguration.class);
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context,
|
||||||
|
"spring.jackson.serialization.write_dates_as_timestamps:false");
|
||||||
|
this.context.refresh();
|
||||||
|
ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
|
||||||
|
assertTrue(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS.enabledByDefault());
|
||||||
|
assertFalse(mapper.getSerializationConfig().hasSerializationFeatures(
|
||||||
|
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS.getMask()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enableDeserializationFeature() throws Exception {
|
||||||
|
this.context.register(JacksonAutoConfiguration.class);
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context,
|
||||||
|
"spring.jackson.deserialization.use_big_decimal_for_floats:true");
|
||||||
|
this.context.refresh();
|
||||||
|
ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
|
||||||
|
assertFalse(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS.enabledByDefault());
|
||||||
|
assertTrue(mapper.getDeserializationConfig().hasDeserializationFeatures(
|
||||||
|
DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS.getMask()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disableDeserializationFeature() throws Exception {
|
||||||
|
this.context.register(JacksonAutoConfiguration.class);
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context,
|
||||||
|
"spring.jackson.deserialization.fail_on_unknown_properties:false");
|
||||||
|
this.context.refresh();
|
||||||
|
ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
|
||||||
|
assertTrue(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES.enabledByDefault());
|
||||||
|
assertFalse(mapper.getDeserializationConfig().hasDeserializationFeatures(
|
||||||
|
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES.getMask()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enableMapperFeature() throws Exception {
|
||||||
|
this.context.register(JacksonAutoConfiguration.class);
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context,
|
||||||
|
"spring.jackson.mapper.require_setters_for_getters:true");
|
||||||
|
this.context.refresh();
|
||||||
|
ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
|
||||||
|
assertFalse(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS.enabledByDefault());
|
||||||
|
assertTrue(mapper.getSerializationConfig().hasMapperFeatures(
|
||||||
|
MapperFeature.REQUIRE_SETTERS_FOR_GETTERS.getMask()));
|
||||||
|
assertTrue(mapper.getDeserializationConfig().hasMapperFeatures(
|
||||||
|
MapperFeature.REQUIRE_SETTERS_FOR_GETTERS.getMask()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disableMapperFeature() throws Exception {
|
||||||
|
this.context.register(JacksonAutoConfiguration.class);
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context,
|
||||||
|
"spring.jackson.mapper.use_annotations:false");
|
||||||
|
this.context.refresh();
|
||||||
|
ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
|
||||||
|
assertTrue(MapperFeature.USE_ANNOTATIONS.enabledByDefault());
|
||||||
|
assertFalse(mapper.getDeserializationConfig().hasMapperFeatures(
|
||||||
|
MapperFeature.USE_ANNOTATIONS.getMask()));
|
||||||
|
assertFalse(mapper.getSerializationConfig().hasMapperFeatures(
|
||||||
|
MapperFeature.USE_ANNOTATIONS.getMask()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enableParserFeature() throws Exception {
|
||||||
|
this.context.register(JacksonAutoConfiguration.class);
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context,
|
||||||
|
"spring.jackson.parser.allow_single_quotes:true");
|
||||||
|
this.context.refresh();
|
||||||
|
ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
|
||||||
|
assertFalse(JsonParser.Feature.ALLOW_SINGLE_QUOTES.enabledByDefault());
|
||||||
|
assertTrue(mapper.getFactory().isEnabled(JsonParser.Feature.ALLOW_SINGLE_QUOTES));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disableParserFeature() throws Exception {
|
||||||
|
this.context.register(JacksonAutoConfiguration.class);
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context,
|
||||||
|
"spring.jackson.parser.auto_close_source:false");
|
||||||
|
this.context.refresh();
|
||||||
|
ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
|
||||||
|
assertTrue(JsonParser.Feature.AUTO_CLOSE_SOURCE.enabledByDefault());
|
||||||
|
assertFalse(mapper.getFactory().isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enableGeneratorFeature() throws Exception {
|
||||||
|
this.context.register(JacksonAutoConfiguration.class);
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context,
|
||||||
|
"spring.jackson.generator.write_numbers_as_strings:true");
|
||||||
|
this.context.refresh();
|
||||||
|
ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
|
||||||
|
assertFalse(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS.enabledByDefault());
|
||||||
|
assertTrue(mapper.getFactory().isEnabled(
|
||||||
|
JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disableGeneratorFeature() throws Exception {
|
||||||
|
this.context.register(JacksonAutoConfiguration.class);
|
||||||
|
EnvironmentTestUtils.addEnvironment(this.context,
|
||||||
|
"spring.jackson.generator.auto_close_target:false");
|
||||||
|
this.context.refresh();
|
||||||
|
ObjectMapper mapper = this.context.getBean(ObjectMapper.class);
|
||||||
|
assertTrue(JsonGenerator.Feature.AUTO_CLOSE_TARGET.enabledByDefault());
|
||||||
|
assertFalse(mapper.getFactory()
|
||||||
|
.isEnabled(JsonGenerator.Feature.AUTO_CLOSE_TARGET));
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
protected static class ModulesConfig {
|
protected static class ModulesConfig {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,13 @@ content into your application; rather pick only the properties that you need.
|
||||||
spring.resources.cache-period= # cache timeouts in headers sent to browser
|
spring.resources.cache-period= # cache timeouts in headers sent to browser
|
||||||
spring.resources.add-mappings=true # if default mappings should be added
|
spring.resources.add-mappings=true # if default mappings should be added
|
||||||
|
|
||||||
|
# JACKSON ({sc-spring-boot-autoconfigure}}/jackson/JacksonProperties.{sc-ext}[JacksonProperties])
|
||||||
|
spring.jackson.deserialization.*= # see Jackson's DeserializationFeature
|
||||||
|
spring.jackson.generator.*= # see Jackson's JsonGenerator.Feature
|
||||||
|
spring.jackson.mapper.*= # see Jackson's MapperFeature
|
||||||
|
spring.jackson.parser.*= # see Jackson's JsonParser.Feature
|
||||||
|
spring.jackson.serialization.*= # see Jackson's SerializationFeature
|
||||||
|
|
||||||
# THYMELEAF ({sc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{sc-ext}[ThymeleafAutoConfiguration])
|
# THYMELEAF ({sc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{sc-ext}[ThymeleafAutoConfiguration])
|
||||||
spring.thymeleaf.prefix=classpath:/templates/
|
spring.thymeleaf.prefix=classpath:/templates/
|
||||||
spring.thymeleaf.suffix=.html
|
spring.thymeleaf.suffix=.html
|
||||||
|
|
|
||||||
|
|
@ -654,15 +654,43 @@ conversion in an HTTP exchange. If Jackson is on the classpath you already get a
|
||||||
converter with a vanilla `ObjectMapper`. Spring Boot has some features to make it easier
|
converter with a vanilla `ObjectMapper`. Spring Boot has some features to make it easier
|
||||||
to customize this behavior.
|
to customize this behavior.
|
||||||
|
|
||||||
The smallest change that might work is to just add beans of type
|
You can configure the vanilla `ObjectMapper` using the environment. Jackson provides an
|
||||||
`com.fasterxml.jackson.databind.Module` to your context. They will be registered with the
|
extensive suite of simple on/off features that can be used to configure various aspects
|
||||||
default `ObjectMapper` and then injected into the default message converter. To replace
|
of its processing. These features are described in five enums in Jackson which map onto
|
||||||
the default `ObjectMapper` completely, define a `@Bean` of that type and mark it as
|
properties in the environment:
|
||||||
`@Primary`.
|
|
||||||
|
|
||||||
In addition, if your context contains any beans of type `ObjectMapper` then all of the
|
|===
|
||||||
`Module` beans will be registered with all of the mappers. So there is a global mechanism
|
|Jackson enum|Environment property
|
||||||
for contributing custom modules when you add new features to your application.
|
|
||||||
|
|`com.fasterxml.jackson.databind.DeserializationFeature`
|
||||||
|
|`spring.jackson.deserialization.<feature_name>=true\|false`
|
||||||
|
|
||||||
|
|`com.fasterxml.jackson.core.JsonGenerator.Feature`
|
||||||
|
|`spring.jackson.generator.<feature_name>=true\|false`
|
||||||
|
|
||||||
|
|`com.fasterxml.jackson.databind.MapperFeature`
|
||||||
|
|`spring.jackson.mapper.<feature_name>=true\|false`
|
||||||
|
|
||||||
|
|`com.fasterxml.jackson.core.JsonParser.Feature`
|
||||||
|
|`spring.jackson.parser.<feature_name>=true\|false`
|
||||||
|
|
||||||
|
|`com.fasterxml.jackson.databind.SerializationFeature`
|
||||||
|
|`spring.jackson.serialization.<feature_name>=true\|false`
|
||||||
|
|===
|
||||||
|
|
||||||
|
For example, to allow deserialization to continue when an unknown property is encountered
|
||||||
|
during deserialization, set `spring.jackson.deserialization.fail_on_unknown_properties=false`.
|
||||||
|
Note that, thanks to the use of <<boot-features-external-config-relaxed-binding, relaxed binding>>,
|
||||||
|
the case of `fail_on_unknown_properties` doesn't have to match the case of the corresponding
|
||||||
|
enum constant which is `FAIL_ON_UNKNOWN_PROPERTIES`.
|
||||||
|
|
||||||
|
If you want to replace the default `ObjectMapper` completely, define a `@Bean` of that type
|
||||||
|
and mark it as `@Primary`.
|
||||||
|
|
||||||
|
Another way to customize Jackson is to add beans of type
|
||||||
|
`com.fasterxml.jackson.databind.Module` to your context. They will be registered with every
|
||||||
|
bean of type `ObjectMapper`, providing a global mechanism for contributing custom modules
|
||||||
|
when you add new features to your application.
|
||||||
|
|
||||||
Finally, if you provide any `@Beans` of type `MappingJackson2HttpMessageConverter` then
|
Finally, if you provide any `@Beans` of type `MappingJackson2HttpMessageConverter` then
|
||||||
they will replace the default value in the MVC configuration. Also, a convenience bean is
|
they will replace the default value in the MVC configuration. Also, a convenience bean is
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue