mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Prefer Jackson unless user explicity states preference for Gson
This commit rewords the changes made in d718a80
so that simply adding
Gson to the classpath isn't sufficient to stop Jackson being used
for HTTP JSON mapping. To use Gson, the user must now either remove
Jackson from the classpath (not an option if they also wish to use
the Actuator) or configure the spring.http.converters.preferred-mapper
property with a value gson.
Closes gh-2247
This commit is contained in:
parent
e5d653dbd4
commit
230048ae8b
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.web;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* Configuration for HTTP Message converters that use Gson
|
||||
*
|
||||
* @author awilkinson
|
||||
* @since 1.2.2
|
||||
*/
|
||||
@Configuration
|
||||
class GsonHttpMessageConvertersConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(Gson.class)
|
||||
@ConditionalOnBean(Gson.class)
|
||||
@Conditional(PreferGsonOrMissingJacksonCondition.class)
|
||||
protected static class GsonHttpMessageConverterConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson) {
|
||||
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
|
||||
converter.setGson(gson);
|
||||
return converter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class PreferGsonOrMissingJacksonCondition extends AnyNestedCondition {
|
||||
|
||||
public PreferGsonOrMissingJacksonCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "gson", matchIfMissing = false)
|
||||
static class GsonPreferred {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean(MappingJackson2HttpMessageConverter.class)
|
||||
static class JacksonMissing {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -22,7 +22,6 @@ import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
|
||||
@ -30,16 +29,9 @@ 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.Import;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link HttpMessageConverter}s.
|
||||
@ -56,8 +48,12 @@ import com.google.gson.Gson;
|
||||
@Configuration
|
||||
@ConditionalOnClass(HttpMessageConverter.class)
|
||||
@AutoConfigureAfter({ GsonAutoConfiguration.class, JacksonAutoConfiguration.class })
|
||||
@Import({ JacksonHttpMessageConvertersConfiguration.class,
|
||||
GsonHttpMessageConvertersConfiguration.class })
|
||||
public class HttpMessageConvertersAutoConfiguration {
|
||||
|
||||
static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-mapper";
|
||||
|
||||
@Autowired(required = false)
|
||||
private final List<HttpMessageConverter<?>> converters = Collections.emptyList();
|
||||
|
||||
@ -67,72 +63,6 @@ public class HttpMessageConvertersAutoConfiguration {
|
||||
return new HttpMessageConverters(this.converters);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(ObjectMapper.class)
|
||||
@ConditionalOnBean(ObjectMapper.class)
|
||||
@ConditionalOnMissingBean(GsonHttpMessageConverter.class)
|
||||
@EnableConfigurationProperties(HttpMapperProperties.class)
|
||||
@SuppressWarnings("deprecation")
|
||||
protected static class MappingJackson2HttpMessageConverterConfiguration {
|
||||
|
||||
// This can be removed when the deprecated class is removed (the ObjectMapper will
|
||||
// already have all the correct properties).
|
||||
@Autowired
|
||||
private HttpMapperProperties properties = new HttpMapperProperties();
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
|
||||
ObjectMapper objectMapper) {
|
||||
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(
|
||||
objectMapper);
|
||||
if (this.properties.isJsonPrettyPrint() != null) {
|
||||
converter.setPrettyPrint(this.properties.isJsonPrettyPrint());
|
||||
}
|
||||
return converter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(XmlMapper.class)
|
||||
@ConditionalOnBean(Jackson2ObjectMapperBuilder.class)
|
||||
@EnableConfigurationProperties(HttpMapperProperties.class)
|
||||
@SuppressWarnings("deprecation")
|
||||
protected static class MappingJackson2XmlHttpMessageConverterConfiguration {
|
||||
|
||||
@Autowired
|
||||
private HttpMapperProperties properties = new HttpMapperProperties();
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter(
|
||||
Jackson2ObjectMapperBuilder builder) {
|
||||
MappingJackson2XmlHttpMessageConverter converter = new MappingJackson2XmlHttpMessageConverter();
|
||||
converter.setObjectMapper(builder.createXmlMapper(true).build());
|
||||
if (this.properties.isJsonPrettyPrint() != null) {
|
||||
converter.setPrettyPrint(this.properties.isJsonPrettyPrint());
|
||||
}
|
||||
return converter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(Gson.class)
|
||||
@ConditionalOnBean(Gson.class)
|
||||
protected static class GsonHttpMessageConverterConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson) {
|
||||
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
|
||||
converter.setGson(gson);
|
||||
return converter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(StringHttpMessageConverter.class)
|
||||
@EnableConfigurationProperties(HttpEncodingProperties.class)
|
||||
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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.web;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
|
||||
/**
|
||||
* Configuration for HTTP message converters that use Jackson
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 1.2.2
|
||||
*/
|
||||
@Configuration
|
||||
class JacksonHttpMessageConvertersConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(ObjectMapper.class)
|
||||
@ConditionalOnBean(ObjectMapper.class)
|
||||
@EnableConfigurationProperties(HttpMapperProperties.class)
|
||||
@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "jackson", matchIfMissing = true)
|
||||
@SuppressWarnings("deprecation")
|
||||
protected static class MappingJackson2HttpMessageConverterConfiguration {
|
||||
|
||||
// This can be removed when the deprecated class is removed (the ObjectMapper will
|
||||
// already have all the correct properties).
|
||||
@Autowired
|
||||
private HttpMapperProperties properties = new HttpMapperProperties();
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
|
||||
ObjectMapper objectMapper) {
|
||||
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(
|
||||
objectMapper);
|
||||
if (this.properties.isJsonPrettyPrint() != null) {
|
||||
converter.setPrettyPrint(this.properties.isJsonPrettyPrint());
|
||||
}
|
||||
return converter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(XmlMapper.class)
|
||||
@ConditionalOnBean(Jackson2ObjectMapperBuilder.class)
|
||||
@EnableConfigurationProperties(HttpMapperProperties.class)
|
||||
@SuppressWarnings("deprecation")
|
||||
protected static class MappingJackson2XmlHttpMessageConverterConfiguration {
|
||||
|
||||
@Autowired
|
||||
private HttpMapperProperties properties = new HttpMapperProperties();
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter(
|
||||
Jackson2ObjectMapperBuilder builder) {
|
||||
MappingJackson2XmlHttpMessageConverter converter = new MappingJackson2XmlHttpMessageConverter();
|
||||
converter.setObjectMapper(builder.createXmlMapper(true).build());
|
||||
if (this.properties.isJsonPrettyPrint() != null) {
|
||||
converter.setPrettyPrint(this.properties.isJsonPrettyPrint());
|
||||
}
|
||||
return converter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -130,11 +130,26 @@ public class HttpMessageConvertersAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gsonIsPreferredWhenBothGsonAndJacksonAreAvailable() {
|
||||
public void jacksonIsPreferredByDefaultWhenBothGsonAndJacksonAreAvailable() {
|
||||
this.context.register(GsonAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertConverterBeanExists(MappingJackson2HttpMessageConverter.class,
|
||||
"mappingJackson2HttpMessageConverter");
|
||||
assertConverterBeanRegisteredWithHttpMessageConverters(MappingJackson2HttpMessageConverter.class);
|
||||
assertEquals(0, this.context.getBeansOfType(GsonHttpMessageConverter.class)
|
||||
.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gsonCanBePreferredWhenBothGsonAndJacksonAreAvailable() {
|
||||
this.context.register(GsonAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class);
|
||||
EnvironmentTestUtils.addEnvironment(this.context,
|
||||
"spring.http.converters.preferred-mapper:gson");
|
||||
this.context.refresh();
|
||||
assertConverterBeanExists(GsonHttpMessageConverter.class,
|
||||
"gsonHttpMessageConverter");
|
||||
assertConverterBeanRegisteredWithHttpMessageConverters(GsonHttpMessageConverter.class);
|
||||
|
Loading…
Reference in New Issue
Block a user