Skip to content

Commit 6ea6adb

Browse files
committed
Merge pull request #11498 from ioanngolovko
* pr/11498: Polish GSON customization support Allow GSON customization via properties or beans
2 parents 9cb5f3d + 286a3bb commit 6ea6adb

File tree

5 files changed

+524
-23
lines changed

5 files changed

+524
-23
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/gson/GsonAutoConfiguration.java

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,28 +16,88 @@
1616

1717
package org.springframework.boot.autoconfigure.gson;
1818

19+
import java.util.List;
20+
1921
import com.google.gson.Gson;
22+
import com.google.gson.GsonBuilder;
2023

2124
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2225
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2326
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
27+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
28+
import org.springframework.boot.context.properties.PropertyMapper;
2429
import org.springframework.context.annotation.Bean;
2530
import org.springframework.context.annotation.Configuration;
31+
import org.springframework.core.Ordered;
2632

2733
/**
2834
* {@link EnableAutoConfiguration Auto-configuration} for Gson.
2935
*
3036
* @author David Liu
37+
* @author Ivan Golovko
3138
* @since 1.2.0
3239
*/
3340
@Configuration
3441
@ConditionalOnClass(Gson.class)
42+
@EnableConfigurationProperties(GsonProperties.class)
3543
public class GsonAutoConfiguration {
3644

3745
@Bean
38-
@ConditionalOnMissingBean
39-
public Gson gson() {
40-
return new Gson();
46+
public GsonBuilder gsonBuilder(List<GsonBuilderCustomizer> customizers) {
47+
GsonBuilder builder = new GsonBuilder();
48+
customizers.forEach(c -> c.customize(builder));
49+
return builder;
50+
}
51+
52+
@Bean
53+
@ConditionalOnMissingBean(Gson.class)
54+
public Gson gson(GsonBuilder gsonBuilder) {
55+
return gsonBuilder.create();
56+
}
57+
58+
@Bean
59+
public StandardGsonBuilderCustomizer standardGsonBuilderCustomizer(
60+
GsonProperties gsonProperties) {
61+
return new StandardGsonBuilderCustomizer(gsonProperties);
62+
}
63+
64+
private static final class StandardGsonBuilderCustomizer
65+
implements GsonBuilderCustomizer, Ordered {
66+
67+
private final GsonProperties properties;
68+
69+
StandardGsonBuilderCustomizer(GsonProperties properties) {
70+
this.properties = properties;
71+
}
72+
73+
@Override
74+
public int getOrder() {
75+
return 0;
76+
}
77+
78+
@Override
79+
public void customize(GsonBuilder builder) {
80+
GsonProperties properties = this.properties;
81+
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
82+
map.from(properties::getGenerateNonExecutableJson)
83+
.toCall(builder::generateNonExecutableJson);
84+
map.from(properties::getExcludeFieldsWithoutExposeAnnotation)
85+
.toCall(builder::excludeFieldsWithoutExposeAnnotation);
86+
map.from(properties::getSerializeNulls).toCall(builder::serializeNulls);
87+
map.from(properties::getEnableComplexMapKeySerialization)
88+
.toCall(builder::enableComplexMapKeySerialization);
89+
map.from(properties::getDisableInnerClassSerialization)
90+
.toCall(builder::disableInnerClassSerialization);
91+
map.from(properties::getLongSerializationPolicy)
92+
.to(builder::setLongSerializationPolicy);
93+
map.from(properties::getFieldNamingPolicy).to(builder::setFieldNamingPolicy);
94+
map.from(properties::getPrettyPrinting).toCall(builder::setPrettyPrinting);
95+
map.from(properties::getLenient).toCall(builder::setLenient);
96+
map.from(properties::getDisableHtmlEscaping)
97+
.toCall(builder::disableHtmlEscaping);
98+
map.from(properties::getDateFormat).to(builder::setDateFormat);
99+
}
100+
41101
}
42102

43103
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.gson;
18+
19+
import com.google.gson.Gson;
20+
import com.google.gson.GsonBuilder;
21+
22+
/**
23+
* Callback interface that can be implemented by beans wishing to further customize the
24+
* {@link Gson} via {@link GsonBuilder} retaining its default auto-configuration.
25+
*
26+
* @author Ivan Golovko
27+
* @since 2.0.0
28+
*/
29+
@FunctionalInterface
30+
public interface GsonBuilderCustomizer {
31+
32+
/**
33+
* Customize the GsonBuilder.
34+
* @param gsonBuilder the GsonBuilder to customize
35+
*/
36+
void customize(GsonBuilder gsonBuilder);
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.gson;
18+
19+
import com.google.gson.FieldNamingPolicy;
20+
import com.google.gson.Gson;
21+
import com.google.gson.LongSerializationPolicy;
22+
23+
import org.springframework.boot.context.properties.ConfigurationProperties;
24+
25+
/**
26+
* Configuration properties to configure {@link Gson}.
27+
*
28+
* @author Ivan Golovko
29+
* @since 2.0.0
30+
*/
31+
@ConfigurationProperties(prefix = "spring.gson")
32+
public class GsonProperties {
33+
34+
/**
35+
* Whether to generate non executable JSON by prefixing the output with some special
36+
* text.
37+
*/
38+
private Boolean generateNonExecutableJson;
39+
40+
/**
41+
* Whether to exclude all fields from consideration for serialization or
42+
* deserialization that do not have the "Expose" annotation.
43+
*/
44+
private Boolean excludeFieldsWithoutExposeAnnotation;
45+
46+
/**
47+
* Whether to to serialize null fields.
48+
*/
49+
private Boolean serializeNulls;
50+
51+
/**
52+
* Whether to enabled serialization of complex map keys (i.e. non-primitives).
53+
*/
54+
private Boolean enableComplexMapKeySerialization;
55+
56+
/**
57+
* Whether to exclude inner classes during serialization.
58+
*/
59+
private Boolean disableInnerClassSerialization;
60+
61+
/**
62+
* Serialization policy for Long and long types.
63+
*/
64+
private LongSerializationPolicy longSerializationPolicy;
65+
66+
/**
67+
* The naming policy that should be applied to an object's field during serialization
68+
* and deserialization.
69+
*/
70+
private FieldNamingPolicy fieldNamingPolicy;
71+
72+
/**
73+
* Whether to output serialized JSON that fits in a page for pretty printing.
74+
*/
75+
private Boolean prettyPrinting;
76+
77+
/**
78+
* Whether to be lenient about parsing JSON that doesn't conform to RFC 4627.
79+
*/
80+
private Boolean lenient;
81+
82+
/**
83+
* Whether to disable the escaping of HTML characters such as '<' '>' etc.
84+
*/
85+
private Boolean disableHtmlEscaping;
86+
87+
/**
88+
* The format to use when serializing Date objects.
89+
*/
90+
private String dateFormat;
91+
92+
public Boolean getGenerateNonExecutableJson() {
93+
return this.generateNonExecutableJson;
94+
}
95+
96+
public void setGenerateNonExecutableJson(Boolean generateNonExecutableJson) {
97+
this.generateNonExecutableJson = generateNonExecutableJson;
98+
}
99+
100+
public Boolean getExcludeFieldsWithoutExposeAnnotation() {
101+
return this.excludeFieldsWithoutExposeAnnotation;
102+
}
103+
104+
public void setExcludeFieldsWithoutExposeAnnotation(
105+
Boolean excludeFieldsWithoutExposeAnnotation) {
106+
this.excludeFieldsWithoutExposeAnnotation = excludeFieldsWithoutExposeAnnotation;
107+
}
108+
109+
public Boolean getSerializeNulls() {
110+
return this.serializeNulls;
111+
}
112+
113+
public void setSerializeNulls(Boolean serializeNulls) {
114+
this.serializeNulls = serializeNulls;
115+
}
116+
117+
public Boolean getEnableComplexMapKeySerialization() {
118+
return this.enableComplexMapKeySerialization;
119+
}
120+
121+
public void setEnableComplexMapKeySerialization(
122+
Boolean enableComplexMapKeySerialization) {
123+
this.enableComplexMapKeySerialization = enableComplexMapKeySerialization;
124+
}
125+
126+
public Boolean getDisableInnerClassSerialization() {
127+
return this.disableInnerClassSerialization;
128+
}
129+
130+
public void setDisableInnerClassSerialization(
131+
Boolean disableInnerClassSerialization) {
132+
this.disableInnerClassSerialization = disableInnerClassSerialization;
133+
}
134+
135+
public LongSerializationPolicy getLongSerializationPolicy() {
136+
return this.longSerializationPolicy;
137+
}
138+
139+
public void setLongSerializationPolicy(
140+
LongSerializationPolicy longSerializationPolicy) {
141+
this.longSerializationPolicy = longSerializationPolicy;
142+
}
143+
144+
public FieldNamingPolicy getFieldNamingPolicy() {
145+
return this.fieldNamingPolicy;
146+
}
147+
148+
public void setFieldNamingPolicy(FieldNamingPolicy fieldNamingPolicy) {
149+
this.fieldNamingPolicy = fieldNamingPolicy;
150+
}
151+
152+
public Boolean getPrettyPrinting() {
153+
return this.prettyPrinting;
154+
}
155+
156+
public void setPrettyPrinting(Boolean prettyPrinting) {
157+
this.prettyPrinting = prettyPrinting;
158+
}
159+
160+
public Boolean getLenient() {
161+
return this.lenient;
162+
}
163+
164+
public void setLenient(Boolean lenient) {
165+
this.lenient = lenient;
166+
}
167+
168+
public Boolean getDisableHtmlEscaping() {
169+
return this.disableHtmlEscaping;
170+
}
171+
172+
public void setDisableHtmlEscaping(Boolean disableHtmlEscaping) {
173+
this.disableHtmlEscaping = disableHtmlEscaping;
174+
}
175+
176+
public String getDateFormat() {
177+
return this.dateFormat;
178+
}
179+
180+
public void setDateFormat(String dateFormat) {
181+
this.dateFormat = dateFormat;
182+
}
183+
184+
}

0 commit comments

Comments
 (0)