Document Devtools' property defaults directly in reference docs

Closes gh-29406
This commit is contained in:
Andy Wilkinson 2022-03-11 08:15:40 +00:00
parent bbdef2b026
commit cced7edd9c
7 changed files with 154 additions and 25 deletions

View File

@ -0,0 +1,101 @@
/*
* 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.devtools;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import org.gradle.api.DefaultTask;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
/**
* Task for documenting Devtools' property defaults.
*
* @author Andy Wilkinson
*/
public class DocumentDevtoolsPropertyDefaults extends DefaultTask {
private Configuration devtools;
private final RegularFileProperty outputFile;
public DocumentDevtoolsPropertyDefaults() {
this.devtools = getProject().getConfigurations().create("devtools");
this.outputFile = getProject().getObjects().fileProperty();
this.outputFile.convention(getProject().getLayout().getBuildDirectory()
.file("docs/generated/using/devtools-property-defaults.adoc"));
Map<String, String> dependency = new HashMap<>();
dependency.put("path", ":spring-boot-project:spring-boot-devtools");
dependency.put("configuration", "propertyDefaults");
this.devtools.getDependencies().add(getProject().getDependencies().project(dependency));
}
@InputFiles
public FileCollection getDevtools() {
return this.devtools;
}
@OutputFile
public RegularFileProperty getOutputFile() {
return this.outputFile;
}
@TaskAction
void documentPropertyDefaults() throws IOException {
Map<String, String> properties = loadProperties();
documentProperties(properties);
}
private Map<String, String> loadProperties() throws IOException, FileNotFoundException {
Properties properties = new Properties();
Map<String, String> sortedProperties = new TreeMap<>();
try (FileInputStream stream = new FileInputStream(this.devtools.getSingleFile())) {
properties.load(stream);
for (String name : properties.stringPropertyNames()) {
sortedProperties.put(name, properties.getProperty(name));
}
}
return sortedProperties;
}
private void documentProperties(Map<String, String> properties) throws IOException {
try (PrintWriter writer = new PrintWriter(new FileWriter(this.outputFile.getAsFile().get()))) {
writer.println("[cols=\"3,1\"]");
writer.println("|===");
writer.println("| Name | Default Value");
properties.forEach((name, value) -> {
writer.println();
writer.printf("| `%s`%n", name);
writer.printf("| `%s`%n", value);
});
writer.println("|===");
}
}
}

View File

@ -13,6 +13,13 @@ configurations {
intTestDependencies {
extendsFrom dependencyManagement
}
propertyDefaults
}
artifacts {
propertyDefaults(file("build/resources/main/org/springframework/boot/devtools/env/devtools-property-defaults.properties")) {
builtBy(processResources)
}
}
dependencies {

View File

@ -16,9 +16,11 @@
package org.springframework.boot.devtools.env;
import java.util.Collections;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.logging.Log;
@ -62,23 +64,19 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro
private static final Map<String, Object> PROPERTIES;
static {
Map<String, Object> properties = new HashMap<>();
properties.put("spring.thymeleaf.cache", "false");
properties.put("spring.freemarker.cache", "false");
properties.put("spring.groovy.template.cache", "false");
properties.put("spring.mustache.cache", "false");
properties.put("server.servlet.session.persistent", "true");
properties.put("spring.h2.console.enabled", "true");
properties.put("spring.web.resources.cache.period", "0");
properties.put("spring.web.resources.chain.cache", "false");
properties.put("spring.template.provider.cache", "false");
properties.put("spring.mvc.log-resolved-exception", "true");
properties.put("server.error.include-binding-errors", "ALWAYS");
properties.put("server.error.include-message", "ALWAYS");
properties.put("server.error.include-stacktrace", "ALWAYS");
properties.put("server.servlet.jsp.init-parameters.development", "true");
properties.put("spring.reactor.debug", "true");
PROPERTIES = Collections.unmodifiableMap(properties);
Properties properties = new Properties();
try (InputStream stream = DevToolsPropertyDefaultsPostProcessor.class
.getResourceAsStream("devtools-property-defaults.properties")) {
properties.load(stream);
}
catch (IOException ex) {
throw new RuntimeException("Failed to load devtools-property-defaults.properties", ex);
}
Map<String, Object> map = new HashMap<>();
for (String name : properties.stringPropertyNames()) {
map.put(name, properties.getProperty(name));
}
PROPERTIES = map;
}
@Override

View File

@ -0,0 +1,15 @@
server.error.include-binding-errors=always
server.error.include-message=always
server.error.include-stacktrace=always
server.servlet.jsp.init-parameters.development=true
server.servlet.session.persistent=true
spring.freemarker.cache=false
spring.groovy.template.cache=false
spring.h2.console.enabled=true
spring.mustache.cache=false
spring.mvc.log-resolved-exception=true
spring.reactor.debug=true
spring.template.provider.cache=false
spring.thymeleaf.cache=false
spring.web.resources.cache.period=0
spring.web.resources.chain.cache=false

View File

@ -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.
@ -18,6 +18,7 @@ package org.springframework.boot.devtools.env;
import java.net.URL;
import java.util.Collections;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
@ -107,9 +108,11 @@ class DevToolPropertiesIntegrationTests {
this.context = getContext(application::run);
ConfigurableEnvironment environment = this.context.getEnvironment();
String includeStackTrace = environment.getProperty("server.error.include-stacktrace");
assertThat(includeStackTrace).isEqualTo(ErrorProperties.IncludeAttribute.ALWAYS.toString());
assertThat(includeStackTrace)
.isEqualTo(ErrorProperties.IncludeAttribute.ALWAYS.toString().toLowerCase(Locale.ENGLISH));
String includeMessage = environment.getProperty("server.error.include-message");
assertThat(includeMessage).isEqualTo(ErrorProperties.IncludeAttribute.ALWAYS.toString());
assertThat(includeMessage)
.isEqualTo(ErrorProperties.IncludeAttribute.ALWAYS.toString().toLowerCase(Locale.ENGLISH));
}
protected ConfigurableApplicationContext getContext(Supplier<ConfigurableApplicationContext> supplier)

View File

@ -243,6 +243,8 @@ task documentConfigurationProperties(type: org.springframework.boot.build.contex
outputDir = file("${buildDir}/docs/generated/")
}
task documentDevtoolsPropertyDefaults(type: org.springframework.boot.build.devtools.DocumentDevtoolsPropertyDefaults) {}
tasks.withType(org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask) {
dependsOn dependencyVersions
asciidoctorj {
@ -296,6 +298,7 @@ syncDocumentationSourceForAsciidoctor {
dependsOn documentDependencyVersions
dependsOn documentVersionProperties
dependsOn documentConfigurationProperties
dependsOn documentDevtoolsPropertyDefaults
from("${buildDir}/docs/generated") {
into "asciidoc"
}

View File

@ -67,13 +67,15 @@ Cache options are usually configured by settings in your `application.properties
For example, Thymeleaf offers the configprop:spring.thymeleaf.cache[] property.
Rather than needing to set these properties manually, the `spring-boot-devtools` module automatically applies sensible development-time configuration.
Because you need more information about web requests while developing Spring MVC and Spring WebFlux applications, developer tools suggests you to enable `DEBUG` logging for the `web` logging group.
This will give you information about the incoming request, which handler is processing it, the response outcome, etc.
If you wish to log all request details (including potentially sensitive information), you can turn on the configprop:spring.mvc.log-request-details[] or configprop:spring.codec.log-request-details[] configuration properties.
The following table lists all the properties that are applied:
include::devtools-property-defaults.adoc[]
NOTE: If you don't want property defaults to be applied you can set configprop:spring.devtools.add-properties[] to `false` in your `application.properties`.
TIP: For a complete list of the properties that are applied by the devtools, see {spring-boot-devtools-module-code}/env/DevToolsPropertyDefaultsPostProcessor.java[DevToolsPropertyDefaultsPostProcessor].
Because you need more information about web requests while developing Spring MVC and Spring WebFlux applications, developer tools suggests you to enable `DEBUG` logging for the `web` logging group.
This will give you information about the incoming request, which handler is processing it, the response outcome, etc.
If you wish to log all request details (including potentially sensitive information), you can turn on the configprop:spring.mvc.log-request-details[] or configprop:spring.codec.log-request-details[] configuration properties.