diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java index ca70851af25..691dc7e6548 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java @@ -118,7 +118,7 @@ public abstract class DocumentConfigurationProperties extends DefaultTask { private void jsonPrefixes(Config config) { config.accept("spring.jackson"); config.accept("spring.gson"); - config.accept("spring.kotlin-serialization"); + config.accept("spring.kotlin.serialization"); } private void dataPrefixes(Config config) { diff --git a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/json.adoc b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/json.adoc index 74db0be74d1..063c992df34 100644 --- a/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/json.adoc +++ b/documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/json.adoc @@ -77,4 +77,4 @@ The preferred JSON-B implementation is Eclipse Yasson for which dependency manag Auto-configuration for Kotlin Serialization is provided. When `kotlinx-serialization-json` is on the classpath a https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/[Json] bean is automatically configured. -Several `+spring.kotlin-serialization.*+` configuration properties are provided for customizing the configuration. +Several `+spring.kotlin.serialization.*+` configuration properties are provided for customizing the configuration. diff --git a/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/GsonHttpMessageConvertersConfiguration.java b/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/GsonHttpMessageConvertersConfiguration.java index 67f8de5422a..e42a6b575de 100644 --- a/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/GsonHttpMessageConvertersConfiguration.java +++ b/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/GsonHttpMessageConvertersConfiguration.java @@ -42,7 +42,7 @@ class GsonHttpMessageConvertersConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnBean(Gson.class) - @Conditional(PreferGsonOrJacksonAndJsonbUnavailableCondition.class) + @Conditional(PreferGsonOrOtherJsonLibraryUnavailableCondition.class) static class GsonHttpMessageConverterConfiguration { @Bean @@ -55,9 +55,9 @@ class GsonHttpMessageConvertersConfiguration { } - private static class PreferGsonOrJacksonAndJsonbUnavailableCondition extends AnyNestedCondition { + private static class PreferGsonOrOtherJsonLibraryUnavailableCondition extends AnyNestedCondition { - PreferGsonOrJacksonAndJsonbUnavailableCondition() { + PreferGsonOrOtherJsonLibraryUnavailableCondition() { super(ConfigurationPhase.REGISTER_BEAN); } @@ -67,16 +67,16 @@ class GsonHttpMessageConvertersConfiguration { } - @Conditional(JacksonAndJsonbUnavailableCondition.class) + @Conditional(OtherJsonLibrariesUnavailableCondition.class) static class JacksonJsonbUnavailable { } } - private static class JacksonAndJsonbUnavailableCondition extends NoneNestedConditions { + private static class OtherJsonLibrariesUnavailableCondition extends NoneNestedConditions { - JacksonAndJsonbUnavailableCondition() { + OtherJsonLibrariesUnavailableCondition() { super(ConfigurationPhase.REGISTER_BEAN); } @@ -93,7 +93,7 @@ class GsonHttpMessageConvertersConfiguration { @ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "kotlin-serialization") - static class KotlinxSerialization { + static class KotlinSerializationPreferred { } diff --git a/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/JsonbHttpMessageConvertersConfiguration.java b/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/JsonbHttpMessageConvertersConfiguration.java index d382667f8d9..96b6a4ce357 100644 --- a/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/JsonbHttpMessageConvertersConfiguration.java +++ b/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/JsonbHttpMessageConvertersConfiguration.java @@ -42,7 +42,7 @@ class JsonbHttpMessageConvertersConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnBean(Jsonb.class) - @Conditional(PreferJsonbOrMissingJacksonAndGsonCondition.class) + @Conditional(PreferJsonbOrOtherJsonLibrariesMissingCondition.class) static class JsonbHttpMessageConverterConfiguration { @Bean @@ -55,9 +55,9 @@ class JsonbHttpMessageConvertersConfiguration { } - private static class PreferJsonbOrMissingJacksonAndGsonCondition extends AnyNestedCondition { + private static class PreferJsonbOrOtherJsonLibrariesMissingCondition extends AnyNestedCondition { - PreferJsonbOrMissingJacksonAndGsonCondition() { + PreferJsonbOrOtherJsonLibrariesMissingCondition() { super(ConfigurationPhase.REGISTER_BEAN); } @@ -67,16 +67,16 @@ class JsonbHttpMessageConvertersConfiguration { } - @Conditional(JacksonAndGsonAndKotlinSerializationMissingCondition.class) - static class JacksonAndGsonAndKotlinSerializationMissing { + @Conditional(OtherJsonLibrariesMissingMissingCondition.class) + static class OtherJsonLibrariesMissingMissing { } } - private static class JacksonAndGsonAndKotlinSerializationMissingCondition extends NoneNestedConditions { + private static class OtherJsonLibrariesMissingMissingCondition extends NoneNestedConditions { - JacksonAndGsonAndKotlinSerializationMissingCondition() { + OtherJsonLibrariesMissingMissingCondition() { super(ConfigurationPhase.REGISTER_BEAN); } @@ -92,7 +92,7 @@ class JsonbHttpMessageConvertersConfiguration { @ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "kotlin-serialization") - static class KotlinxPreferred { + static class KotlinPreferred { } diff --git a/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/KotlinSerializationHttpMessageConvertersConfiguration.java b/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/KotlinSerializationHttpMessageConvertersConfiguration.java index 89c996e242f..d8f1edf3fc9 100644 --- a/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/KotlinSerializationHttpMessageConvertersConfiguration.java +++ b/module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/KotlinSerializationHttpMessageConvertersConfiguration.java @@ -18,12 +18,17 @@ package org.springframework.boot.http.converter.autoconfigure; import kotlinx.serialization.json.Json; +import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.json.GsonHttpMessageConverter; +import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter; +import org.springframework.http.converter.json.JsonbHttpMessageConverter; import org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter; /** @@ -37,8 +42,7 @@ class KotlinSerializationHttpMessageConvertersConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnBean(Json.class) - @ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY, - havingValue = "kotlin-serialization") + @Conditional(PreferKotlinSerializationOrOtherJsonLibrariesUnavailableCondition.class) static class KotlinSerializationHttpMessageConverterConfiguration { @Bean @@ -49,4 +53,24 @@ class KotlinSerializationHttpMessageConvertersConfiguration { } + private static class PreferKotlinSerializationOrOtherJsonLibrariesUnavailableCondition extends AnyNestedCondition { + + PreferKotlinSerializationOrOtherJsonLibrariesUnavailableCondition() { + super(ConfigurationPhase.REGISTER_BEAN); + } + + @ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY, + havingValue = "kotlin-serialization") + static class KotlinSerializationPreferred { + + } + + @ConditionalOnMissingBean({ JacksonJsonHttpMessageConverter.class, JsonbHttpMessageConverter.class, + GsonHttpMessageConverter.class }) + static class OtherJsonLibrariesUnavailable { + + } + + } + } diff --git a/module/spring-boot-kotlin-serialization/build.gradle b/module/spring-boot-kotlin-serialization/build.gradle index 15dcac28f80..21f294ddf96 100644 --- a/module/spring-boot-kotlin-serialization/build.gradle +++ b/module/spring-boot-kotlin-serialization/build.gradle @@ -40,9 +40,3 @@ dependencies { testRuntimeOnly("ch.qos.logback:logback-classic") testRuntimeOnly("org.jetbrains.kotlin:kotlin-reflect") } - -tasks.named("checkAutoConfigurationClasses", CheckAutoConfigurationClasses.class) { - doFirst { - classpath = classpath.filter { !it.path.contains('/build/classes/kotlin/main') } - } -} diff --git a/module/spring-boot-kotlin-serialization/src/main/java/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationAutoConfiguration.java b/module/spring-boot-kotlin-serialization/src/main/java/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationAutoConfiguration.java index b7a02da0221..490304a3ea8 100644 --- a/module/spring-boot-kotlin-serialization/src/main/java/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationAutoConfiguration.java +++ b/module/spring-boot-kotlin-serialization/src/main/java/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationAutoConfiguration.java @@ -79,7 +79,7 @@ public final class KotlinSerializationAutoConfiguration { @Override public void customize(JsonBuilder jsonBuilder) { KotlinSerializationProperties properties = this.properties; - PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + PropertyMapper map = PropertyMapper.get(); map.from(properties::getNamingStrategy).to(setNamingStrategy(jsonBuilder)); map.from(properties::getPrettyPrint).to(jsonBuilder::setPrettyPrint); map.from(properties::getLenient).to(jsonBuilder::setLenient); diff --git a/module/spring-boot-kotlin-serialization/src/main/java/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationProperties.java b/module/spring-boot-kotlin-serialization/src/main/java/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationProperties.java index 1cd6c4eec51..c1d1387de1c 100644 --- a/module/spring-boot-kotlin-serialization/src/main/java/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationProperties.java +++ b/module/spring-boot-kotlin-serialization/src/main/java/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationProperties.java @@ -28,7 +28,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * @author Dmitry Sulman * @since 4.0.0 */ -@ConfigurationProperties("spring.kotlin-serialization") +@ConfigurationProperties("spring.kotlin.serialization") public class KotlinSerializationProperties { /** diff --git a/module/spring-boot-kotlin-serialization/src/test/kotlin/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationAutoConfigurationTests.kt b/module/spring-boot-kotlin-serialization/src/test/kotlin/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationAutoConfigurationTests.kt index 7f8fa6e9ec3..6ca75fb9776 100644 --- a/module/spring-boot-kotlin-serialization/src/test/kotlin/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationAutoConfigurationTests.kt +++ b/module/spring-boot-kotlin-serialization/src/test/kotlin/org/springframework/boot/kotlin/serialization/autoconfigure/KotlinSerializationAutoConfigurationTests.kt @@ -42,14 +42,14 @@ class KotlinSerializationAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(KotlinSerializationAutoConfiguration::class.java)) @Test - fun shouldSupplyBean() { + fun shouldSupplyJsonBean() { this.contextRunner.run { context -> assertThat(context).hasSingleBean(Json::class.java) } } @Test - fun shouldNotSupplyBean() { + fun shouldNotSupplyJsonBean() { this.contextRunner .withClassLoader(FilteredClassLoader(Json::class.java)) .run { context -> @@ -90,7 +90,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun serializeSnakeCase() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.naming-strategy=snake_case") + .withPropertyValues("spring.kotlin.serialization.naming-strategy=snake_case") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.encodeToString(DataObject("hello"))) @@ -101,7 +101,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun serializeKebabCase() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.naming-strategy=kebab_case") + .withPropertyValues("spring.kotlin.serialization.naming-strategy=kebab_case") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.encodeToString(DataObject("hello"))) @@ -112,7 +112,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun serializePrettyPrint() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.pretty-print=true") + .withPropertyValues("spring.kotlin.serialization.pretty-print=true") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.encodeToString(DataObject("hello"))) @@ -130,7 +130,7 @@ class KotlinSerializationAutoConfigurationTests { @Suppress("JsonStandardCompliance") fun deserializeLenient() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.lenient=true") + .withPropertyValues("spring.kotlin.serialization.lenient=true") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.decodeFromString("""{"stringField":hello}""")) @@ -141,7 +141,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun deserializeIgnoreUnknownKeys() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.ignore-unknown-keys=true") + .withPropertyValues("spring.kotlin.serialization.ignore-unknown-keys=true") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.decodeFromString("""{"stringField":"hello", "anotherField":"value"}""")) @@ -152,7 +152,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun serializeDefaults() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.encode-defaults=true") + .withPropertyValues("spring.kotlin.serialization.encode-defaults=true") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.encodeToString(DataObjectWithDefault("hello"))) @@ -163,7 +163,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun serializeExplicitNullsFalse() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.explicit-nulls=false") + .withPropertyValues("spring.kotlin.serialization.explicit-nulls=false") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.encodeToString(DataObjectWithDefault(null, "hello"))) @@ -174,7 +174,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun deserializeCoerceInputValues() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.coerce-input-values=true") + .withPropertyValues("spring.kotlin.serialization.coerce-input-values=true") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.decodeFromString("""{"stringField":"hello", "defaultField":null}""")) @@ -185,7 +185,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun serializeStructuredMapKeys() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.allow-structured-map-keys=true") + .withPropertyValues("spring.kotlin.serialization.allow-structured-map-keys=true") .run { context -> val json = context.getBean(Json::class.java) val map = mapOf( @@ -200,7 +200,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun serializeSpecialFloatingPointValues() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.allow-special-floating-point-values=true") + .withPropertyValues("spring.kotlin.serialization.allow-special-floating-point-values=true") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.encodeToString(DataObjectDouble(Double.NaN))) @@ -211,7 +211,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun serializeClassDiscriminator() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.class-discriminator=class") + .withPropertyValues("spring.kotlin.serialization.class-discriminator=class") .run { context -> val json = context.getBean(Json::class.java) val value: BaseClass = ChildClass("value") @@ -223,7 +223,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun serializeClassDiscriminatorNone() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.class-discriminator-mode=none") + .withPropertyValues("spring.kotlin.serialization.class-discriminator-mode=none") .run { context -> val json = context.getBean(Json::class.java) val value: BaseClass = ChildClass("value") @@ -235,7 +235,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun deserializeEnumsCaseInsensitive() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.decode-enums-case-insensitive=true") + .withPropertyValues("spring.kotlin.serialization.decode-enums-case-insensitive=true") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.decodeFromString("""{"values":["value_A", "alternative"]}""")) @@ -246,7 +246,7 @@ class KotlinSerializationAutoConfigurationTests { @Test fun deserializeAlternativeNames() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.use-alternative-names=false") + .withPropertyValues("spring.kotlin.serialization.use-alternative-names=false") .run { context -> val json = context.getBean(Json::class.java) assertThatExceptionOfType(SerializationException::class.java).isThrownBy { @@ -259,7 +259,7 @@ class KotlinSerializationAutoConfigurationTests { @Suppress("JsonStandardCompliance") fun deserializeTrailingComma() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.allow-trailing-comma=true") + .withPropertyValues("spring.kotlin.serialization.allow-trailing-comma=true") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.decodeFromString("""{"stringField":"hello",}""")) @@ -271,7 +271,7 @@ class KotlinSerializationAutoConfigurationTests { @Suppress("JsonStandardCompliance") fun deserializeComments() { this.contextRunner - .withPropertyValues("spring.kotlin-serialization.allow-comments=true") + .withPropertyValues("spring.kotlin.serialization.allow-comments=true") .run { context -> val json = context.getBean(Json::class.java) assertThat(json.decodeFromString("""{"stringField":"hello" /*comment*/}"""))