diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckSpringConfigurationMetadata.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckSpringConfigurationMetadata.java new file mode 100644 index 0000000000..a41d1448c7 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckSpringConfigurationMetadata.java @@ -0,0 +1,167 @@ +/* + * Copyright 2012-2022 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.build.context.properties; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.gradle.api.DefaultTask; +import org.gradle.api.GradleException; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.api.tasks.SourceTask; +import org.gradle.api.tasks.TaskAction; + +/** + * {@link SourceTask} that checks {@code spring-configuration-metadata.json} files. + * + * @author Andy Wilkinson + */ +public class CheckSpringConfigurationMetadata extends DefaultTask { + + private List exclusions = new ArrayList<>(); + + private final RegularFileProperty reportLocation; + + private final RegularFileProperty metadataLocation; + + public CheckSpringConfigurationMetadata() { + this.metadataLocation = getProject().getObjects().fileProperty(); + this.reportLocation = getProject().getObjects().fileProperty(); + } + + @OutputFile + public RegularFileProperty getReportLocation() { + return this.reportLocation; + } + + @InputFile + @PathSensitive(PathSensitivity.RELATIVE) + public RegularFileProperty getMetadataLocation() { + return this.metadataLocation; + } + + public void setExclusions(List exclusions) { + this.exclusions = exclusions; + } + + @Input + public List getExclusions() { + return this.exclusions; + } + + @TaskAction + void check() throws JsonParseException, IOException { + Report report = createReport(); + File reportFile = getReportLocation().get().getAsFile(); + Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + if (report.hasProblems()) { + throw new GradleException( + "Problems found in Spring configuration metadata. See " + reportFile + " for details."); + } + } + + @SuppressWarnings("unchecked") + private Report createReport() throws IOException, JsonParseException, JsonMappingException { + ObjectMapper objectMapper = new ObjectMapper(); + File file = this.metadataLocation.get().getAsFile(); + Report report = new Report(getProject().getProjectDir().toPath().relativize(file.toPath())); + Map json = objectMapper.readValue(file, Map.class); + List> properties = (List>) json.get("properties"); + for (Map property : properties) { + String name = (String) property.get("name"); + if (!isDeprecated(property) && !isDescribed(property) && !isExcluded(name)) { + report.propertiesWithNoDescription.add(name); + } + } + return report; + } + + private boolean isExcluded(String propertyName) { + for (String exclusion : this.exclusions) { + if (propertyName.equals(exclusion)) { + return true; + } + if (exclusion.endsWith(".*")) { + if (propertyName.startsWith(exclusion.substring(0, exclusion.length() - 2))) { + return true; + } + } + } + return false; + } + + @SuppressWarnings("unchecked") + private boolean isDeprecated(Map property) { + return (Map) property.get("deprecation") != null; + } + + private boolean isDescribed(Map property) { + return property.get("description") != null; + } + + private static final class Report implements Iterable { + + private final List propertiesWithNoDescription = new ArrayList<>(); + + private final Path source; + + private Report(Path source) { + this.source = source; + } + + private boolean hasProblems() { + return !this.propertiesWithNoDescription.isEmpty(); + } + + @Override + public Iterator iterator() { + List lines = new ArrayList<>(); + lines.add(this.source.toString()); + lines.add(""); + if (this.propertiesWithNoDescription.isEmpty()) { + lines.add("No problems found."); + } + else { + lines.add("The following properties have no description:"); + lines.add(""); + lines.addAll(this.propertiesWithNoDescription.stream().map((line) -> "\t" + line) + .collect(Collectors.toList())); + } + lines.add(""); + return lines.iterator(); + + } + + } + +} diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesPlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesPlugin.java index 4f8c5db265..8229e5ddb4 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesPlugin.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesPlugin.java @@ -25,8 +25,10 @@ import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.artifacts.Configuration; +import org.gradle.api.file.RegularFile; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.provider.Provider; import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskProvider; @@ -41,6 +43,7 @@ import org.springframework.util.StringUtils; * *
    *
  • Adding a dependency on the configuration properties annotation processor. + *
  • Disables incremental compilation to avoid property descriptions being lost. *
  • Configuring the additional metadata locations annotation processor compiler * argument. *
  • Adding the outputs of the processResources task as inputs of the compileJava task @@ -66,12 +69,19 @@ public class ConfigurationPropertiesPlugin implements Plugin { */ public static final String CHECK_ADDITIONAL_SPRING_CONFIGURATION_METADATA_TASK_NAME = "checkAdditionalSpringConfigurationMetadata"; + /** + * Name of the {@link CheckAdditionalSpringConfigurationMetadata} task. + */ + public static final String CHECK_SPRING_CONFIGURATION_METADATA_TASK_NAME = "checkSpringConfigurationMetadata"; + @Override public void apply(Project project) { project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> { addConfigurationProcessorDependency(project); + disableIncrementalCompilation(project); configureAdditionalMetadataLocationsCompilerArgument(project); registerCheckAdditionalMetadataTask(project); + registerCheckMetadataTask(project); addMetadataArtifact(project); }); } @@ -83,6 +93,13 @@ public class ConfigurationPropertiesPlugin implements Plugin { ":spring-boot-project:spring-boot-tools:spring-boot-configuration-processor"))); } + private void disableIncrementalCompilation(Project project) { + SourceSet mainSourceSet = project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets() + .getByName(SourceSet.MAIN_SOURCE_SET_NAME); + project.getTasks().named(mainSourceSet.getCompileJavaTaskName(), JavaCompile.class) + .configure((compileJava) -> compileJava.getOptions().setIncremental(false)); + } + private void addMetadataArtifact(Project project) { SourceSet mainSourceSet = project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets() .getByName(SourceSet.MAIN_SOURCE_SET_NAME); @@ -124,4 +141,22 @@ public class ConfigurationPropertiesPlugin implements Plugin { .configure((check) -> check.dependsOn(checkConfigurationMetadata)); } + private void registerCheckMetadataTask(Project project) { + TaskProvider checkConfigurationMetadata = project.getTasks() + .register(CHECK_SPRING_CONFIGURATION_METADATA_TASK_NAME, CheckSpringConfigurationMetadata.class); + checkConfigurationMetadata.configure((check) -> { + SourceSet mainSourceSet = project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets() + .getByName(SourceSet.MAIN_SOURCE_SET_NAME); + Provider metadataLocation = project.getTasks() + .named(mainSourceSet.getCompileJavaTaskName(), JavaCompile.class) + .flatMap((javaCompile) -> javaCompile.getDestinationDirectory() + .file("META-INF/spring-configuration-metadata.json")); + check.getMetadataLocation().set(metadataLocation); + check.getReportLocation().set( + project.getLayout().getBuildDirectory().file("reports/spring-configuration-metadata/check.txt")); + }); + project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME) + .configure((check) -> check.dependsOn(checkConfigurationMetadata)); + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/AutoTimeProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/AutoTimeProperties.java index c8f1cc2704..a1727b33fa 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/AutoTimeProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/AutoTimeProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -30,10 +30,19 @@ import org.springframework.boot.actuate.metrics.AutoTimer; */ public final class AutoTimeProperties implements AutoTimer { + /** + * Whether to enable auto-timing. + */ private boolean enabled = true; + /** + * Whether to publish percentile histrograms. + */ private boolean percentilesHistogram; + /** + * Percentiles for which additional time series should be published. + */ private double[] percentiles; /** diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/wavefront/WavefrontProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/wavefront/WavefrontProperties.java index 9c5eb330a6..b99706c348 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/wavefront/WavefrontProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/wavefront/WavefrontProperties.java @@ -97,10 +97,20 @@ public class WavefrontProperties extends PushRegistryProperties { public static class Sender { + /** + * Maximum queue size of the in-memory buffer. + */ private int maxQueueSize = 50000; + /** + * Interval at which points are flushed to the Wavefront server. + */ private Duration flushInterval = Duration.ofSeconds(1); + /** + * Maximum message size, such that each batch is reported as one or more messages + * where no message exceeds the specified size. + */ private DataSize messageSize = DataSize.ofBytes(Integer.MAX_VALUE); public int getMaxQueueSize() { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 5de5385b54..87ce8a186a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -243,15 +243,6 @@ "description": "Whether to enable Solr health check.", "defaultValue": true }, - { - "name": "management.health.status.order", - "defaultValue": [ - "DOWN", - "OUT_OF_SERVICE", - "UP", - "UNKNOWN" - ] - }, { "name": "management.info.build.enabled", "type": "java.lang.Boolean", @@ -605,6 +596,14 @@ "level": "error" } }, + { + "name": "management.server.ssl.certificate", + "description": "Path to a PEM-encoded SSL certificate file." + }, + { + "name": "management.server.ssl.certificate-private-key", + "description": "Path to a PEM-encoded private key file for the SSL certificate." + }, { "name": "management.server.ssl.ciphers", "description": "Supported SSL ciphers." @@ -651,6 +650,14 @@ "description": "SSL protocol to use.", "defaultValue": "TLS" }, + { + "name": "management.server.ssl.trust-certificate", + "description": "Path to a PEM-encoded SSL certificate authority file." + }, + { + "name": "management.server.ssl.trust-certificate-private-key", + "description": "Path to a PEM-encoded private key file for the SSL certificate authority." + }, { "name": "management.server.ssl.trust-store", "description": "Trust store that holds SSL certificates." diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfigurationTests.java index a9ad0df229..332077f140 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfigurationTests.java @@ -123,7 +123,7 @@ class HealthEndpointAutoConfigurationTests { @Test void runWhenHasHttpCodeStatusMapperBeanIgnoresProperties() { this.contextRunner.withUserConfiguration(HttpCodeStatusMapperConfiguration.class) - .withPropertyValues("management.health.status.http-mapping.up=123").run((context) -> { + .withPropertyValues("management.endpoint.health.status.http-mapping.up=123").run((context) -> { HttpCodeStatusMapper mapper = context.getBean(HttpCodeStatusMapper.class); assertThat(mapper.getStatusCode(Status.UP)).isEqualTo(456); }); diff --git a/spring-boot-project/spring-boot-autoconfigure/build.gradle b/spring-boot-project/spring-boot-autoconfigure/build.gradle index 522a9287ad..750adf7479 100644 --- a/spring-boot-project/spring-boot-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-autoconfigure/build.gradle @@ -266,3 +266,13 @@ dependencies { testRuntimeOnly("jakarta.management.j2ee:jakarta.management.j2ee-api") testRuntimeOnly("org.jetbrains.kotlin:kotlin-reflect") } + +tasks.named("checkSpringConfigurationMetadata").configure { + exclusions = [ + "spring.datasource.dbcp2.*", + "spring.datasource.hikari.*", + "spring.datasource.oracleucp.*", + "spring.datasource.tomcat.*", + "spring.groovy.template.configuration.*" + ] +} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 8f67cab31e..355af3ffb3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -1752,8 +1752,14 @@ public class ServerProperties { public static class Options { + /** + * Socket options as defined in org.xnio.Options. + */ private Map socket = new LinkedHashMap<>(); + /** + * Server options as defined in io.undertow.UndertowOptions. + */ private Map server = new LinkedHashMap<>(); public Map getServer() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 5655679cd2..96a7ee1662 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -129,17 +129,67 @@ "name": "server.port", "defaultValue": 8080 }, + { + "name": "server.reactive.session.cookie.domain", + "description": "Domain for the cookie." + }, + { + "name": "server.reactive.session.cookie.http-only", + "description": "Whether to use \"HttpOnly\" cookies for the cookie." + }, + { + "name": "server.reactive.session.cookie.max-age", + "description": "Maximum age of the cookie. If a duration suffix is not specified, seconds will be used. A positive value indicates when the cookie expires relative to the current time. A value of 0 means the cookie should expire immediately. A negative value means no \"Max-Age\"." + }, + { + "name": "server.reactive.session.cookie.name", + "description": "Name for the cookie." + }, + { + "name": "server.reactive.session.cookie.path", + "description": "Path of the cookie." + }, + { + "name": "server.reactive.session.cookie.same-site", + "description": "SameSite setting for the cookie." + }, + { + "name": "server.reactive.session.cookie.secure", + "description": "Whether to always mark the cookie as secure." + }, + { + "name": "server.servlet.encoding.charset", + "description": "Charset of HTTP requests and responses. Added to the \"Content-Type\" header if not set explicitly.", + "defaultValue": "UTF-8" + }, { "name": "server.servlet.encoding.enabled", "type": "java.lang.Boolean", "description": "Whether to enable http encoding support.", "defaultValue": true }, + { + "name": "server.servlet.encoding.force", + "description": "Whether to force the encoding to the configured charset on HTTP requests and responses." + }, + { + "name": "server.servlet.encoding.force-request", + "description": "Whether to force the encoding to the configured charset on HTTP requests. Defaults to true when \"force\" has not been specified." + }, + { + "name": "server.servlet.encoding.force-response", + "description": "Whether to force the encoding to the configured charset on HTTP responses." + }, + { + "name": "server.servlet.encoding.mapping", + "description": "Mapping of locale to charset for response encoding." + }, { "name": "server.servlet.jsp.class-name", "description": "Class name of the servlet to use for JSPs. If registered is true and this class\n\t * is on the classpath then it will be registered.", "defaultValue": "org.apache.jasper.servlet.JspServlet" }, + { "name": "server.servlet.jsp.init-parameters", "description": "Init parameters used to configure the JSP servlet." @@ -159,6 +209,38 @@ "level": "error" } }, + { + "name": "server.servlet.session.cookie.comment", + "description": "Comment for the cookie." + }, + { + "name": "server.servlet.session.cookie.domain", + "description": "Domain for the cookie." + }, + { + "name": "server.servlet.session.cookie.http-only", + "description": "Whether to use \"HttpOnly\" cookies for the cookie." + }, + { + "name": "server.servlet.session.cookie.max-age", + "description": "Maximum age of the cookie. If a duration suffix is not specified, seconds will be used. A positive value indicates when the cookie expires relative to the current time. A value of 0 means the cookie should expire immediately. A negative value means no \"Max-Age\"." + }, + { + "name": "server.servlet.session.cookie.name", + "description": "Name of the cookie." + }, + { + "name": "server.servlet.session.cookie.path", + "description": "Path of the cookie." + }, + { + "name": "server.servlet.session.cookie.same-site", + "description": "SameSite setting for the cookie." + }, + { + "name": "server.servlet.session.cookie.secure", + "description": "Whether to always mark the cookie as secure." + }, { "name": "server.servlet.session.persistent", "description": "Whether to persist session data between restarts.", @@ -2054,6 +2136,84 @@ "level": "error" } }, + { + "name": "spring.rsocket.server.ssl.certificate", + "description": "Path to a PEM-encoded SSL certificate file." + }, + { + "name": "spring.rsocket.server.ssl.certificate-private-key", + "description": "Path to a PEM-encoded private key file for the SSL certificate." + }, + { + "name": "spring.rsocket.server.ssl.ciphers", + "description": "Supported SSL ciphers." + }, + { + "name": "spring.rsocket.server.ssl.client-auth", + "description": "Client authentication mode. Requires a trust store." + }, + { + "name": "spring.rsocket.server.ssl.enabled", + "description": "Whether to enable SSL support.", + "defaultValue": true + }, + { + "name": "spring.rsocket.server.ssl.enabled-protocols", + "description": "Enabled SSL protocols." + }, + { + "name": "spring.rsocket.server.ssl.key-alias", + "description": "Alias that identifies the key in the key store." + }, + { + "name": "spring.rsocket.server.ssl.key-password", + "description": "Password used to access the key in the key store." + }, + { + "name": "spring.rsocket.server.ssl.key-store", + "description": "Path to the key store that holds the SSL certificate (typically a jks file)." + }, + { + "name": "spring.rsocket.server.ssl.key-store-password", + "description": "Password used to access the key store." + }, + { + "name": "spring.rsocket.server.ssl.key-store-provider", + "description": "Provider for the key store." + }, + { + "name": "spring.rsocket.server.ssl.key-store-type", + "description": "Type of the key store." + }, + { + "name": "spring.rsocket.server.ssl.protocol", + "description": "SSL protocol to use.", + "defaultValue": "TLS" + }, + { + "name": "spring.rsocket.server.ssl.trust-certificate", + "description": "Path to a PEM-encoded SSL certificate authority file." + }, + { + "name": "spring.rsocket.server.ssl.trust-certificate-private-key", + "description": "Path to a PEM-encoded private key file for the SSL certificate authority." + }, + { + "name": "spring.rsocket.server.ssl.trust-store", + "description": "Trust store that holds SSL certificates." + }, + { + "name": "spring.rsocket.server.ssl.trust-store-password", + "description": "Password used to access the trust store." + }, + { + "name": "spring.rsocket.server.ssl.trust-store-provider", + "description": "Provider for the trust store." + }, + { + "name": "spring.rsocket.server.ssl.trust-store-type", + "description": "Type of the trust store." + }, { "name": "spring.rsocket.server.transport", "defaultValue": "tcp" @@ -2166,10 +2326,6 @@ "description": "Whether to enable Spring's HiddenHttpMethodFilter.", "defaultValue": false }, - { - "name": "spring.webflux.session.timeout", - "defaultValue": "30m" - }, { "name": "spring.webservices.wsdl-locations", "type": "java.util.List", diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Encoding.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Encoding.java index ee3ec73830..f6a09d36f4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Encoding.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Encoding.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -60,7 +60,7 @@ public class Encoding { private Boolean forceResponse; /** - * Locale in which to encode mapping. + * Mapping of locale to charset for response encoding.. */ private Map mapping; diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json index f26593c76b..9a50f7a40a 100644 --- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -324,6 +324,7 @@ { "name": "spring.jpa.defer-datasource-initialization", "type": "java.lang.Boolean", + "description": "Whether to defer DataSource initialization until after any EntityManagerFactory beans have been created and initialized.", "defaultValue": false }, {