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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,28 +16,88 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.gson;
|
package org.springframework.boot.autoconfigure.gson;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link EnableAutoConfiguration Auto-configuration} for Gson.
|
* {@link EnableAutoConfiguration Auto-configuration} for Gson.
|
||||||
*
|
*
|
||||||
* @author David Liu
|
* @author David Liu
|
||||||
|
* @author Ivan Golovko
|
||||||
* @since 1.2.0
|
* @since 1.2.0
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnClass(Gson.class)
|
@ConditionalOnClass(Gson.class)
|
||||||
|
@EnableConfigurationProperties(GsonProperties.class)
|
||||||
public class GsonAutoConfiguration {
|
public class GsonAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
public GsonBuilder gsonBuilder(List<GsonBuilderCustomizer> customizers) {
|
||||||
public Gson gson() {
|
GsonBuilder builder = new GsonBuilder();
|
||||||
return new Gson();
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,12 +16,22 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.gson;
|
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 com.google.gson.Gson;
|
||||||
import org.junit.After;
|
import com.google.gson.LongSerializationPolicy;
|
||||||
import org.junit.Before;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.Test;
|
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;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
|
@ -29,36 +39,233 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
* Tests for {@link GsonAutoConfiguration}.
|
* Tests for {@link GsonAutoConfiguration}.
|
||||||
*
|
*
|
||||||
* @author David Liu
|
* @author David Liu
|
||||||
|
* @author Ivan Golovko
|
||||||
*/
|
*/
|
||||||
public class GsonAutoConfigurationTests {
|
public class GsonAutoConfigurationTests {
|
||||||
|
|
||||||
AnnotationConfigApplicationContext context;
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
|
.withConfiguration(AutoConfigurations.of(GsonAutoConfiguration.class));
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
this.context = new AnnotationConfigApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
if (this.context != null) {
|
|
||||||
this.context.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void gsonRegistration() {
|
public void gsonRegistration() {
|
||||||
this.context.register(GsonAutoConfiguration.class);
|
this.contextRunner.run(context -> {
|
||||||
this.context.refresh();
|
Gson gson = context.getBean(Gson.class);
|
||||||
Gson gson = this.context.getBean(Gson.class);
|
assertThat(gson.toJson(new DataObject())).isEqualTo("{\"data\":1}");
|
||||||
assertThat(gson.toJson(new DataObject())).isEqualTo("{\"data\":\"hello\"}");
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 class DataObject {
|
||||||
|
|
||||||
|
public static final String STATIC_DATA = "bye";
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@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.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".
|
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])
|
# 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.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.
|
spring.jersey.filter.order=0 # Jersey filter chain order.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue