How to overwrite StringHttpMessageConverter DEFAULT_CHARSET to use UTF8 in spring 4
Solution 1
Your Network tab seems to be showing
text/html;charset=UTF-8
which isn't what you configured it to be
converter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", Charset.forName("UTF-8"))));
It seems your custom HttpMessageConverter
bean isn't getting registered. Add this to your WebAppConfig
class
@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
converters.add(responseBodyConverter());
}
You should see your response contain
Content-Type:"text/plain;charset=UTF-8"
I can't explain why your browser's network tab would show UTF-8
but wouldn't be able to parse or render it properly. It works fine for me.
Solution 2
The problem is that StringHttpMessageConverter
defaults to ISO-8859-1. You need either set the default to UTF-8 as shown here:
@Bean
public HttpMessageConverter<String> responseBodyConverter() {
StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
converter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", Charset.forName("UTF-8"))));
return converter;
}
Or get the client to specify exactly what they want with the Accept
header, ie: Accept: text/plain;charset="UTF-8"
.
Solution 3
The problem as others have stated is that StringHttpMessageConverter
defaults to ISO-8859-1.
I just replaced the default charset of existing StringHttpMessageConverter to UTF-8
@Configuration
@EnableWebMvc
public class SampleWebConfiguration implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.stream()
.filter(converter -> converter instanceof StringHttpMessageConverter)
.forEach(converter -> ((StringHttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8));
}
}
masterdany88
Full-stack Java/Gwt Web Developer. Interested in software quality and software architecture. Always looking for new opportunities to learn something new and usefull. Main career goal: Software Architect position. Methodologies: Clean Code Design Patterns Java EE Architecture Agile JAVA: Design and implementation of Java EE based applications, using: PlayFramework2, Spring, GWT, JPA/ Hibernate, REST, SBT, Maven, Ant. WEB: Bootstrap, HTML5, JQuery. DB: MSSQL, MySql, H2DB. LINUX
Updated on July 21, 2022Comments
-
masterdany88 almost 2 years
I am trying to make spring @ResponseBody return always utf-8. But I can't do it for so long. Problem comes when I am returning simple text answer:
@RequestMapping(value="/test", method=RequestMethod.PUT) @ResponseBody public String ajaxTest() { return "Characters test: ęółąśżźćń"; }
Each polish chars (ęółąśżźćń) goes to
?
And in web page I am getting this string:
Characters test: ?�???????
instead ofCharacters test: ęółąśżźćń
I don't know what I am missing.
I've added custome bean to
public class WebAppConfig extends WebMvcConfigurerAdapter {}
Which goes as follows:@Bean public HttpMessageConverter<String> responseBodyConverter() { StringHttpMessageConverter converter = new StringHttpMessageConverter(); converter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", Charset.forName("UTF-8")))); return converter; }
Instruction taken from https://jira.spring.io/browse/SPR-9099
But it doesn't work. I can see in firefox and chrome that returned value is in utf-8:
Spring version: 4.1.1.RELEASE
Web app config class:
package com.derp.common.init; import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; import java.util.Properties; import javax.annotation.Resource; import javax.sql.DataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.hibernate4.HibernateTransactionManager; import org.springframework.orm.hibernate4.LocalSessionFactoryBean; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; //import com.derp.common.wicketView.HomePage; @Configuration @ComponentScan("com.derp") @EnableWebMvc @EnableTransactionManagement @PropertySource("classpath:application.properties") public class WebAppConfig extends WebMvcConfigurerAdapter { private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver"; private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password"; private static final String PROPERTY_NAME_DATABASE_URL = "db.url"; private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username"; private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect"; private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql"; private static final String PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO = "hibernate.hbm2ddl.auto"; private static final String PROPERTY_NAME_HIBERNATE_CONNECTION_CHARSET = "hibernate.connection.CharSet"; private static final String PROPERTY_NAME_HIBERNATE_CONNECTION_CHARACTERENCODING = "hibernate.connection.characterEncoding"; private static final String PROPERTY_NAME_HIBERNATE_CONNECTION_USEUNICODE = "hibernate.connection.useUnicode"; private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_SERVICES = "services.entitymanager.packages.to.scan"; private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_COMMON = "common.entitymanager.packages.to.scan"; private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_CMS = "cms.entitymanager.packages.to.scan"; private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_PROCEDURE = "procedure.entitymanager.packages.to.scan"; @Resource private Environment env; @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER)); dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL)); dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME)); dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD)); return dataSource; } @Bean public LocalSessionFactoryBean sessionFactory() { LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource()); //sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN)); sessionFactoryBean.setPackagesToScan(new String[] { env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_SERVICES), env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_COMMON), env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_CMS), env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN_PROCEDURE) }); sessionFactoryBean.setHibernateProperties(hibProperties()); return sessionFactoryBean; } private Properties hibProperties() { Properties properties = new Properties(); properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT)); properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL)); properties.put(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO)); properties.put(PROPERTY_NAME_HIBERNATE_CONNECTION_CHARSET, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_CONNECTION_CHARSET)); properties.put(PROPERTY_NAME_HIBERNATE_CONNECTION_CHARACTERENCODING, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_CONNECTION_CHARACTERENCODING)); properties.put(PROPERTY_NAME_HIBERNATE_CONNECTION_USEUNICODE, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_CONNECTION_USEUNICODE)); properties.put("jadira.usertype.autoRegisterUserTypes", "true"); return properties; } @Bean public HibernateTransactionManager transactionManager() { HibernateTransactionManager transactionManager = new HibernateTransactionManager(); transactionManager.setSessionFactory(sessionFactory().getObject()); return transactionManager; } @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { // Simple strategy: only path extension is taken into account configurer.favorPathExtension(true). ignoreAcceptHeader(true). useJaf(false). defaultContentType(MediaType.TEXT_HTML). mediaType("html", MediaType.TEXT_HTML). mediaType("xml", MediaType.APPLICATION_XML). mediaType("json", MediaType.APPLICATION_JSON); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/img/**").addResourceLocations("/WEB-INF/img/*"); registry.addResourceHandler("/css/**").addResourceLocations("/WEB-INF/css/*"); registry.addResourceHandler("/js/**").addResourceLocations("/WEB-INF/js/*"); registry.addResourceHandler("/lib/**").addResourceLocations("/WEB-INF/lib/*"); } @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { super.configureMessageConverters(converters); converters.add(responseBodyConverter()); } @Bean public HttpMessageConverter<String> responseBodyConverter() { StringHttpMessageConverter converter = new StringHttpMessageConverter(); converter.setSupportedMediaTypes(Arrays.asList(new MediaType("text", "plain", Charset.forName("UTF-8")))); return converter; } }
Application initializer:
package com.derp.common.init; import java.nio.charset.Charset; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration.Dynamic; import org.springframework.http.MediaType; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.filter.HiddenHttpMethodFilter; import org.springframework.web.servlet.DispatcherServlet; public class Initializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(WebAppConfig.class); ctx.register(ThymeleafConfig.class); servletContext.addListener(new ContextLoaderListener(ctx)); ctx.setServletContext(servletContext); Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx)); servlet.addMapping("/"); servlet.setAsyncSupported(true); servlet.setLoadOnStartup(1); // Allow to use Put and Delete method for REST architecture registerCharachterEncodingFilter(servletContext); registerHiddenFieldFilter(servletContext); } private void registerCharachterEncodingFilter(ServletContext aContext) { CharacterEncodingFilter cef = new CharacterEncodingFilter(); cef.setForceEncoding(true); cef.setEncoding("UTF-8"); aContext.addFilter("charachterEncodingFilter", cef).addMappingForUrlPatterns(null ,true, "/*"); } private void registerHiddenFieldFilter(ServletContext aContext) { aContext.addFilter("hiddenHttpMethodFilter", new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*"); } }
Java script/Jquery ajax call
$('h1').click(function() { $.ajax({ type: "PUT", url: "/derp/procedury/test", data: "none", success: function (response, status, xhr) { showNotifications(status, xhr.responseText); }, error: function (response, status, xhr) { showNotifications('error', JSON.stringify(response)); showNotifications('error', status); showNotifications('error', xhr); } }); });
Please help.