From 23892e33d6ed73a130850d27342dba631b9fb8d7 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 16 Mar 2018 14:30:42 -0700 Subject: [PATCH] Add text/plain error response support Refine `BasicErrorController` mappings so that only JSON and XML get structured responses. A simple string response is returned for all other media types. Fixes gh-12513 --- .../web/BasicErrorController.java | 29 +++++++++++++++---- .../BasicErrorControllerIntegrationTests.java | 14 +++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/BasicErrorController.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/BasicErrorController.java index 41363125d15..4da57344910 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/BasicErrorController.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/BasicErrorController.java @@ -31,7 +31,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.Assert; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; /** @@ -82,6 +81,16 @@ public class BasicErrorController extends AbstractErrorController { return this.errorProperties.getPath(); } + @RequestMapping(produces = { "application/xml", "text/xml", "application/json", + "application/*+xml", "application/*+json" }) + public ResponseEntity> errorStructured( + HttpServletRequest request) { + Map body = getErrorAttributes(request, + isIncludeStackTrace(request, MediaType.ALL)); + HttpStatus status = getStatus(request); + return new ResponseEntity>(body, status); + } + @RequestMapping(produces = "text/html") public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { @@ -94,12 +103,20 @@ public class BasicErrorController extends AbstractErrorController { } @RequestMapping - @ResponseBody - public ResponseEntity> error(HttpServletRequest request) { - Map body = getErrorAttributes(request, - isIncludeStackTrace(request, MediaType.ALL)); + public ResponseEntity errorText(HttpServletRequest request) { + Map attributes = getErrorAttributes(request, + isIncludeStackTrace(request, MediaType.TEXT_PLAIN)); + int padding = 0; + for (Map.Entry entry : attributes.entrySet()) { + padding = Math.max(padding, entry.getKey().length()); + } + StringBuffer body = new StringBuffer(); + for (Map.Entry entry : attributes.entrySet()) { + body.append(String.format("%-" + padding + "s : %s%n", entry.getKey(), + entry.getValue())); + } HttpStatus status = getStatus(request); - return new ResponseEntity>(body, status); + return new ResponseEntity(body.toString(), status); } /** diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/BasicErrorControllerIntegrationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/BasicErrorControllerIntegrationTests.java index 932d174c86b..3add527f788 100755 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/BasicErrorControllerIntegrationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/BasicErrorControllerIntegrationTests.java @@ -158,6 +158,7 @@ public class BasicErrorControllerIntegrationTests { load(); RequestEntity request = RequestEntity .post(URI.create(createUrl("/bodyValidation"))) + .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON).body("{}"); ResponseEntity entity = new TestRestTemplate().exchange(request, Map.class); String resp = entity.getBody().toString(); @@ -167,6 +168,19 @@ public class BasicErrorControllerIntegrationTests { assertThat(resp).contains(MethodArgumentNotValidException.class.getName()); } + @Test + public void testRequestBodyValidationForText() throws Exception { + load(); + RequestEntity request = RequestEntity.post(URI.create(createUrl("/"))) + .accept(MediaType.TEXT_PLAIN).build(); + ResponseEntity entity = new TestRestTemplate().exchange(request, + String.class); + String resp = entity.getBody().toString(); + assertThat(resp).contains("status"); + assertThat(resp).contains("error"); + assertThat(resp).contains(IllegalStateException.class.getName()); + } + @Test public void testConventionTemplateMapping() throws Exception { load();