Browse Source

Provide default values for Kotlinx Serialization JSON properties

Closes gh-48097
pull/48124/head
Andy Wilkinson 4 months ago
parent
commit
eb381d642a
  1. 25
      module/spring-boot-kotlinx-serialization-json/src/main/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonAutoConfiguration.java
  2. 109
      module/spring-boot-kotlinx-serialization-json/src/main/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonProperties.java
  3. 99
      module/spring-boot-kotlinx-serialization-json/src/test/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonPropertiesTests.java

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

@ -81,21 +81,20 @@ public final class KotlinxSerializationJsonAutoConfiguration {
KotlinxSerializationJsonProperties properties = this.properties; KotlinxSerializationJsonProperties properties = this.properties;
PropertyMapper map = PropertyMapper.get(); PropertyMapper map = PropertyMapper.get();
map.from(properties::getNamingStrategy).to(setNamingStrategy(jsonBuilder)); map.from(properties::getNamingStrategy).to(setNamingStrategy(jsonBuilder));
map.from(properties::getPrettyPrint).to(jsonBuilder::setPrettyPrint); map.from(properties::isPrettyPrint).to(jsonBuilder::setPrettyPrint);
map.from(properties::getLenient).to(jsonBuilder::setLenient); map.from(properties::isLenient).to(jsonBuilder::setLenient);
map.from(properties::getIgnoreUnknownKeys).to(jsonBuilder::setIgnoreUnknownKeys); map.from(properties::isIgnoreUnknownKeys).to(jsonBuilder::setIgnoreUnknownKeys);
map.from(properties::getEncodeDefaults).to(jsonBuilder::setEncodeDefaults); map.from(properties::isEncodeDefaults).to(jsonBuilder::setEncodeDefaults);
map.from(properties::getExplicitNulls).to(jsonBuilder::setExplicitNulls); map.from(properties::isExplicitNulls).to(jsonBuilder::setExplicitNulls);
map.from(properties::getCoerceInputValues).to(jsonBuilder::setCoerceInputValues); map.from(properties::isCoerceInputValues).to(jsonBuilder::setCoerceInputValues);
map.from(properties::getAllowStructuredMapKeys).to(jsonBuilder::setAllowStructuredMapKeys); map.from(properties::isAllowStructuredMapKeys).to(jsonBuilder::setAllowStructuredMapKeys);
map.from(properties::getAllowSpecialFloatingPointValues) map.from(properties::isAllowSpecialFloatingPointValues).to(jsonBuilder::setAllowSpecialFloatingPointValues);
.to(jsonBuilder::setAllowSpecialFloatingPointValues);
map.from(properties::getClassDiscriminator).to(jsonBuilder::setClassDiscriminator); map.from(properties::getClassDiscriminator).to(jsonBuilder::setClassDiscriminator);
map.from(properties::getClassDiscriminatorMode).to(jsonBuilder::setClassDiscriminatorMode); map.from(properties::getClassDiscriminatorMode).to(jsonBuilder::setClassDiscriminatorMode);
map.from(properties::getDecodeEnumsCaseInsensitive).to(jsonBuilder::setDecodeEnumsCaseInsensitive); map.from(properties::isDecodeEnumsCaseInsensitive).to(jsonBuilder::setDecodeEnumsCaseInsensitive);
map.from(properties::getUseAlternativeNames).to(jsonBuilder::setUseAlternativeNames); map.from(properties::isUseAlternativeNames).to(jsonBuilder::setUseAlternativeNames);
map.from(properties::getAllowTrailingComma).to(jsonBuilder::setAllowTrailingComma); map.from(properties::isAllowTrailingComma).to(jsonBuilder::setAllowTrailingComma);
map.from(properties::getAllowComments).to(jsonBuilder::setAllowComments); map.from(properties::isAllowComments).to(jsonBuilder::setAllowComments);
} }
private Consumer<KotlinxSerializationJsonProperties.JsonNamingStrategy> setNamingStrategy(JsonBuilder builder) { private Consumer<KotlinxSerializationJsonProperties.JsonNamingStrategy> setNamingStrategy(JsonBuilder builder) {

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

@ -38,83 +38,82 @@ public class KotlinxSerializationJsonProperties {
private @Nullable JsonNamingStrategy namingStrategy; private @Nullable JsonNamingStrategy namingStrategy;
/** /**
* Whether resulting JSON should be pretty-printed: formatted and optimized for human * Whether resulting JSON should be pretty-printed.
* readability.
*/ */
private @Nullable Boolean prettyPrint; private boolean prettyPrint;
/** /**
* Enable lenient mode that removes JSON specification restriction (RFC-4627) and * Whether parser should operate in lenient mode, removing the JSON specification
* makes parser more liberal to the malformed input. * restriction (RFC-4627) and being more liberal to malformed input.
*/ */
private @Nullable Boolean lenient; private boolean lenient;
/** /**
* Whether encounters of unknown properties in the input JSON should be ignored * Whether encounters of unknown properties in the input JSON should be ignored
* instead of throwing SerializationException. * instead of throwing SerializationException.
*/ */
private @Nullable Boolean ignoreUnknownKeys; private boolean ignoreUnknownKeys;
/** /**
* Whether default values of Kotlin properties should be encoded. * Whether default values of Kotlin properties should be encoded.
*/ */
private @Nullable Boolean encodeDefaults; private boolean encodeDefaults;
/** /**
* Whether null values should be encoded for nullable properties and must be present * Whether null values should be encoded for nullable properties and must be present
* in JSON object during decoding. * in JSON object during decoding.
*/ */
private @Nullable Boolean explicitNulls; private boolean explicitNulls = true;
/** /**
* Enable coercing incorrect JSON values. * Whether to coerce incorrect JSON values.
*/ */
private @Nullable Boolean coerceInputValues; private boolean coerceInputValues;
/** /**
* Enable structured objects to be serialized as map keys by changing serialized form * Whether to allow structured objects to be serialized as map keys by changing the
* of the map from JSON object (key-value pairs) to flat array like [k1, v1, k2, v2]. * serialized form of the map from JSON object (key-value pairs) to flat array like
* [k1, v1, k2, v2].
*/ */
private @Nullable Boolean allowStructuredMapKeys; private boolean allowStructuredMapKeys;
/** /**
* Whether to remove JSON specification restriction on special floating-point values * Whether to remove the JSON specification restriction on special floating-point
* such as 'NaN' and 'Infinity' and enable their serialization and deserialization as * values such as 'NaN' and 'Infinity' and allow their serialization and
* float literals without quotes. * deserialization as float literals without quotes.
*/ */
private @Nullable Boolean allowSpecialFloatingPointValues; private boolean allowSpecialFloatingPointValues;
/** /**
* Name of the class descriptor property for polymorphic serialization. * Name of the class descriptor property for polymorphic serialization.
*/ */
private @Nullable String classDiscriminator; private String classDiscriminator = "type";
/** /**
* Defines which classes and objects should have class discriminator added to the * Defines which classes and objects should have class discriminator added to the
* output. * output.
*/ */
private @Nullable ClassDiscriminatorMode classDiscriminatorMode; private ClassDiscriminatorMode classDiscriminatorMode = ClassDiscriminatorMode.POLYMORPHIC;
/** /**
* Enable decoding enum values in a case-insensitive manner. * Whether enum values are decoded in a case-insensitive manner.
*/ */
private @Nullable Boolean decodeEnumsCaseInsensitive; private boolean decodeEnumsCaseInsensitive;
/** /**
* Whether Json instance makes use of JsonNames annotation. * Whether Json instance makes use of JsonNames annotation.
*/ */
private @Nullable Boolean useAlternativeNames; private boolean useAlternativeNames = true;
/** /**
* Whether to allow parser to accept trailing (ending) commas in JSON objects and * Whether to allow parser to accept trailing commas in JSON objects and arrays.
* arrays.
*/ */
private @Nullable Boolean allowTrailingComma; private boolean allowTrailingComma;
/** /**
* Whether to allow parser to accept C/Java-style comments in JSON input. * Whether to allow parser to accept C/Java-style comments in JSON input.
*/ */
private @Nullable Boolean allowComments; private boolean allowComments;
public @Nullable JsonNamingStrategy getNamingStrategy() { public @Nullable JsonNamingStrategy getNamingStrategy() {
return this.namingStrategy; return this.namingStrategy;
@ -124,115 +123,115 @@ public class KotlinxSerializationJsonProperties {
this.namingStrategy = namingStrategy; this.namingStrategy = namingStrategy;
} }
public @Nullable Boolean getPrettyPrint() { public boolean isPrettyPrint() {
return this.prettyPrint; return this.prettyPrint;
} }
public void setPrettyPrint(@Nullable Boolean prettyPrint) { public void setPrettyPrint(boolean prettyPrint) {
this.prettyPrint = prettyPrint; this.prettyPrint = prettyPrint;
} }
public @Nullable Boolean getLenient() { public boolean isLenient() {
return this.lenient; return this.lenient;
} }
public void setLenient(@Nullable Boolean lenient) { public void setLenient(boolean lenient) {
this.lenient = lenient; this.lenient = lenient;
} }
public @Nullable Boolean getIgnoreUnknownKeys() { public boolean isIgnoreUnknownKeys() {
return this.ignoreUnknownKeys; return this.ignoreUnknownKeys;
} }
public void setIgnoreUnknownKeys(@Nullable Boolean ignoreUnknownKeys) { public void setIgnoreUnknownKeys(boolean ignoreUnknownKeys) {
this.ignoreUnknownKeys = ignoreUnknownKeys; this.ignoreUnknownKeys = ignoreUnknownKeys;
} }
public @Nullable Boolean getEncodeDefaults() { public boolean isEncodeDefaults() {
return this.encodeDefaults; return this.encodeDefaults;
} }
public void setEncodeDefaults(@Nullable Boolean encodeDefaults) { public void setEncodeDefaults(boolean encodeDefaults) {
this.encodeDefaults = encodeDefaults; this.encodeDefaults = encodeDefaults;
} }
public @Nullable Boolean getExplicitNulls() { public boolean isExplicitNulls() {
return this.explicitNulls; return this.explicitNulls;
} }
public void setExplicitNulls(@Nullable Boolean explicitNulls) { public void setExplicitNulls(boolean explicitNulls) {
this.explicitNulls = explicitNulls; this.explicitNulls = explicitNulls;
} }
public @Nullable Boolean getCoerceInputValues() { public boolean isCoerceInputValues() {
return this.coerceInputValues; return this.coerceInputValues;
} }
public void setCoerceInputValues(@Nullable Boolean coerceInputValues) { public void setCoerceInputValues(boolean coerceInputValues) {
this.coerceInputValues = coerceInputValues; this.coerceInputValues = coerceInputValues;
} }
public @Nullable Boolean getAllowStructuredMapKeys() { public boolean isAllowStructuredMapKeys() {
return this.allowStructuredMapKeys; return this.allowStructuredMapKeys;
} }
public void setAllowStructuredMapKeys(@Nullable Boolean allowStructuredMapKeys) { public void setAllowStructuredMapKeys(boolean allowStructuredMapKeys) {
this.allowStructuredMapKeys = allowStructuredMapKeys; this.allowStructuredMapKeys = allowStructuredMapKeys;
} }
public @Nullable Boolean getAllowSpecialFloatingPointValues() { public boolean isAllowSpecialFloatingPointValues() {
return this.allowSpecialFloatingPointValues; return this.allowSpecialFloatingPointValues;
} }
public void setAllowSpecialFloatingPointValues(@Nullable Boolean allowSpecialFloatingPointValues) { public void setAllowSpecialFloatingPointValues(boolean allowSpecialFloatingPointValues) {
this.allowSpecialFloatingPointValues = allowSpecialFloatingPointValues; this.allowSpecialFloatingPointValues = allowSpecialFloatingPointValues;
} }
public @Nullable String getClassDiscriminator() { public String getClassDiscriminator() {
return this.classDiscriminator; return this.classDiscriminator;
} }
public void setClassDiscriminator(@Nullable String classDiscriminator) { public void setClassDiscriminator(String classDiscriminator) {
this.classDiscriminator = classDiscriminator; this.classDiscriminator = classDiscriminator;
} }
public @Nullable ClassDiscriminatorMode getClassDiscriminatorMode() { public ClassDiscriminatorMode getClassDiscriminatorMode() {
return this.classDiscriminatorMode; return this.classDiscriminatorMode;
} }
public void setClassDiscriminatorMode(@Nullable ClassDiscriminatorMode classDiscriminatorMode) { public void setClassDiscriminatorMode(ClassDiscriminatorMode classDiscriminatorMode) {
this.classDiscriminatorMode = classDiscriminatorMode; this.classDiscriminatorMode = classDiscriminatorMode;
} }
public @Nullable Boolean getDecodeEnumsCaseInsensitive() { public boolean isDecodeEnumsCaseInsensitive() {
return this.decodeEnumsCaseInsensitive; return this.decodeEnumsCaseInsensitive;
} }
public void setDecodeEnumsCaseInsensitive(@Nullable Boolean decodeEnumsCaseInsensitive) { public void setDecodeEnumsCaseInsensitive(boolean decodeEnumsCaseInsensitive) {
this.decodeEnumsCaseInsensitive = decodeEnumsCaseInsensitive; this.decodeEnumsCaseInsensitive = decodeEnumsCaseInsensitive;
} }
public @Nullable Boolean getUseAlternativeNames() { public boolean isUseAlternativeNames() {
return this.useAlternativeNames; return this.useAlternativeNames;
} }
public void setUseAlternativeNames(@Nullable Boolean useAlternativeNames) { public void setUseAlternativeNames(boolean useAlternativeNames) {
this.useAlternativeNames = useAlternativeNames; this.useAlternativeNames = useAlternativeNames;
} }
public @Nullable Boolean getAllowTrailingComma() { public boolean isAllowTrailingComma() {
return this.allowTrailingComma; return this.allowTrailingComma;
} }
public void setAllowTrailingComma(@Nullable Boolean allowTrailingComma) { public void setAllowTrailingComma(boolean allowTrailingComma) {
this.allowTrailingComma = allowTrailingComma; this.allowTrailingComma = allowTrailingComma;
} }
public @Nullable Boolean getAllowComments() { public boolean isAllowComments() {
return this.allowComments; return this.allowComments;
} }
public void setAllowComments(@Nullable Boolean allowComments) { public void setAllowComments(boolean allowComments) {
this.allowComments = allowComments; this.allowComments = allowComments;
} }

99
module/spring-boot-kotlinx-serialization-json/src/test/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonPropertiesTests.java

@ -0,0 +1,99 @@
/*
* Copyright 2012-present 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
*
* https://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.kotlinx.serialization.json.autoconfigure;
import kotlinx.serialization.json.Json;
import kotlinx.serialization.json.JsonBuilder;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link KotlinxSerializationJsonProperties}.
*
* @author Andy Wilkinson
*/
class KotlinxSerializationJsonPropertiesTests {
@ParameterizedTest
@EnumSource
void defaultsAreAligned(JsonBuilderSettings settings) {
JsonBuilder jsonBuilder = new JsonBuilder(Json.Default);
KotlinxSerializationJsonProperties properties = new KotlinxSerializationJsonProperties();
assertThat(settings.propertyGetter.get(properties)).isEqualTo(settings.jsonBuilderGetter.get(jsonBuilder));
}
private enum JsonBuilderSettings {
ALLOW_COMMENTS(KotlinxSerializationJsonProperties::isAllowComments, JsonBuilder::getAllowComments),
ALLOW_SPECIAL_FLOATING_POINT_VALUES(KotlinxSerializationJsonProperties::isAllowSpecialFloatingPointValues,
JsonBuilder::getAllowSpecialFloatingPointValues),
ALLOW_STRUCTURED_MAP_KEYS(KotlinxSerializationJsonProperties::isAllowStructuredMapKeys,
JsonBuilder::getAllowStructuredMapKeys),
ALLOW_TRAILING_COMMA(KotlinxSerializationJsonProperties::isAllowTrailingComma,
JsonBuilder::getAllowTrailingComma),
CLASS_DISCRIMINATOR(KotlinxSerializationJsonProperties::getClassDiscriminator,
JsonBuilder::getClassDiscriminator),
CLASS_DISCRIMINATOR_MODE(KotlinxSerializationJsonProperties::getClassDiscriminatorMode,
JsonBuilder::getClassDiscriminatorMode),
COERCE_INPUT_VALUES(KotlinxSerializationJsonProperties::isCoerceInputValues, JsonBuilder::getCoerceInputValues),
DECODE_ENUMS_CASE_INSENSITIVE(KotlinxSerializationJsonProperties::isDecodeEnumsCaseInsensitive,
JsonBuilder::getDecodeEnumsCaseInsensitive),
ENCODE_DEFAULTS(KotlinxSerializationJsonProperties::isEncodeDefaults, JsonBuilder::getEncodeDefaults),
EXPLICIT_NULLS(KotlinxSerializationJsonProperties::isExplicitNulls, JsonBuilder::getExplicitNulls),
IGNORE_UNKNOWN_KEYS(KotlinxSerializationJsonProperties::isIgnoreUnknownKeys, JsonBuilder::getIgnoreUnknownKeys),
LENIENT(KotlinxSerializationJsonProperties::isLenient, JsonBuilder::isLenient),
NAMING_STRATEGY(KotlinxSerializationJsonProperties::getNamingStrategy, JsonBuilder::getNamingStrategy),
PRETTY_PRINT(KotlinxSerializationJsonProperties::isPrettyPrint, JsonBuilder::getPrettyPrint),
USE_ALTERNATIVE_NAMES(KotlinxSerializationJsonProperties::isUseAlternativeNames,
JsonBuilder::getUseAlternativeNames);
private final Accessor<KotlinxSerializationJsonProperties, ?> propertyGetter;
private final Accessor<JsonBuilder, ?> jsonBuilderGetter;
JsonBuilderSettings(Accessor<KotlinxSerializationJsonProperties, @Nullable Object> propertyGetter,
Accessor<JsonBuilder, @Nullable Object> jsonBuilderGetter) {
this.propertyGetter = propertyGetter;
this.jsonBuilderGetter = jsonBuilderGetter;
}
private interface Accessor<S, @Nullable P extends @Nullable Object> {
@Nullable P get(S source);
}
}
}
Loading…
Cancel
Save