diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/trace/WebRequestTraceFilterTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/trace/WebRequestTraceFilterTests.java index 4f5c552b5d..2830160678 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/trace/WebRequestTraceFilterTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/trace/WebRequestTraceFilterTests.java @@ -256,7 +256,7 @@ public class WebRequestTraceFilterTests { @Test public void filterHasError() { - this.filter.setErrorAttributes(new DefaultErrorAttributes()); + this.filter.setErrorAttributes(new DefaultErrorAttributes(false)); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); MockHttpServletResponse response = new MockHttpServletResponse(); response.setStatus(500); diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorProperties.java index 265b6de8f0..d162fa20a1 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2017 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. @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Value; * * @author Michael Stummvoll * @author Stephane Nicoll + * @author Vedran Pavic * @since 1.3.0 */ public class ErrorProperties { @@ -33,6 +34,11 @@ public class ErrorProperties { @Value("${error.path:/error}") private String path = "/error"; + /** + * Set whether to include "exception" attribute. + */ + private boolean includeException; + /** * When to include a "stacktrace" attribute. */ @@ -46,6 +52,14 @@ public class ErrorProperties { this.path = path; } + public boolean isIncludeException() { + return this.includeException; + } + + public void setIncludeException(boolean includeException) { + this.includeException = includeException; + } + public IncludeStacktrace getIncludeStacktrace() { return this.includeStacktrace; } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorAttributes.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorAttributes.java index d378ad48c5..7a062c5fa4 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorAttributes.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorAttributes.java @@ -54,6 +54,7 @@ import org.springframework.web.servlet.ModelAndView; * @author Phillip Webb * @author Dave Syer * @author Stephane Nicoll + * @author Vedran Pavic * @since 1.1.0 * @see ErrorAttributes */ @@ -64,6 +65,16 @@ public class DefaultErrorAttributes private static final String ERROR_ATTRIBUTE = DefaultErrorAttributes.class.getName() + ".ERROR"; + private boolean includeException; + + /** + * Create a new {@link DefaultErrorAttributes} instance. + * @param includeException whether to include "exception" attribute + */ + public DefaultErrorAttributes(boolean includeException) { + this.includeException = includeException; + } + @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; @@ -117,7 +128,9 @@ public class DefaultErrorAttributes while (error instanceof ServletException && error.getCause() != null) { error = ((ServletException) error).getCause(); } - errorAttributes.put("exception", error.getClass().getName()); + if (this.includeException) { + errorAttributes.put("exception", error.getClass().getName()); + } addErrorMessage(errorAttributes, error); if (includeStackTrace) { addStackTrace(errorAttributes, error); diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java index b52a9ba600..c7caf1f4fc 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/ErrorMvcAutoConfiguration.java @@ -98,7 +98,8 @@ public class ErrorMvcAutoConfiguration { @Bean @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT) public DefaultErrorAttributes errorAttributes() { - return new DefaultErrorAttributes(); + return new DefaultErrorAttributes( + this.serverProperties.getError().isIncludeException()); } @Bean diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorAttributesTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorAttributesTests.java index 7fbdb4624c..5f04b89b3e 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorAttributesTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/DefaultErrorAttributesTests.java @@ -41,10 +41,11 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link DefaultErrorAttributes}. * * @author Phillip Webb + * @author Vedran Pavic */ public class DefaultErrorAttributesTests { - private DefaultErrorAttributes errorAttributes = new DefaultErrorAttributes(); + private DefaultErrorAttributes errorAttributes = new DefaultErrorAttributes(false); private MockHttpServletRequest request = new MockHttpServletRequest(); @@ -87,8 +88,7 @@ public class DefaultErrorAttributesTests { .getErrorAttributes(this.requestAttributes, false); assertThat(this.errorAttributes.getError(this.requestAttributes)).isSameAs(ex); assertThat(modelAndView).isNull(); - assertThat(attributes.get("exception")) - .isEqualTo(RuntimeException.class.getName()); + assertThat(attributes.get("exception")).isNull(); assertThat(attributes.get("message")).isEqualTo("Test"); } @@ -99,8 +99,7 @@ public class DefaultErrorAttributesTests { Map attributes = this.errorAttributes .getErrorAttributes(this.requestAttributes, false); assertThat(this.errorAttributes.getError(this.requestAttributes)).isSameAs(ex); - assertThat(attributes.get("exception")) - .isEqualTo(RuntimeException.class.getName()); + assertThat(attributes.get("exception")).isNull(); assertThat(attributes.get("message")).isEqualTo("Test"); } @@ -120,8 +119,7 @@ public class DefaultErrorAttributesTests { this.request.setAttribute("javax.servlet.error.message", "Test"); Map attributes = this.errorAttributes .getErrorAttributes(this.requestAttributes, false); - assertThat(attributes.get("exception")) - .isEqualTo(RuntimeException.class.getName()); + assertThat(attributes.get("exception")).isNull(); assertThat(attributes.get("message")).isEqualTo("Test"); } @@ -134,8 +132,7 @@ public class DefaultErrorAttributesTests { .getErrorAttributes(this.requestAttributes, false); assertThat(this.errorAttributes.getError(this.requestAttributes)) .isSameAs(wrapped); - assertThat(attributes.get("exception")) - .isEqualTo(RuntimeException.class.getName()); + assertThat(attributes.get("exception")).isNull(); assertThat(attributes.get("message")).isEqualTo("Test"); } @@ -146,8 +143,7 @@ public class DefaultErrorAttributesTests { Map attributes = this.errorAttributes .getErrorAttributes(this.requestAttributes, false); assertThat(this.errorAttributes.getError(this.requestAttributes)).isSameAs(error); - assertThat(attributes.get("exception")) - .isEqualTo(OutOfMemoryError.class.getName()); + assertThat(attributes.get("exception")).isNull(); assertThat(attributes.get("message")).isEqualTo("Test error"); } @@ -179,6 +175,18 @@ public class DefaultErrorAttributesTests { assertThat(attributes.get("errors")).isEqualTo(bindingResult.getAllErrors()); } + @Test + public void withExceptionAttribute() throws Exception { + DefaultErrorAttributes errorAttributes = new DefaultErrorAttributes(true); + RuntimeException ex = new RuntimeException("Test"); + this.request.setAttribute("javax.servlet.error.exception", ex); + Map attributes = errorAttributes + .getErrorAttributes(this.requestAttributes, false); + assertThat(attributes.get("exception")) + .isEqualTo(RuntimeException.class.getName()); + assertThat(attributes.get("message")).isEqualTo("Test"); + } + @Test public void trace() throws Exception { RuntimeException ex = new RuntimeException("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 fb79a5db1f..6a291b0429 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -153,6 +153,7 @@ content into your application; rather pick only the properties that you need. server.connection-timeout= # Time in milliseconds that connectors will wait for another HTTP request before closing the connection. When not set, the connector's container-specific default will be used. Use a value of -1 to indicate no (i.e. infinite) timeout. server.display-name=application # Display name of the application. server.max-http-header-size=0 # Maximum size in bytes of the HTTP message header. + server.error.include-exception=false # Set whether to include "exception" attribute. server.error.include-stacktrace=never # When to include a "stacktrace" attribute. server.error.path=/error # Path of the error controller. server.error.whitelabel.enabled=true # Enable the default error page displayed in browsers in case of a server error.