From 1d363e5a417fa6c1a956b381f7ffc00ee59f6b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Thu, 13 Jun 2024 16:02:28 +0200 Subject: [PATCH] Use UTF-8 with JSON in MockHttpServletResponse This commit makes MockHttpServletResponse consistent with the other parts of the framework where the body of a response is read as an UTF-8 String when the content type is application/json or similar, overriding the ISO-8859-1 default Servlet encoding. Closes gh-33019 --- .../mock/web/MockHttpServletResponse.java | 7 +++++++ .../test/web/servlet/result/ContentResultMatchers.java | 4 ++-- .../test/web/servlet/result/JsonPathResultMatchers.java | 3 +-- .../test/web/servlet/result/PrintingResultHandler.java | 8 ++------ .../mock/web/MockHttpServletResponseTests.java | 9 +++++++++ 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java index 1f9f77b2f18..d50d991c2fa 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java @@ -24,6 +24,7 @@ import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -72,6 +73,8 @@ public class MockHttpServletResponse implements HttpServletResponse { private static final TimeZone GMT = TimeZone.getTimeZone("GMT"); + private static final MediaType APPLICATION_PLUS_JSON = new MediaType("application", "*+json"); + //--------------------------------------------------------------------- // ServletResponse properties @@ -348,6 +351,10 @@ public class MockHttpServletResponse implements HttpServletResponse { if (mediaType.getCharset() != null) { setExplicitCharacterEncoding(mediaType.getCharset().name()); } + else if (mediaType.isCompatibleWith(MediaType.APPLICATION_JSON) || + mediaType.isCompatibleWith(APPLICATION_PLUS_JSON)) { + this.characterEncoding = StandardCharsets.UTF_8.name(); + } } catch (Exception ex) { // Try to get charset value anyway diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/ContentResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/ContentResultMatchers.java index 1dc4cf89848..fa3c9dcf763 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/ContentResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/ContentResultMatchers.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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. @@ -257,7 +257,7 @@ public class ContentResultMatchers { */ public ResultMatcher json(String jsonContent, JsonComparator comparator) { return result -> { - String content = result.getResponse().getContentAsString(StandardCharsets.UTF_8); + String content = result.getResponse().getContentAsString(); comparator.assertIsMatch(jsonContent, content); }; } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java index e84db5471df..01e722fffd8 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java @@ -17,7 +17,6 @@ package org.springframework.test.web.servlet.result; import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; import com.jayway.jsonpath.JsonPath; import org.hamcrest.Matcher; @@ -238,7 +237,7 @@ public class JsonPathResultMatchers { } private String getContent(MvcResult result) throws UnsupportedEncodingException { - String content = result.getResponse().getContentAsString(StandardCharsets.UTF_8); + String content = result.getResponse().getContentAsString(); if (StringUtils.hasLength(this.prefix)) { try { String reason = String.format("Expected a JSON payload prefixed with \"%s\" but found: %s", diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/PrintingResultHandler.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/PrintingResultHandler.java index bccce330561..50baf1cd963 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/PrintingResultHandler.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/PrintingResultHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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. @@ -16,7 +16,6 @@ package org.springframework.test.web.servlet.result; -import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Enumeration; import java.util.Map; @@ -28,7 +27,6 @@ import jakarta.servlet.http.HttpSession; import org.springframework.core.style.ToStringCreator; import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; import org.springframework.lang.Nullable; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -250,9 +248,7 @@ public class PrintingResultHandler implements ResultHandler { this.printer.printValue("Error message", response.getErrorMessage()); this.printer.printValue("Headers", getResponseHeaders(response)); this.printer.printValue("Content type", response.getContentType()); - String body = (MediaType.APPLICATION_JSON_VALUE.equals(response.getContentType()) ? - response.getContentAsString(StandardCharsets.UTF_8) : response.getContentAsString()); - this.printer.printValue("Body", body); + this.printer.printValue("Body", response.getContentAsString()); this.printer.printValue("Forwarded URL", response.getForwardedUrl()); this.printer.printValue("Redirected URL", response.getRedirectedUrl()); printCookies(response.getCookies()); diff --git a/spring-test/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java b/spring-test/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java index 0bc9975a7c0..7c066fef0bd 100644 --- a/spring-test/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java +++ b/spring-test/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java @@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.http.MediaType; import org.springframework.web.util.WebUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -620,4 +621,12 @@ class MockHttpServletResponseTests { assertThat(contentTypeHeader).isEqualTo("text/plain"); } + @Test // gh-33019 + void contentAsStringEncodingWithJson() throws IOException { + String content = "{\"name\": \"Jürgen\"}"; + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.getWriter().write(content); + assertThat(response.getContentAsString()).isEqualTo(content); + } + }