2

I'm building a Spring MVC service using Spring Boot and want to be able to return strings as plain text encoded in UTF-8. Following this description, I thought the only thing necessary should be to add the bean method

@Bean
public HttpMessageConverter<String> responseBodyConverter() {
    StringHttpMessageConverter converter = new StringHttpMessageConverter();
    converter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", Charset.forName("UTF-8"))));
    return converter;
}

But the root method in

@Controller
public class RootController {

    @RequestMapping(value="/"/*, produces="text/plain;charset=UTF-8"*/)
    @ResponseBody
    public String root() {
        return "æøå";
    }

}

responds the string æøå in ISO-8859-1 instead of UTF-8, unless I uncomment the produces part, in which case it actually returns UTF-8. The message converter doesn't seems to have any effect here.

Following this approach I confirm that the bean has actually been registered. Besides this bean, I also register an EmbeddedServletContainerFactory and CharacterEncodingFilter as described in another question, although I don't think that's relevant here.

Can someone explain what the registered HttpMessageConverter actually does, and how to make @ResponseBody-annotated controller methods return UTF-8 without having to provide produces every time?

Edit

As discussed in the comments, for the accepted answer to work, I had to upgrade the version of Spring Boot from 0.5.0.M6 to 0.5.0.BUILD-SNAPSHOT and, to prevent outputting a junk header, call converter.setWriteAcceptCharset(false) on the StringHttpMessageConverter.

Community
  • 1
  • 1
bisgardo
  • 4,130
  • 4
  • 29
  • 38

1 Answers1

1

The default character set for the StringHttpMessageConverteris ISO-8859-1. That means when a client does not request a specific character set, then ISO-8859-1 will be returned.

If you want UTF-8to be the default character set then you pass it into the constructor:

converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));

Calling setSupportedMediaTypes() is then no longer necessary either as text/plain; charset=default character set is added automatically.

a better oliver
  • 26,330
  • 2
  • 58
  • 66
  • I believe that is correct but it doesn't quite answer the question, since the code in the OP should also work. I think the answer the OP is looking for is "upgrade Spring Boot to m7 or a recent snapshot" (the feature in the docs he linked to is newish). – Dave Syer Jan 05 '14 at 18:10
  • 1
    @DaveSyer **"Can someone explain what the registered HttpMessageConverter actually does, and how to make @ ResponseBody-annotated controller methods return UTF-8 without having to provide produces every time"** - The answer completely covers that, don't you think? – a better oliver Jan 05 '14 at 18:30
  • Hm it seems that while it does add `charset=UTF-8` to `Content-Type`, the returned text is still actually ISO-8859-1. – bisgardo Jan 05 '14 at 19:21
  • @HalleKnast What values do the `Accept` and `Accept-Charset` headers of the request have? And how do you know its `ISO-8859-1`? Don't you get `æøå`? – a better oliver Jan 05 '14 at 19:48
  • I use Chrome. The network inspection panel gives the request headers `Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8`, no `Accept-Charset` header. I know because when I tell Chrome to change page encoding from `UTF-8` to `ISO-8859-1`, the page changes from `���` to `æøå`. – bisgardo Jan 05 '14 at 19:55
  • The `Content-Type` response header is `text/html;charset=UTF-8`. Also, it's the same in Firefox. – bisgardo Jan 05 '14 at 19:56
  • Ok, following @DaveSyer's suggestion, I upgraded `spring-boot-starter-parent` to version `0.5.0.BUILD-SNAPSHOT` and now it suddenly works. But it then adds a rather insane length response header `Accept-Charset:[many, many char sets - makes comment too long for SO]`. What's the point in that? – bisgardo Jan 05 '14 at 20:53
  • @HalleKnast You should be able to turn that off with `converter.setWriteAcceptCharset(false)`. I'm facing the problem that the converter actually does not replace the default one, like stated in the docs. Neither do I have the mentioned `HttpMessageConverters` class in my jars :( – a better oliver Jan 05 '14 at 21:30
  • Ok that works :) I guess that as last everything works as I want it to. But why in the world does it write that header by default?? – bisgardo Jan 05 '14 at 21:43
  • Can You post whole clean answer? How did You solve it? I see that comments above but cant understand it. – masterdany88 Dec 22 '14 at 17:04