Merge pull request #11498 from ioanngolovko
* pr/11498: Polish GSON customization support Allow GSON customization via properties or beans
This commit is contained in:
		
						commit
						6ea6adb10e
					
				| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2017 the original author or authors.
 | 
			
		||||
 * Copyright 2012-2018 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.
 | 
			
		||||
| 
						 | 
				
			
			@ -16,28 +16,88 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.boot.autoconfigure.gson;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import com.google.gson.GsonBuilder;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 | 
			
		||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
 | 
			
		||||
import org.springframework.boot.context.properties.PropertyMapper;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.core.Ordered;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * {@link EnableAutoConfiguration Auto-configuration} for Gson.
 | 
			
		||||
 *
 | 
			
		||||
 * @author David Liu
 | 
			
		||||
 * @author Ivan Golovko
 | 
			
		||||
 * @since 1.2.0
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
@ConditionalOnClass(Gson.class)
 | 
			
		||||
@EnableConfigurationProperties(GsonProperties.class)
 | 
			
		||||
public class GsonAutoConfiguration {
 | 
			
		||||
 | 
			
		||||
	@Bean
 | 
			
		||||
	@ConditionalOnMissingBean
 | 
			
		||||
	public Gson gson() {
 | 
			
		||||
		return new Gson();
 | 
			
		||||
	public GsonBuilder gsonBuilder(List<GsonBuilderCustomizer> customizers) {
 | 
			
		||||
		GsonBuilder builder = new GsonBuilder();
 | 
			
		||||
		customizers.forEach(c -> c.customize(builder));
 | 
			
		||||
		return builder;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Bean
 | 
			
		||||
	@ConditionalOnMissingBean(Gson.class)
 | 
			
		||||
	public Gson gson(GsonBuilder gsonBuilder) {
 | 
			
		||||
		return gsonBuilder.create();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Bean
 | 
			
		||||
	public StandardGsonBuilderCustomizer standardGsonBuilderCustomizer(
 | 
			
		||||
			GsonProperties gsonProperties) {
 | 
			
		||||
		return new StandardGsonBuilderCustomizer(gsonProperties);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static final class StandardGsonBuilderCustomizer
 | 
			
		||||
			implements GsonBuilderCustomizer, Ordered {
 | 
			
		||||
 | 
			
		||||
		private final GsonProperties properties;
 | 
			
		||||
 | 
			
		||||
		StandardGsonBuilderCustomizer(GsonProperties properties) {
 | 
			
		||||
			this.properties = properties;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public int getOrder() {
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public void customize(GsonBuilder builder) {
 | 
			
		||||
			GsonProperties properties = this.properties;
 | 
			
		||||
			PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
 | 
			
		||||
			map.from(properties::getGenerateNonExecutableJson)
 | 
			
		||||
					.toCall(builder::generateNonExecutableJson);
 | 
			
		||||
			map.from(properties::getExcludeFieldsWithoutExposeAnnotation)
 | 
			
		||||
					.toCall(builder::excludeFieldsWithoutExposeAnnotation);
 | 
			
		||||
			map.from(properties::getSerializeNulls).toCall(builder::serializeNulls);
 | 
			
		||||
			map.from(properties::getEnableComplexMapKeySerialization)
 | 
			
		||||
					.toCall(builder::enableComplexMapKeySerialization);
 | 
			
		||||
			map.from(properties::getDisableInnerClassSerialization)
 | 
			
		||||
					.toCall(builder::disableInnerClassSerialization);
 | 
			
		||||
			map.from(properties::getLongSerializationPolicy)
 | 
			
		||||
					.to(builder::setLongSerializationPolicy);
 | 
			
		||||
			map.from(properties::getFieldNamingPolicy).to(builder::setFieldNamingPolicy);
 | 
			
		||||
			map.from(properties::getPrettyPrinting).toCall(builder::setPrettyPrinting);
 | 
			
		||||
			map.from(properties::getLenient).toCall(builder::setLenient);
 | 
			
		||||
			map.from(properties::getDisableHtmlEscaping)
 | 
			
		||||
					.toCall(builder::disableHtmlEscaping);
 | 
			
		||||
			map.from(properties::getDateFormat).to(builder::setDateFormat);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2018 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.gson;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import com.google.gson.GsonBuilder;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Callback interface that can be implemented by beans wishing to further customize the
 | 
			
		||||
 * {@link Gson} via {@link GsonBuilder} retaining its default auto-configuration.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Ivan Golovko
 | 
			
		||||
 * @since 2.0.0
 | 
			
		||||
 */
 | 
			
		||||
@FunctionalInterface
 | 
			
		||||
public interface GsonBuilderCustomizer {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Customize the GsonBuilder.
 | 
			
		||||
	 * @param gsonBuilder the GsonBuilder to customize
 | 
			
		||||
	 */
 | 
			
		||||
	void customize(GsonBuilder gsonBuilder);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,184 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2018 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.gson;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.FieldNamingPolicy;
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import com.google.gson.LongSerializationPolicy;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.context.properties.ConfigurationProperties;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configuration properties to configure {@link Gson}.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Ivan Golovko
 | 
			
		||||
 * @since 2.0.0
 | 
			
		||||
 */
 | 
			
		||||
@ConfigurationProperties(prefix = "spring.gson")
 | 
			
		||||
public class GsonProperties {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Whether to generate non executable JSON by prefixing the output with some special
 | 
			
		||||
	 * text.
 | 
			
		||||
	 */
 | 
			
		||||
	private Boolean generateNonExecutableJson;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Whether to exclude all fields from consideration for serialization or
 | 
			
		||||
	 * deserialization that do not have the "Expose" annotation.
 | 
			
		||||
	 */
 | 
			
		||||
	private Boolean excludeFieldsWithoutExposeAnnotation;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Whether to to serialize null fields.
 | 
			
		||||
	 */
 | 
			
		||||
	private Boolean serializeNulls;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Whether to enabled serialization of complex map keys (i.e. non-primitives).
 | 
			
		||||
	 */
 | 
			
		||||
	private Boolean enableComplexMapKeySerialization;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Whether to exclude inner classes during serialization.
 | 
			
		||||
	 */
 | 
			
		||||
	private Boolean disableInnerClassSerialization;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Serialization policy for Long and long types.
 | 
			
		||||
	 */
 | 
			
		||||
	private LongSerializationPolicy longSerializationPolicy;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The naming policy that should be applied to an object's field during serialization
 | 
			
		||||
	 * and deserialization.
 | 
			
		||||
	 */
 | 
			
		||||
	private FieldNamingPolicy fieldNamingPolicy;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Whether to output serialized JSON that fits in a page for pretty printing.
 | 
			
		||||
	 */
 | 
			
		||||
	private Boolean prettyPrinting;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Whether to be lenient about parsing JSON that doesn't conform to RFC 4627.
 | 
			
		||||
	 */
 | 
			
		||||
	private Boolean lenient;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Whether to disable the escaping of HTML characters such as '<' '>' etc.
 | 
			
		||||
	 */
 | 
			
		||||
	private Boolean disableHtmlEscaping;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The format to use when serializing Date objects.
 | 
			
		||||
	 */
 | 
			
		||||
	private String dateFormat;
 | 
			
		||||
 | 
			
		||||
	public Boolean getGenerateNonExecutableJson() {
 | 
			
		||||
		return this.generateNonExecutableJson;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setGenerateNonExecutableJson(Boolean generateNonExecutableJson) {
 | 
			
		||||
		this.generateNonExecutableJson = generateNonExecutableJson;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Boolean getExcludeFieldsWithoutExposeAnnotation() {
 | 
			
		||||
		return this.excludeFieldsWithoutExposeAnnotation;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setExcludeFieldsWithoutExposeAnnotation(
 | 
			
		||||
			Boolean excludeFieldsWithoutExposeAnnotation) {
 | 
			
		||||
		this.excludeFieldsWithoutExposeAnnotation = excludeFieldsWithoutExposeAnnotation;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Boolean getSerializeNulls() {
 | 
			
		||||
		return this.serializeNulls;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setSerializeNulls(Boolean serializeNulls) {
 | 
			
		||||
		this.serializeNulls = serializeNulls;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Boolean getEnableComplexMapKeySerialization() {
 | 
			
		||||
		return this.enableComplexMapKeySerialization;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setEnableComplexMapKeySerialization(
 | 
			
		||||
			Boolean enableComplexMapKeySerialization) {
 | 
			
		||||
		this.enableComplexMapKeySerialization = enableComplexMapKeySerialization;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Boolean getDisableInnerClassSerialization() {
 | 
			
		||||
		return this.disableInnerClassSerialization;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setDisableInnerClassSerialization(
 | 
			
		||||
			Boolean disableInnerClassSerialization) {
 | 
			
		||||
		this.disableInnerClassSerialization = disableInnerClassSerialization;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public LongSerializationPolicy getLongSerializationPolicy() {
 | 
			
		||||
		return this.longSerializationPolicy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setLongSerializationPolicy(
 | 
			
		||||
			LongSerializationPolicy longSerializationPolicy) {
 | 
			
		||||
		this.longSerializationPolicy = longSerializationPolicy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public FieldNamingPolicy getFieldNamingPolicy() {
 | 
			
		||||
		return this.fieldNamingPolicy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setFieldNamingPolicy(FieldNamingPolicy fieldNamingPolicy) {
 | 
			
		||||
		this.fieldNamingPolicy = fieldNamingPolicy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Boolean getPrettyPrinting() {
 | 
			
		||||
		return this.prettyPrinting;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setPrettyPrinting(Boolean prettyPrinting) {
 | 
			
		||||
		this.prettyPrinting = prettyPrinting;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Boolean getLenient() {
 | 
			
		||||
		return this.lenient;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setLenient(Boolean lenient) {
 | 
			
		||||
		this.lenient = lenient;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Boolean getDisableHtmlEscaping() {
 | 
			
		||||
		return this.disableHtmlEscaping;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setDisableHtmlEscaping(Boolean disableHtmlEscaping) {
 | 
			
		||||
		this.disableHtmlEscaping = disableHtmlEscaping;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public String getDateFormat() {
 | 
			
		||||
		return this.dateFormat;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void setDateFormat(String dateFormat) {
 | 
			
		||||
		this.dateFormat = dateFormat;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2012-2017 the original author or authors.
 | 
			
		||||
 * Copyright 2012-2018 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.
 | 
			
		||||
| 
						 | 
				
			
			@ -16,12 +16,22 @@
 | 
			
		|||
 | 
			
		||||
package org.springframework.boot.autoconfigure.gson;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.LinkedHashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import com.google.gson.ExclusionStrategy;
 | 
			
		||||
import com.google.gson.FieldAttributes;
 | 
			
		||||
import com.google.gson.FieldNamingPolicy;
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import org.junit.After;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import com.google.gson.LongSerializationPolicy;
 | 
			
		||||
import org.joda.time.DateTime;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 | 
			
		||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
 | 
			
		||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -29,36 +39,233 @@ import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		|||
 * Tests for {@link GsonAutoConfiguration}.
 | 
			
		||||
 *
 | 
			
		||||
 * @author David Liu
 | 
			
		||||
 * @author Ivan Golovko
 | 
			
		||||
 */
 | 
			
		||||
public class GsonAutoConfigurationTests {
 | 
			
		||||
 | 
			
		||||
	AnnotationConfigApplicationContext context;
 | 
			
		||||
 | 
			
		||||
	@Before
 | 
			
		||||
	public void setUp() {
 | 
			
		||||
		this.context = new AnnotationConfigApplicationContext();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@After
 | 
			
		||||
	public void tearDown() {
 | 
			
		||||
		if (this.context != null) {
 | 
			
		||||
			this.context.close();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
 | 
			
		||||
			.withConfiguration(AutoConfigurations.of(GsonAutoConfiguration.class));
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void gsonRegistration() {
 | 
			
		||||
		this.context.register(GsonAutoConfiguration.class);
 | 
			
		||||
		this.context.refresh();
 | 
			
		||||
		Gson gson = this.context.getBean(Gson.class);
 | 
			
		||||
		assertThat(gson.toJson(new DataObject())).isEqualTo("{\"data\":\"hello\"}");
 | 
			
		||||
		this.contextRunner.run(context -> {
 | 
			
		||||
			Gson gson = context.getBean(Gson.class);
 | 
			
		||||
			assertThat(gson.toJson(new DataObject())).isEqualTo("{\"data\":1}");
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void generateNonExecutableJson() {
 | 
			
		||||
		this.contextRunner
 | 
			
		||||
				.withPropertyValues("spring.gson.generate-non-executable-json:true")
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					assertThat(gson.toJson(new DataObject()))
 | 
			
		||||
							.isNotEqualTo("{\"data\":1}");
 | 
			
		||||
					assertThat(gson.toJson(new DataObject())).endsWith("{\"data\":1}");
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void excludeFieldsWithoutExposeAnnotation() {
 | 
			
		||||
		this.contextRunner
 | 
			
		||||
				.withPropertyValues(
 | 
			
		||||
						"spring.gson.exclude-fields-without-expose-annotation:true")
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					assertThat(gson.toJson(new DataObject())).isEqualTo("{}");
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void serializeNulls() {
 | 
			
		||||
		this.contextRunner.withPropertyValues("spring.gson.serialize-nulls:true")
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					assertThat(gson.serializeNulls()).isTrue();
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void enableComplexMapKeySerialization() {
 | 
			
		||||
		this.contextRunner
 | 
			
		||||
				.withPropertyValues(
 | 
			
		||||
						"spring.gson.enable-complex-map-key-serialization:true")
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					Map<DataObject, String> original = new LinkedHashMap<>();
 | 
			
		||||
					original.put(new DataObject(), "a");
 | 
			
		||||
					assertThat(gson.toJson(original)).isEqualTo("[[{\"data\":1},\"a\"]]");
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void notDisableInnerClassSerialization() {
 | 
			
		||||
		this.contextRunner.run(context -> {
 | 
			
		||||
			Gson gson = context.getBean(Gson.class);
 | 
			
		||||
			WrapperObject wrapperObject = new WrapperObject();
 | 
			
		||||
			assertThat(gson.toJson(wrapperObject.new NestedObject()))
 | 
			
		||||
					.isEqualTo("{\"data\":\"nested\"}");
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void disableInnerClassSerialization() {
 | 
			
		||||
		this.contextRunner
 | 
			
		||||
				.withPropertyValues("spring.gson.disable-inner-class-serialization:true")
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					WrapperObject wrapperObject = new WrapperObject();
 | 
			
		||||
					assertThat(gson.toJson(wrapperObject.new NestedObject()))
 | 
			
		||||
							.isEqualTo("null");
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void withLongSerializationPolicy() {
 | 
			
		||||
		this.contextRunner.withPropertyValues(
 | 
			
		||||
				"spring.gson.long-serialization-policy:" + LongSerializationPolicy.STRING)
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					assertThat(gson.toJson(new DataObject()))
 | 
			
		||||
							.isEqualTo("{\"data\":\"1\"}");
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void withFieldNamingPolicy() {
 | 
			
		||||
		FieldNamingPolicy fieldNamingPolicy = FieldNamingPolicy.UPPER_CAMEL_CASE;
 | 
			
		||||
		this.contextRunner
 | 
			
		||||
				.withPropertyValues(
 | 
			
		||||
						"spring.gson.field-naming-policy:" + fieldNamingPolicy)
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					assertThat(gson.fieldNamingStrategy()).isEqualTo(fieldNamingPolicy);
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void additionalGsonBuilderCustomization() {
 | 
			
		||||
		this.contextRunner.withUserConfiguration(GsonBuilderCustomConfig.class)
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					assertThat(gson.toJson(new DataObject())).isEqualTo("{}");
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void withPrettyPrinting() {
 | 
			
		||||
		this.contextRunner.withPropertyValues("spring.gson.pretty-printing:true")
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					assertThat(gson.toJson(new DataObject()))
 | 
			
		||||
							.isEqualTo("{\n  \"data\": 1\n}");
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void withoutLenient() throws Exception {
 | 
			
		||||
		this.contextRunner.run(context -> {
 | 
			
		||||
			Gson gson = context.getBean(Gson.class);
 | 
			
		||||
			/*
 | 
			
		||||
			 * It seems, that lenient setting not work in version 2.8.2 We get access to
 | 
			
		||||
			 * it via reflection
 | 
			
		||||
			 */
 | 
			
		||||
			Field lenientField = gson.getClass().getDeclaredField("lenient");
 | 
			
		||||
			lenientField.setAccessible(true);
 | 
			
		||||
			boolean lenient = lenientField.getBoolean(gson);
 | 
			
		||||
 | 
			
		||||
			assertThat(lenient).isFalse();
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void withLenient() throws Exception {
 | 
			
		||||
		this.contextRunner.withPropertyValues("spring.gson.lenient:true").run(context -> {
 | 
			
		||||
			Gson gson = context.getBean(Gson.class);
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * It seems, that lenient setting not work in version 2.8.0 of gson We get
 | 
			
		||||
			 * access to it via reflection
 | 
			
		||||
			 */
 | 
			
		||||
			Field lenientField = gson.getClass().getDeclaredField("lenient");
 | 
			
		||||
			lenientField.setAccessible(true);
 | 
			
		||||
			boolean lenient = lenientField.getBoolean(gson);
 | 
			
		||||
 | 
			
		||||
			assertThat(lenient).isTrue();
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void withHtmlEscaping() {
 | 
			
		||||
		this.contextRunner.run(context -> {
 | 
			
		||||
			Gson gson = context.getBean(Gson.class);
 | 
			
		||||
			assertThat(gson.htmlSafe()).isTrue();
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void withoutHtmlEscaping() {
 | 
			
		||||
		this.contextRunner.withPropertyValues("spring.gson.disable-html-escaping:true")
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					assertThat(gson.htmlSafe()).isFalse();
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void customDateFormat() {
 | 
			
		||||
		this.contextRunner.withPropertyValues("spring.gson.date-format:H")
 | 
			
		||||
				.run(context -> {
 | 
			
		||||
					Gson gson = context.getBean(Gson.class);
 | 
			
		||||
					DateTime dateTime = new DateTime(1988, 6, 25, 20, 30);
 | 
			
		||||
					Date date = dateTime.toDate();
 | 
			
		||||
					assertThat(gson.toJson(date)).isEqualTo("\"20\"");
 | 
			
		||||
				});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	protected static class GsonBuilderCustomConfig {
 | 
			
		||||
 | 
			
		||||
		@Bean
 | 
			
		||||
		public GsonBuilderCustomizer customSerializationExclusionStrategy() {
 | 
			
		||||
			return (gsonBuilder) -> gsonBuilder
 | 
			
		||||
					.addSerializationExclusionStrategy(new ExclusionStrategy() {
 | 
			
		||||
						@Override
 | 
			
		||||
						public boolean shouldSkipField(FieldAttributes fieldAttributes) {
 | 
			
		||||
							return "data".equals(fieldAttributes.getName());
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						@Override
 | 
			
		||||
						public boolean shouldSkipClass(Class<?> aClass) {
 | 
			
		||||
							return false;
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public class DataObject {
 | 
			
		||||
 | 
			
		||||
		public static final String STATIC_DATA = "bye";
 | 
			
		||||
 | 
			
		||||
		@SuppressWarnings("unused")
 | 
			
		||||
		private String data = "hello";
 | 
			
		||||
		private Long data = 1L;
 | 
			
		||||
 | 
			
		||||
		public void setData(Long data) {
 | 
			
		||||
			this.data = data;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public class WrapperObject {
 | 
			
		||||
 | 
			
		||||
		@SuppressWarnings("unused")
 | 
			
		||||
		class NestedObject {
 | 
			
		||||
 | 
			
		||||
			private String data = "nested";
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -340,6 +340,19 @@ content into your application. Rather, pick only the properties that you need.
 | 
			
		|||
	spring.jackson.serialization.*= # Jackson on/off features that affect the way Java objects are serialized.
 | 
			
		||||
	spring.jackson.time-zone= #  Time zone used when formatting dates. For instance, "America/Los_Angeles" or "GMT+10".
 | 
			
		||||
 | 
			
		||||
	# GSON ({sc-spring-boot-autoconfigure}/gson/GsonProperties.{sc-ext}[GsonProperties])
 | 
			
		||||
	spring.gson.date-format= # The format to use when serializing Date objects.
 | 
			
		||||
	spring.gson.disable-html-escaping= # Whether to disable the escaping of HTML characters such as '<' '>' etc.
 | 
			
		||||
	spring.gson.disable-inner-class-serialization= # Whether to exclude inner classes during serialization.
 | 
			
		||||
	spring.gson.enable-complex-map-key-serialization= # Whether to enabled serialization of complex map keys (i.e. non-primitives).
 | 
			
		||||
	spring.gson.exclude-fields-without-expose-annotation= # Whether to exclude all fields from consideration for serialization or deserialization that do not have the "Expose" annotation.
 | 
			
		||||
	spring.gson.field-naming-policy= # The naming policy that should be applied to an object's field during serialization and deserialization.
 | 
			
		||||
	spring.gson.generate-non-executable-json= # Whether to generate non executable JSON by prefixing the output with some special text.
 | 
			
		||||
	spring.gson.lenient= # Whether to be lenient about parsing JSON that doesn't conform to RFC 4627.
 | 
			
		||||
	spring.gson.long-serialization-policy= # Serialization policy for Long and long types.
 | 
			
		||||
	spring.gson.pretty-printing= # Whether to output serialized JSON that fits in a page for pretty printing.
 | 
			
		||||
	spring.gson.serialize-nulls= # Whether to to serialize null fields.
 | 
			
		||||
 | 
			
		||||
	# JERSEY ({sc-spring-boot-autoconfigure}/jersey/JerseyProperties.{sc-ext}[JerseyProperties])
 | 
			
		||||
	spring.jersey.application-path= # Path that serves as the base URI for the application. If specified, overrides the value of "@ApplicationPath".
 | 
			
		||||
	spring.jersey.filter.order=0 # Jersey filter chain order.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue