diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/NamedMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/NamedMvcEndpoint.java index 87e9a59188..f92fb0eecf 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/NamedMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/NamedMvcEndpoint.java @@ -17,7 +17,7 @@ package org.springframework.boot.actuate.endpoint.mvc; /** - * A {@link MvcEndpoint} that also includes a logical name. Unlike {@link #getPath() + * An {@link MvcEndpoint} that also includes a logical name. Unlike {@link #getPath() * endpoints paths}, it should not be possible for a user to change the endpoint name. * Names provide a consistent way to reference an endpoint, for example they may be used * as the {@literal 'rel'} attribute in a HAL response. diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqExceptionTranslator.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqExceptionTranslator.java index d1f9de3913..778f83df54 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqExceptionTranslator.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jooq/JooqExceptionTranslator.java @@ -30,7 +30,7 @@ import org.springframework.jdbc.support.SQLExceptionTranslator; import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator; /** - * Transforms {@link java.sql.SQLException} into a Spring-specific @{link + * Transforms {@link java.sql.SQLException} into a Spring-specific {@link * DataAccessException}. * * @author Lukas Eder diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java index 6126f61966..e157173a7f 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java @@ -174,6 +174,20 @@ public class SecurityProperties implements SecurityPrerequisite { NONE, DOMAIN, ALL } + public enum ContentSecurityPolicyMode { + + /** + * Use the 'Content-Security-Policy' header. + */ + DEFAULT, + + /** + * Use the 'Content-Security-Policy-Report-Only' header. + */ + REPORT_ONLY + + } + /** * Enable cross site scripting (XSS) protection. */ @@ -194,6 +208,16 @@ public class SecurityProperties implements SecurityPrerequisite { */ private boolean contentType = true; + /** + * Value for content security policy header. + */ + private String contentSecurityPolicy; + + /** + * Security policy mode. + */ + private ContentSecurityPolicyMode contentSecurityPolicyMode = ContentSecurityPolicyMode.DEFAULT; + /** * HTTP Strict Transport Security (HSTS) mode (none, domain, all). */ @@ -231,6 +255,23 @@ public class SecurityProperties implements SecurityPrerequisite { this.contentType = contentType; } + public String getContentSecurityPolicy() { + return this.contentSecurityPolicy; + } + + public void setContentSecurityPolicy(String contentSecurityPolicy) { + this.contentSecurityPolicy = contentSecurityPolicy; + } + + public ContentSecurityPolicyMode getContentSecurityPolicyMode() { + return this.contentSecurityPolicyMode; + } + + public void setContentSecurityPolicyMode( + ContentSecurityPolicyMode contentSecurityPolicyMode) { + this.contentSecurityPolicyMode = contentSecurityPolicyMode; + } + public HSTS getHsts() { return this.hsts; } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java index 22747e1ad7..0197ca2ee7 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java @@ -29,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.security.SecurityProperties.Headers; +import org.springframework.boot.autoconfigure.security.SecurityProperties.Headers.ContentSecurityPolicyMode; import org.springframework.boot.autoconfigure.web.ErrorController; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -108,6 +109,16 @@ public class SpringBootWebSecurityConfiguration { if (!headers.isContentType()) { configurer.contentTypeOptions().disable(); } + if (StringUtils.hasText(headers.getContentSecurityPolicy())) { + String policyDirectives = headers.getContentSecurityPolicy(); + ContentSecurityPolicyMode mode = headers.getContentSecurityPolicyMode(); + if (mode == ContentSecurityPolicyMode.DEFAULT) { + configurer.contentSecurityPolicy(policyDirectives); + } + else { + configurer.contentSecurityPolicy(policyDirectives).reportOnly(); + } + } if (!headers.isXss()) { configurer.xssProtection().disable(); } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnCloudPlatformTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnCloudPlatformTests.java index f2de5088d2..9d9aa5a5a0 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnCloudPlatformTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnCloudPlatformTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.condition; +import org.junit.After; import org.junit.Test; import org.springframework.boot.cloud.CloudPlatform; @@ -33,6 +34,13 @@ public class ConditionalOnCloudPlatformTests { private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + @After + public void cleanUp() { + if (this.context != null) { + this.context.close(); + } + } + @Test public void outcomeWhenCloudfoundryPlatformNotPresentShouldNotMatch() throws Exception { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfigurationTests.java index 82d6956546..e20cbb74d9 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfigurationTests.java @@ -213,7 +213,9 @@ public class SpringBootWebSecurityConfigurationTests { .andExpect(MockMvcResultMatchers.header().string("Cache-Control", is(notNullValue()))) .andExpect(MockMvcResultMatchers.header().string("X-Frame-Options", - is(notNullValue()))); + is(notNullValue()))) + .andExpect(MockMvcResultMatchers.header() + .doesNotExist("Content-Security-Policy")); } @Test @@ -239,6 +241,39 @@ public class SpringBootWebSecurityConfigurationTests { MockMvcResultMatchers.header().doesNotExist("X-Frame-Options")); } + @Test + public void contentSecurityPolicyConfiguration() throws Exception { + this.context = SpringApplication.run(VanillaWebConfiguration.class, + "--security.headers.content-security-policy=default-src 'self';"); + MockMvc mockMvc = MockMvcBuilders + .webAppContextSetup((WebApplicationContext) this.context) + .addFilters((FilterChainProxy) this.context + .getBean("springSecurityFilterChain", Filter.class)) + .build(); + mockMvc.perform(MockMvcRequestBuilders.get("/")) + .andExpect(MockMvcResultMatchers.header() + .string("Content-Security-Policy", is("default-src 'self';"))) + .andExpect(MockMvcResultMatchers.header() + .doesNotExist("Content-Security-Policy-Report-Only")); + } + + @Test + public void contentSecurityPolicyReportOnlyConfiguration() throws Exception { + this.context = SpringApplication.run(VanillaWebConfiguration.class, + "--security.headers.content-security-policy=default-src 'self';", + "--security.headers.content-security-policy-mode=report-only"); + MockMvc mockMvc = MockMvcBuilders + .webAppContextSetup((WebApplicationContext) this.context) + .addFilters((FilterChainProxy) this.context + .getBean("springSecurityFilterChain", Filter.class)) + .build(); + mockMvc.perform(MockMvcRequestBuilders.get("/")) + .andExpect(MockMvcResultMatchers.header().string( + "Content-Security-Policy-Report-Only", is("default-src 'self';"))) + .andExpect(MockMvcResultMatchers.header() + .doesNotExist("Content-Security-Policy")); + } + @Configuration @Import(TestWebConfiguration.class) @Order(Ordered.LOWEST_PRECEDENCE) diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfigurationTests.java index 9b17db8c2f..478772ba3a 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfigurationTests.java @@ -577,7 +577,7 @@ public class WebMvcAutoConfigurationTests { } @Test - public void welcomePageMappingDoesNotHandleRequestThatDoNotAcceptTextHtml() + public void welcomePageMappingDoesNotHandleRequestsThatDoNotAcceptTextHtml() throws Exception { load("spring.resources.static-locations:classpath:/welcome-page/"); assertThat(this.context.getBeansOfType(WelcomePageHandlerMapping.class)) diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 55a54e9790..7f7b004284 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -87,7 +87,7 @@ 2.4.7 2.3.13 2.3.3 - 2.21 + 2.23 4.1.2 4.5.2 4.4.5 @@ -136,6 +136,7 @@ 4.1.4 3.0.3.RELEASE 2.53.1 + 2.23.2 2.2.2 3.1.0 1.1.1 @@ -1818,7 +1819,7 @@ org.seleniumhq.selenium htmlunit-driver - ${htmlunit.version} + ${selenium-htmlunit.version} org.seleniumhq.selenium diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java index 8cd7d81229..817d173359 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java @@ -45,15 +45,14 @@ public class RestartApplicationListener onApplicationStartingEvent((ApplicationStartingEvent) event); } if (event instanceof ApplicationPreparedEvent) { - Restarter.getInstance() - .prepare(((ApplicationPreparedEvent) event).getApplicationContext()); + onApplicationPreparedEvent((ApplicationPreparedEvent) event); } if (event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) { Restarter.getInstance().finish(); - if (event instanceof ApplicationFailedEvent) { - Restarter.getInstance().prepare(null); - } + } + if (event instanceof ApplicationFailedEvent) { + onApplicationFailedEvent((ApplicationFailedEvent) event); } } @@ -72,6 +71,14 @@ public class RestartApplicationListener } } + private void onApplicationPreparedEvent(ApplicationPreparedEvent event) { + Restarter.getInstance().prepare(event.getApplicationContext()); + } + + private void onApplicationFailedEvent(ApplicationFailedEvent event) { + Restarter.getInstance().remove(event.getApplicationContext()); + } + @Override public int getOrder() { return this.order; diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/Restarter.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/Restarter.java index 1c94bc5506..681026c032 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/Restarter.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/Restarter.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.BlockingDeque; import java.util.concurrent.Callable; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadFactory; import java.util.concurrent.locks.Lock; @@ -116,7 +117,7 @@ public class Restarter { private boolean finished = false; - private volatile ConfigurableApplicationContext rootContext; + private final List rootContexts = new CopyOnWriteArrayList(); /** * Internal constructor to create a new {@link Restarter} instance. @@ -314,9 +315,9 @@ public class Restarter { this.logger.debug("Stopping application"); this.stopLock.lock(); try { - if (this.rootContext != null) { - this.rootContext.close(); - this.rootContext = null; + for (ConfigurableApplicationContext context : this.rootContexts) { + context.close(); + this.rootContexts.remove(context); } cleanupCaches(); if (this.forceReferenceCleanup) { @@ -418,7 +419,13 @@ public class Restarter { if (applicationContext != null && applicationContext.getParent() != null) { return; } - this.rootContext = applicationContext; + this.rootContexts.add(applicationContext); + } + + void remove(ConfigurableApplicationContext applicationContext) { + if (applicationContext != null) { + this.rootContexts.remove(applicationContext); + } } private LeakSafeThread getLeakSafeThread() { diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestartApplicationListenerTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestartApplicationListenerTests.java index 31acad0f0e..34848adbc2 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestartApplicationListenerTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestartApplicationListenerTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.devtools.restart; +import java.util.List; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -64,8 +66,8 @@ public class RestartApplicationListenerTests { assertThat(ReflectionTestUtils.getField(Restarter.getInstance(), "args")) .isEqualTo(ARGS); assertThat(Restarter.getInstance().isFinished()).isTrue(); - assertThat(ReflectionTestUtils.getField(Restarter.getInstance(), "rootContext")) - .isNotNull(); + assertThat((List) ReflectionTestUtils.getField(Restarter.getInstance(), + "rootContexts")).isNotEmpty(); } @Test @@ -74,8 +76,8 @@ public class RestartApplicationListenerTests { assertThat(ReflectionTestUtils.getField(Restarter.getInstance(), "args")) .isEqualTo(ARGS); assertThat(Restarter.getInstance().isFinished()).isTrue(); - assertThat(ReflectionTestUtils.getField(Restarter.getInstance(), "rootContext")) - .isNull(); + assertThat((List) ReflectionTestUtils.getField(Restarter.getInstance(), + "rootContexts")).isEmpty(); } @Test diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 3c8b477037..f295f097b7 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -430,6 +430,8 @@ content into your application; rather pick only the properties that you need. security.filter-order=0 # Security filter chain order. security.filter-dispatcher-types=ASYNC, FORWARD, INCLUDE, REQUEST # Security filter chain dispatcher types. security.headers.cache=true # Enable cache control HTTP headers. + security.headers.content-security-policy= # Value for content security policy header. + security.headers.content-security-policy-mode=default # Content security policy mode (default, report-only). security.headers.content-type=true # Enable "X-Content-Type-Options" header. security.headers.frame=true # Enable "X-Frame-Options" header. security.headers.hsts= # HTTP Strict Transport Security (HSTS) mode (none, domain, all). diff --git a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 321bdb9e61..c8dd9ba81f 100644 --- a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -811,7 +811,7 @@ If you are using Jolokia but you don't want Spring Boot to configure it, simply == Loggers Spring Boot Actuator includes the ability to view and configure the log levels of your application at runtime. You can view either the entire list or an individual logger's -configuration which is made up of both the explictily configured logging level as well as +configuration which is made up of both the explicitly configured logging level as well as the effective logging level given to it by the logging framework. These levels can be: * `TRACE` @@ -823,7 +823,7 @@ the effective logging level given to it by the logging framework. These levels * `OFF` * `null` -with `null` indicating that there is no explict configuration. +with `null` indicating that there is no explicit configuration. diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 98b31f93cb..776ed4b367 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3883,7 +3883,7 @@ abstraction expects. No further customization is applied on it. EhCache 2.x is used if a file named `ehcache.xml` can be found at the root of the classpath. If EhCache 2.x, the `EhCacheCacheManager` provided by the `spring-boot-starter-cache` '`Starter`' and such file is present it is used to bootstrap -the cache manager. An alternate configuration file can be provide a well using: +the cache manager. An alternate configuration file can be provided as well using: [source,properties,indent=0] ---- diff --git a/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc index 608f83a09b..00b0b781ef 100644 --- a/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc +++ b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc @@ -769,7 +769,7 @@ dependencies out-of-the-box so you may want to have a look to the {propdeps-plugin}[`propdeps-plugin`] in the meantime. TIP: repackaged archives do not contain devtools by default. If you want to use -<>, you'll need to enable the +<>, you'll need to disable the `excludeDevtools` build property to include it. The property is supported with both the Maven and Gradle plugins. diff --git a/spring-boot-samples/spring-boot-sample-test-nomockito/pom.xml b/spring-boot-samples/spring-boot-sample-test-nomockito/pom.xml index 2bda0f5137..bc99def749 100644 --- a/spring-boot-samples/spring-boot-sample-test-nomockito/pom.xml +++ b/spring-boot-samples/spring-boot-sample-test-nomockito/pom.xml @@ -42,6 +42,7 @@ org.assertj assertj-core + test diff --git a/spring-boot-samples/spring-boot-sample-test-nomockito/src/test/java/sample/testnomockito/SampleTestNoMockitoApplicationTest.java b/spring-boot-samples/spring-boot-sample-test-nomockito/src/test/java/sample/testnomockito/SampleTestNoMockitoApplicationTest.java index 589bb0c4f1..70e89a1f24 100644 --- a/spring-boot-samples/spring-boot-sample-test-nomockito/src/test/java/sample/testnomockito/SampleTestNoMockitoApplicationTest.java +++ b/spring-boot-samples/spring-boot-sample-test-nomockito/src/test/java/sample/testnomockito/SampleTestNoMockitoApplicationTest.java @@ -10,7 +10,7 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests that {code ResetMocksTestExecutionListener} and + * Tests that {@code ResetMocksTestExecutionListener} and * {@code MockitoTestExecutionListener} gracefully degrade when Mockito is not on the * classpath. * diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/webdriver/LocalHostWebConnectionHtmlUnitDriverTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/webdriver/LocalHostWebConnectionHtmlUnitDriverTests.java index 66ed6e53bb..b618de2ce9 100644 --- a/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/webdriver/LocalHostWebConnectionHtmlUnitDriverTests.java +++ b/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/webdriver/LocalHostWebConnectionHtmlUnitDriverTests.java @@ -81,7 +81,9 @@ public class LocalHostWebConnectionHtmlUnitDriverTests { throws Exception { this.thrown.expect(IllegalArgumentException.class); this.thrown.expectMessage("Environment must not be null"); - new LocalHostWebConnectionHtmlUnitDriver(null, mock(Capabilities.class)); + Capabilities capabilities = mock(Capabilities.class); + given(capabilities.getBrowserName()).willReturn("chrome"); + new LocalHostWebConnectionHtmlUnitDriver(null, capabilities); } @Test diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java index 6cc20a4e44..ef6f62f8b3 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java @@ -52,7 +52,7 @@ public class RunProcess { /** * Creates new {@link RunProcess} instance for the specified command. - * @param command the program to execute and it's arguments + * @param command the program to execute and its arguments */ public RunProcess(String... command) { this(null, command); @@ -63,7 +63,7 @@ public class RunProcess { * command. * @param workingDirectory the working directory of the child process or {@code null} * to run in the working directory of the current Java process - * @param command the program to execute and it's arguments + * @param command the program to execute and its arguments */ public RunProcess(File workingDirectory, String... command) { this.workingDirectory = workingDirectory; diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/ExplodedArchive.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/ExplodedArchive.java index 5f6b8fb63e..6efca10a31 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/ExplodedArchive.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/archive/ExplodedArchive.java @@ -65,7 +65,7 @@ public class ExplodedArchive implements Archive { * Create a new {@link ExplodedArchive} instance. * @param root the root folder * @param recursive if recursive searching should be used to locate the manifest. - * Defaults to {@code true}, folders with a large tree might want to set this to {code + * Defaults to {@code true}, folders with a large tree might want to set this to {@code * false}. */ public ExplodedArchive(File root, boolean recursive) { diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index b22b1b7e57..dc08eff497 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -89,7 +89,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { /** * Current working directory to use for the application. If not specified, basedir - * will be used NOTE: the use of working directory means that processes will be + * will be used. NOTE: the use of working directory means that processes will be * started by forking a new JVM. * @since 1.5 */ diff --git a/spring-boot/src/main/java/org/springframework/boot/web/support/ErrorPageFilter.java b/spring-boot/src/main/java/org/springframework/boot/web/support/ErrorPageFilter.java index 484bc42d08..19a612ec75 100644 --- a/spring-boot/src/main/java/org/springframework/boot/web/support/ErrorPageFilter.java +++ b/spring-boot/src/main/java/org/springframework/boot/web/support/ErrorPageFilter.java @@ -185,7 +185,14 @@ public class ErrorPageFilter implements Filter, ErrorPageRegistry { request.getRequestDispatcher(path).forward(request, response); } - private String getDescription(HttpServletRequest request) { + /** + * Return the description for the given request. By default this method will return a + * description based on the request {@code servletPath} and {@code pathInfo}. + * @param request the source request + * @return the description + * @since 1.5.0 + */ + protected String getDescription(HttpServletRequest request) { return "[" + request.getServletPath() + (request.getPathInfo() == null ? "" : request.getPathInfo()) + "]"; }