Skip to content

Commit eb381d6

Browse files
committed
Provide default values for Kotlinx Serialization JSON properties
Closes gh-48097
1 parent 5699915 commit eb381d6

File tree

3 files changed

+165
-68
lines changed

3 files changed

+165
-68
lines changed

module/spring-boot-kotlinx-serialization-json/src/main/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonAutoConfiguration.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,20 @@ public void customize(JsonBuilder jsonBuilder) {
8181
KotlinxSerializationJsonProperties properties = this.properties;
8282
PropertyMapper map = PropertyMapper.get();
8383
map.from(properties::getNamingStrategy).to(setNamingStrategy(jsonBuilder));
84-
map.from(properties::getPrettyPrint).to(jsonBuilder::setPrettyPrint);
85-
map.from(properties::getLenient).to(jsonBuilder::setLenient);
86-
map.from(properties::getIgnoreUnknownKeys).to(jsonBuilder::setIgnoreUnknownKeys);
87-
map.from(properties::getEncodeDefaults).to(jsonBuilder::setEncodeDefaults);
88-
map.from(properties::getExplicitNulls).to(jsonBuilder::setExplicitNulls);
89-
map.from(properties::getCoerceInputValues).to(jsonBuilder::setCoerceInputValues);
90-
map.from(properties::getAllowStructuredMapKeys).to(jsonBuilder::setAllowStructuredMapKeys);
91-
map.from(properties::getAllowSpecialFloatingPointValues)
92-
.to(jsonBuilder::setAllowSpecialFloatingPointValues);
84+
map.from(properties::isPrettyPrint).to(jsonBuilder::setPrettyPrint);
85+
map.from(properties::isLenient).to(jsonBuilder::setLenient);
86+
map.from(properties::isIgnoreUnknownKeys).to(jsonBuilder::setIgnoreUnknownKeys);
87+
map.from(properties::isEncodeDefaults).to(jsonBuilder::setEncodeDefaults);
88+
map.from(properties::isExplicitNulls).to(jsonBuilder::setExplicitNulls);
89+
map.from(properties::isCoerceInputValues).to(jsonBuilder::setCoerceInputValues);
90+
map.from(properties::isAllowStructuredMapKeys).to(jsonBuilder::setAllowStructuredMapKeys);
91+
map.from(properties::isAllowSpecialFloatingPointValues).to(jsonBuilder::setAllowSpecialFloatingPointValues);
9392
map.from(properties::getClassDiscriminator).to(jsonBuilder::setClassDiscriminator);
9493
map.from(properties::getClassDiscriminatorMode).to(jsonBuilder::setClassDiscriminatorMode);
95-
map.from(properties::getDecodeEnumsCaseInsensitive).to(jsonBuilder::setDecodeEnumsCaseInsensitive);
96-
map.from(properties::getUseAlternativeNames).to(jsonBuilder::setUseAlternativeNames);
97-
map.from(properties::getAllowTrailingComma).to(jsonBuilder::setAllowTrailingComma);
98-
map.from(properties::getAllowComments).to(jsonBuilder::setAllowComments);
94+
map.from(properties::isDecodeEnumsCaseInsensitive).to(jsonBuilder::setDecodeEnumsCaseInsensitive);
95+
map.from(properties::isUseAlternativeNames).to(jsonBuilder::setUseAlternativeNames);
96+
map.from(properties::isAllowTrailingComma).to(jsonBuilder::setAllowTrailingComma);
97+
map.from(properties::isAllowComments).to(jsonBuilder::setAllowComments);
9998
}
10099

101100
private Consumer<KotlinxSerializationJsonProperties.JsonNamingStrategy> setNamingStrategy(JsonBuilder builder) {

module/spring-boot-kotlinx-serialization-json/src/main/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonProperties.java

Lines changed: 54 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -38,83 +38,82 @@ public class KotlinxSerializationJsonProperties {
3838
private @Nullable JsonNamingStrategy namingStrategy;
3939

4040
/**
41-
* Whether resulting JSON should be pretty-printed: formatted and optimized for human
42-
* readability.
41+
* Whether resulting JSON should be pretty-printed.
4342
*/
44-
private @Nullable Boolean prettyPrint;
43+
private boolean prettyPrint;
4544

4645
/**
47-
* Enable lenient mode that removes JSON specification restriction (RFC-4627) and
48-
* makes parser more liberal to the malformed input.
46+
* Whether parser should operate in lenient mode, removing the JSON specification
47+
* restriction (RFC-4627) and being more liberal to malformed input.
4948
*/
50-
private @Nullable Boolean lenient;
49+
private boolean lenient;
5150

5251
/**
5352
* Whether encounters of unknown properties in the input JSON should be ignored
5453
* instead of throwing SerializationException.
5554
*/
56-
private @Nullable Boolean ignoreUnknownKeys;
55+
private boolean ignoreUnknownKeys;
5756

5857
/**
5958
* Whether default values of Kotlin properties should be encoded.
6059
*/
61-
private @Nullable Boolean encodeDefaults;
60+
private boolean encodeDefaults;
6261

6362
/**
6463
* Whether null values should be encoded for nullable properties and must be present
6564
* in JSON object during decoding.
6665
*/
67-
private @Nullable Boolean explicitNulls;
66+
private boolean explicitNulls = true;
6867

6968
/**
70-
* Enable coercing incorrect JSON values.
69+
* Whether to coerce incorrect JSON values.
7170
*/
72-
private @Nullable Boolean coerceInputValues;
71+
private boolean coerceInputValues;
7372

7473
/**
75-
* Enable structured objects to be serialized as map keys by changing serialized form
76-
* of the map from JSON object (key-value pairs) to flat array like [k1, v1, k2, v2].
74+
* Whether to allow structured objects to be serialized as map keys by changing the
75+
* serialized form of the map from JSON object (key-value pairs) to flat array like
76+
* [k1, v1, k2, v2].
7777
*/
78-
private @Nullable Boolean allowStructuredMapKeys;
78+
private boolean allowStructuredMapKeys;
7979

8080
/**
81-
* Whether to remove JSON specification restriction on special floating-point values
82-
* such as 'NaN' and 'Infinity' and enable their serialization and deserialization as
83-
* float literals without quotes.
81+
* Whether to remove the JSON specification restriction on special floating-point
82+
* values such as 'NaN' and 'Infinity' and allow their serialization and
83+
* deserialization as float literals without quotes.
8484
*/
85-
private @Nullable Boolean allowSpecialFloatingPointValues;
85+
private boolean allowSpecialFloatingPointValues;
8686

8787
/**
8888
* Name of the class descriptor property for polymorphic serialization.
8989
*/
90-
private @Nullable String classDiscriminator;
90+
private String classDiscriminator = "type";
9191

9292
/**
9393
* Defines which classes and objects should have class discriminator added to the
9494
* output.
9595
*/
96-
private @Nullable ClassDiscriminatorMode classDiscriminatorMode;
96+
private ClassDiscriminatorMode classDiscriminatorMode = ClassDiscriminatorMode.POLYMORPHIC;
9797

9898
/**
99-
* Enable decoding enum values in a case-insensitive manner.
99+
* Whether enum values are decoded in a case-insensitive manner.
100100
*/
101-
private @Nullable Boolean decodeEnumsCaseInsensitive;
101+
private boolean decodeEnumsCaseInsensitive;
102102

103103
/**
104104
* Whether Json instance makes use of JsonNames annotation.
105105
*/
106-
private @Nullable Boolean useAlternativeNames;
106+
private boolean useAlternativeNames = true;
107107

108108
/**
109-
* Whether to allow parser to accept trailing (ending) commas in JSON objects and
110-
* arrays.
109+
* Whether to allow parser to accept trailing commas in JSON objects and arrays.
111110
*/
112-
private @Nullable Boolean allowTrailingComma;
111+
private boolean allowTrailingComma;
113112

114113
/**
115114
* Whether to allow parser to accept C/Java-style comments in JSON input.
116115
*/
117-
private @Nullable Boolean allowComments;
116+
private boolean allowComments;
118117

119118
public @Nullable JsonNamingStrategy getNamingStrategy() {
120119
return this.namingStrategy;
@@ -124,115 +123,115 @@ public void setNamingStrategy(@Nullable JsonNamingStrategy namingStrategy) {
124123
this.namingStrategy = namingStrategy;
125124
}
126125

127-
public @Nullable Boolean getPrettyPrint() {
126+
public boolean isPrettyPrint() {
128127
return this.prettyPrint;
129128
}
130129

131-
public void setPrettyPrint(@Nullable Boolean prettyPrint) {
130+
public void setPrettyPrint(boolean prettyPrint) {
132131
this.prettyPrint = prettyPrint;
133132
}
134133

135-
public @Nullable Boolean getLenient() {
134+
public boolean isLenient() {
136135
return this.lenient;
137136
}
138137

139-
public void setLenient(@Nullable Boolean lenient) {
138+
public void setLenient(boolean lenient) {
140139
this.lenient = lenient;
141140
}
142141

143-
public @Nullable Boolean getIgnoreUnknownKeys() {
142+
public boolean isIgnoreUnknownKeys() {
144143
return this.ignoreUnknownKeys;
145144
}
146145

147-
public void setIgnoreUnknownKeys(@Nullable Boolean ignoreUnknownKeys) {
146+
public void setIgnoreUnknownKeys(boolean ignoreUnknownKeys) {
148147
this.ignoreUnknownKeys = ignoreUnknownKeys;
149148
}
150149

151-
public @Nullable Boolean getEncodeDefaults() {
150+
public boolean isEncodeDefaults() {
152151
return this.encodeDefaults;
153152
}
154153

155-
public void setEncodeDefaults(@Nullable Boolean encodeDefaults) {
154+
public void setEncodeDefaults(boolean encodeDefaults) {
156155
this.encodeDefaults = encodeDefaults;
157156
}
158157

159-
public @Nullable Boolean getExplicitNulls() {
158+
public boolean isExplicitNulls() {
160159
return this.explicitNulls;
161160
}
162161

163-
public void setExplicitNulls(@Nullable Boolean explicitNulls) {
162+
public void setExplicitNulls(boolean explicitNulls) {
164163
this.explicitNulls = explicitNulls;
165164
}
166165

167-
public @Nullable Boolean getCoerceInputValues() {
166+
public boolean isCoerceInputValues() {
168167
return this.coerceInputValues;
169168
}
170169

171-
public void setCoerceInputValues(@Nullable Boolean coerceInputValues) {
170+
public void setCoerceInputValues(boolean coerceInputValues) {
172171
this.coerceInputValues = coerceInputValues;
173172
}
174173

175-
public @Nullable Boolean getAllowStructuredMapKeys() {
174+
public boolean isAllowStructuredMapKeys() {
176175
return this.allowStructuredMapKeys;
177176
}
178177

179-
public void setAllowStructuredMapKeys(@Nullable Boolean allowStructuredMapKeys) {
178+
public void setAllowStructuredMapKeys(boolean allowStructuredMapKeys) {
180179
this.allowStructuredMapKeys = allowStructuredMapKeys;
181180
}
182181

183-
public @Nullable Boolean getAllowSpecialFloatingPointValues() {
182+
public boolean isAllowSpecialFloatingPointValues() {
184183
return this.allowSpecialFloatingPointValues;
185184
}
186185

187-
public void setAllowSpecialFloatingPointValues(@Nullable Boolean allowSpecialFloatingPointValues) {
186+
public void setAllowSpecialFloatingPointValues(boolean allowSpecialFloatingPointValues) {
188187
this.allowSpecialFloatingPointValues = allowSpecialFloatingPointValues;
189188
}
190189

191-
public @Nullable String getClassDiscriminator() {
190+
public String getClassDiscriminator() {
192191
return this.classDiscriminator;
193192
}
194193

195-
public void setClassDiscriminator(@Nullable String classDiscriminator) {
194+
public void setClassDiscriminator(String classDiscriminator) {
196195
this.classDiscriminator = classDiscriminator;
197196
}
198197

199-
public @Nullable ClassDiscriminatorMode getClassDiscriminatorMode() {
198+
public ClassDiscriminatorMode getClassDiscriminatorMode() {
200199
return this.classDiscriminatorMode;
201200
}
202201

203-
public void setClassDiscriminatorMode(@Nullable ClassDiscriminatorMode classDiscriminatorMode) {
202+
public void setClassDiscriminatorMode(ClassDiscriminatorMode classDiscriminatorMode) {
204203
this.classDiscriminatorMode = classDiscriminatorMode;
205204
}
206205

207-
public @Nullable Boolean getDecodeEnumsCaseInsensitive() {
206+
public boolean isDecodeEnumsCaseInsensitive() {
208207
return this.decodeEnumsCaseInsensitive;
209208
}
210209

211-
public void setDecodeEnumsCaseInsensitive(@Nullable Boolean decodeEnumsCaseInsensitive) {
210+
public void setDecodeEnumsCaseInsensitive(boolean decodeEnumsCaseInsensitive) {
212211
this.decodeEnumsCaseInsensitive = decodeEnumsCaseInsensitive;
213212
}
214213

215-
public @Nullable Boolean getUseAlternativeNames() {
214+
public boolean isUseAlternativeNames() {
216215
return this.useAlternativeNames;
217216
}
218217

219-
public void setUseAlternativeNames(@Nullable Boolean useAlternativeNames) {
218+
public void setUseAlternativeNames(boolean useAlternativeNames) {
220219
this.useAlternativeNames = useAlternativeNames;
221220
}
222221

223-
public @Nullable Boolean getAllowTrailingComma() {
222+
public boolean isAllowTrailingComma() {
224223
return this.allowTrailingComma;
225224
}
226225

227-
public void setAllowTrailingComma(@Nullable Boolean allowTrailingComma) {
226+
public void setAllowTrailingComma(boolean allowTrailingComma) {
228227
this.allowTrailingComma = allowTrailingComma;
229228
}
230229

231-
public @Nullable Boolean getAllowComments() {
230+
public boolean isAllowComments() {
232231
return this.allowComments;
233232
}
234233

235-
public void setAllowComments(@Nullable Boolean allowComments) {
234+
public void setAllowComments(boolean allowComments) {
236235
this.allowComments = allowComments;
237236
}
238237

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2012-present 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+
* https://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.kotlinx.serialization.json.autoconfigure;
18+
19+
import kotlinx.serialization.json.Json;
20+
import kotlinx.serialization.json.JsonBuilder;
21+
import org.jspecify.annotations.Nullable;
22+
import org.junit.jupiter.params.ParameterizedTest;
23+
import org.junit.jupiter.params.provider.EnumSource;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
/**
28+
* Tests for {@link KotlinxSerializationJsonProperties}.
29+
*
30+
* @author Andy Wilkinson
31+
*/
32+
class KotlinxSerializationJsonPropertiesTests {
33+
34+
@ParameterizedTest
35+
@EnumSource
36+
void defaultsAreAligned(JsonBuilderSettings settings) {
37+
JsonBuilder jsonBuilder = new JsonBuilder(Json.Default);
38+
KotlinxSerializationJsonProperties properties = new KotlinxSerializationJsonProperties();
39+
assertThat(settings.propertyGetter.get(properties)).isEqualTo(settings.jsonBuilderGetter.get(jsonBuilder));
40+
}
41+
42+
private enum JsonBuilderSettings {
43+
44+
ALLOW_COMMENTS(KotlinxSerializationJsonProperties::isAllowComments, JsonBuilder::getAllowComments),
45+
46+
ALLOW_SPECIAL_FLOATING_POINT_VALUES(KotlinxSerializationJsonProperties::isAllowSpecialFloatingPointValues,
47+
JsonBuilder::getAllowSpecialFloatingPointValues),
48+
49+
ALLOW_STRUCTURED_MAP_KEYS(KotlinxSerializationJsonProperties::isAllowStructuredMapKeys,
50+
JsonBuilder::getAllowStructuredMapKeys),
51+
52+
ALLOW_TRAILING_COMMA(KotlinxSerializationJsonProperties::isAllowTrailingComma,
53+
JsonBuilder::getAllowTrailingComma),
54+
55+
CLASS_DISCRIMINATOR(KotlinxSerializationJsonProperties::getClassDiscriminator,
56+
JsonBuilder::getClassDiscriminator),
57+
58+
CLASS_DISCRIMINATOR_MODE(KotlinxSerializationJsonProperties::getClassDiscriminatorMode,
59+
JsonBuilder::getClassDiscriminatorMode),
60+
61+
COERCE_INPUT_VALUES(KotlinxSerializationJsonProperties::isCoerceInputValues, JsonBuilder::getCoerceInputValues),
62+
63+
DECODE_ENUMS_CASE_INSENSITIVE(KotlinxSerializationJsonProperties::isDecodeEnumsCaseInsensitive,
64+
JsonBuilder::getDecodeEnumsCaseInsensitive),
65+
66+
ENCODE_DEFAULTS(KotlinxSerializationJsonProperties::isEncodeDefaults, JsonBuilder::getEncodeDefaults),
67+
68+
EXPLICIT_NULLS(KotlinxSerializationJsonProperties::isExplicitNulls, JsonBuilder::getExplicitNulls),
69+
70+
IGNORE_UNKNOWN_KEYS(KotlinxSerializationJsonProperties::isIgnoreUnknownKeys, JsonBuilder::getIgnoreUnknownKeys),
71+
72+
LENIENT(KotlinxSerializationJsonProperties::isLenient, JsonBuilder::isLenient),
73+
74+
NAMING_STRATEGY(KotlinxSerializationJsonProperties::getNamingStrategy, JsonBuilder::getNamingStrategy),
75+
76+
PRETTY_PRINT(KotlinxSerializationJsonProperties::isPrettyPrint, JsonBuilder::getPrettyPrint),
77+
78+
USE_ALTERNATIVE_NAMES(KotlinxSerializationJsonProperties::isUseAlternativeNames,
79+
JsonBuilder::getUseAlternativeNames);
80+
81+
private final Accessor<KotlinxSerializationJsonProperties, ?> propertyGetter;
82+
83+
private final Accessor<JsonBuilder, ?> jsonBuilderGetter;
84+
85+
JsonBuilderSettings(Accessor<KotlinxSerializationJsonProperties, @Nullable Object> propertyGetter,
86+
Accessor<JsonBuilder, @Nullable Object> jsonBuilderGetter) {
87+
this.propertyGetter = propertyGetter;
88+
this.jsonBuilderGetter = jsonBuilderGetter;
89+
}
90+
91+
private interface Accessor<S, @Nullable P extends @Nullable Object> {
92+
93+
@Nullable P get(S source);
94+
95+
}
96+
97+
}
98+
99+
}

0 commit comments

Comments
 (0)