question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add the ability to specify the charset UTF-8 in AdviceTrait

See original GitHub issue

Not sure I got the issue title right! Feel free to change it!

My problem was that my french error messages assertions were failing because the UTF-8 encoding was not specified in the response content type. Here’s a piece of my unit test:

...
final FooDto dto = new FooDto();
dto.setCode(ALPHANUMERIC_GENERATOR.generate(11));
mockMvc
    .perform(
        put("/api/foo/{id}", 1)
            .header("accept-language", "fr")
            .contentType(MediaType.APPLICATION_JSON)
            .content(toJsonBytes(dto)))
    // Verify that the response status is BAD_REQUEST (400).
    .andExpect(status().isBadRequest())
    // Verify that the response content type is compatible with application/problem+json
    .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_PROBLEM_JSON))
    // Verify the content, which is supposed to be the validation errors.
    .andExpect(jsonPath("$.status").value(HttpStatus.BAD_REQUEST.value()))
    .andExpect(jsonPath("$.title").value("Constraint Violation"))
    .andExpect(jsonPath("$.violations", hasSize(1)))
    .andExpect(jsonPath("$.violations[0].field", equalTo("code")))
    .andExpect(jsonPath("$.violations[0].message", equalTo("La longueur maximal du code est de 10 caractères")));
...

This test was failing with the following error message:

Expected: “La longueur maximal du code est de 30 caractères” but: was “La longueur maximal du code est de 30 caractères”

In order to get this to work, I had to override AdviceTrait#negociate in my ControllerAdvice annotated class (witch implements ProblemHandling) as followed:

@Override
public Optional<MediaType> negotiate(final NativeWebRequest request) {

  final Optional<MediaType> mediaType = ProblemHandling.super.negotiate(request);
  return mediaType
      .filter(PROBLEM::equals)
      .map(type -> Optional.of(MediaType.APPLICATION_PROBLEM_JSON_UTF8))
      .orElse(mediaType);
}

By the way, I use Spring Boot 2.0.0.M7 and so far this is the only issue I got. So I think that #121 won’t be a hard one.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:9

github_iconTop GitHub Comments

1reaction
whiskeysierracommented, Jan 22, 2018

I think spring.http.encoding.force=true is a good enough workaround for tests. As far as I can tell, it works in production, and that’s my main priority. I’m closing this for now. Feel free to challenge and re-open.

1reaction
sbraconniercommented, Jan 18, 2018

If it can help, I did some digging into this problem and found the source of it.

When we perform a request using MockMvc, a MockHttpServletResponse is created, with a charsetEncoding initialized to: private String characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING; which is public static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";

Then, when the content of the request is get, this default encoding is used, causing the assertion failure:

public String getContentAsString() throws UnsupportedEncodingException {
	flushBuffer();
	return (this.characterEncoding != null ?
			this.content.toString(this.characterEncoding) : this.content.toString());
}

Now, here is the setContentType implementation of MockHttpServletResponse:

@Override
public void setContentType(String contentType) {
	this.contentType = contentType;
	if (contentType != null) {
		try {
			MediaType mediaType = MediaType.parseMediaType(contentType);
			if (mediaType.getCharset() != null) {
				this.characterEncoding = mediaType.getCharset().name();
				this.charset = true;
			}
		}
		catch (Exception ex) {
			// Try to get charset value anyway
			int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX);
			if (charsetIndex != -1) {
				this.characterEncoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length());
				this.charset = true;
			}
		}
		updateContentTypeHeader();
	}
}

Since the charset is not provided in the content type when using application/problem+json only, ISO-8859-1 is always used. This is why the failure goes away once we use application/problem+json;charset=UTF-8 instead.

That being said, I’m not sure what would be the best way to fix this…

Read more comments on GitHub >

github_iconTop Results From Across the Web

MockMvc no longer handles UTF-8 characters with Spring ...
Yes. This is problem from 2.2.0 spring-boot. They set deprecation for default charset encoding. .getContentAsString(StandardCharsets.
Read more >
Declaring character encodings in HTML - W3C
Always declare the encoding of your document using a meta element with a charset attribute, or using the http-equiv and content attributes ( ......
Read more >
Use charset `utf-8` | webhint documentation
The character encoding should be specified for every HTML page, either by using the charset parameter on the Content-Type HTTP response header (e.g.:...
Read more >
SI77512 - OSP-IWS REST SERVICES SHOULD SET ... - IBM
OSP-IWS REST SERVICES SHOULD SET CHARSET=UTF-8 FOR JSON, XML. ... SI63374 OSP-IWS Add ability to control wrapper element identifier
Read more >
How can I fix the UTF-8 error when bulk uploading users?
In Notepad, click Save As. Enter a filename and change Encoding to "UTF-8". Add .csv at the end of the file name to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found