Spring Controller #ResponseBody text/xml response UTF-8 encoding issue - spring

I have annotation based Spring Rest Service running on jetty web server(also tomcat).The controller code is :
#RequestMapping(method = RequestMethod.POST, value = { "/ssrfeed/exec/",
"/query/exec" }, consumes = { "application/xml", "text/xml",
"application/x-www-form-urlencoded" }, produces = {
"application/xml;charset=UTF-8", "text/xml;charset=UTF-8",
"application/x-www-form-urlencoded;charset=UTF-8" })
#ResponseBody
protected String getXmlFeed(HttpServletRequest request,
#PathVariable String serviceName, #RequestBody String xmlReq) {
//code....
return appXMLResponse;
}
The problem is that the response xml returned by Controller contains some characters like ä ö ü (Umlaute). The response when rendered on browser gives the parsing error :
XML Parsing Error: not well-formed
Location: //localhost:8083/MySerice/ssrfeed/exec/
Line Number 18111, Column 17:
<FIRST_NAME>Tzee rfista</FIRST_NAME>
----------------^
(a small triangle appear in place of ü)
The expected is : <FIRST_NAME>Tzeeürfista</FIRST_NAME>
I have tried a below solutions but issue is still there.
Tried using filters referring to solution given on technowobble
passed the charset to StringHttpMessageConverter property
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/xml;charset=UTF-8" />
</bean>
</list>
</property>
</bean>
ref link
Enabled the SetCharacterEncodingFilter in tomcat -web.xml
Changed the code to return ResponseEntity instead of String and removed #ResponseBody.
protected ResponseEntity<String> getXmlFeed(HttpServletRequest
request, #PathVariable String serviceName, #RequestBody String xmlReq) {
//line of code
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "application/xml; charset=utf-8");
return new ResponseEntity<String>(appXMLResponse, responseHeaders, HttpStatus.CREATED);
}
The 4th solution works But this being existing code I can't change method signature as it might impact existing clients of this service. Any ideas/pointers to solve this ?

in your dispatcher servlet context xml, you have to add a propertie. e.g.
<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<array>
<bean class = "org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
</bean>
</array>
</property>
</bean>

Finally the issue is resolved. Here is what I did.
1. Used StringHttpMessageConverter's constructer for setting charset as :
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg index="0" name="defaultCharset" value="UTF-8"/>
<property name="supportedMediaTypes">
<list>
<value>application/xml</value>
<value>text/xml</value>
<value>application/x-www-form-urlencoded</value>
</list>
</property>
</bean>
Also I removed the unnecessary spring3.0 and 3.1 jars from my project. These were not required but were lying there. (should have done earlier).
This solved the problem for me.

There is no such answer with what I've solved my encoding problem so I'll post it.
I've got Spring RestService running on Jetty. At response body part of data that was received from database had correct UTF-8 encoding, but data from .property file (with error and success messages) had incorrect encoding and was like äöü...
At first I checked encoding of .property file itself with File->Settings->Editor->Code Style-> File Encodings (in such way you could not only check but set encoding you need) - it was UTF-8.
Then I set response encoding #RequestMapping in my RestController:
#RequestMapping(value = "/category/{categoryId}", method = RequestMethod.DELETE, produces = { "application/json;**charset=UTF-8**" })
and set defaultCharset property for Jackson2:
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes" value="application/json;" />
<property name="prettyPrint" value="true" />
<property name="defaultCharset" value="UTF-8"/>
</bean>
No result.
But then I found that the problem could be solved by adding UTF-8 encoding to
PropertyPlaceholderConfigurer who grabs data from my .property file:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:app.properties</value>
<value>classpath:database.properties</value>
<value>classpath:ru.error.messages.properties</value>
<value>classpath:ru.success.messages.properties</value>
</list>
</property>
<property name="fileEncoding" value="UTF-8"/>
</bean>
... and the problem has gone )))

Related

Responsebody encoding in Spring MVC 4.3.3

To set #responsebody encoding in spring-webmvc, I used to add the following lines in configuration file:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
</mvc:message-converters>
This override the default charset responsebody handler use. And it worked with spring-mvc version 4.2.7 and below.
However, in the latest version of spring-webmvc(4.3.3), this method does not work. In the new version, StringHttpMessageConverter reads content-type from response header, and if content-type string includes charset information, it use this charset and ignores it's default charset.
I know I can write like this to solve this problem:
#RequestMapping(value = "/getDealers", method = RequestMethod.GET,
produces = "application/json; charset=utf-8")
#ResponseBody
public String sendMobileData() {
}
But I have to write it on every method or every controller.
Is there any way to set responsebody encoding globally like I did before?
I find that I didn't add <value>application/json;charset=UTF-8</value> in my configuration. I don't know why my old configuration works with version 4.2.7 and below, but this new configuration just works with version 4.3.3:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
</mvc:message-converters>

Reading in UTF-8 encoding in Java results in issues at only some places

I am reading a UTF_8 encoded file byte by byte in Java Spring Batch and saving the content in mongodb. The reading is delegated to FlatFileItemReader and the encoding is injected into the bean as UTF-8.
What I do see is that only at one or two specific places, the umlaut character is getting stored with an encoding problem in mongodb. I verified that the content in the original file is okay. What is interesting is that everywhere else, the umlaut character in the original file is interpreted correctly and stored correctly in mongodb.
Could you help with this?
<bean id="recordReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="resource" value="file:#{jobExecutionContext['inputfile']}" />
<property name="linesToSkip" value = "1" />
<property name= "encoding" value ="UTF-8"/>
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper" >
<property name = "lineTokenizer">
<bean class = "com.xyz.NoQuoteDelimitedLineTokenizer">
<property name = "strict" value = "false" />
<property name = "names" value = "Col1,Col2,Col3,Col4,Col5,Col6,Col7,Col8" />
<property name="delimiter">
<util:constant static-field="org.springframework.batch.item.file.transform.DelimitedLineTokenizer.DELIMITER_TAB" />
</property>
</bean>
</property>
<property name = "fieldSetMapper">
<bean class = "com.xyz.MyFieldSetMapper" >
<property name = "ctx" value="#{jobExecutionContext['contextBean']}"/>
</bean>
</property>
</bean>
</property>
</bean>
FieldSetMapper
private void validateFields (String id, ConsumerDO ci, FieldSet fieldset_p) throws Exception
{try {
ci.setCaption(fieldset_p.readString("newCaption"));
}
catch (Exception e) {
}
}

Spring MVC REST produces XML on default

I have a problem with Spring MVC and REST. The problem is that when i post a url without extension or whatever extension other then json or html or htm i am always getting an xml response. But i want it to default to text/html response. I was searching in many topics and cant find the answear to this.
Here is my Controller class :
#RequestMapping(value="/user/{username}", method=RequestMethod.GET)
public String showUserDetails(#PathVariable String username, Model model){
model.addAttribute(userManager.getUser(username));
return "userDetails";
}
#RequestMapping(value = "/user/{username}", method = RequestMethod.GET,
produces={"application/xml", "application/json"})
#ResponseStatus(HttpStatus.OK)
public #ResponseBody
User getUser(#PathVariable String username) {
return userManager.getUser(username);
}
Here is my mvc context config:
<mvc:resources mapping="/resources/**"
location="/resources/"/>
<context:component-scan
base-package="com.chodak.controller" />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="defaultContentType" value="text/html" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
</map>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.tiles3.TilesView
</value>
</property>
</bean>
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles.xml</value>
</list>
</property>
</bean>
Actually when I tried the built in Eclipse browser it works fine, but when I use firefox or chrome it shows xml response on a request with no extension. I tried using ignoreAcceptHeader, but no change.
Also works on IE :/
If anyone has an idea please help, Thank you.
I actually found out how to do it, i dont really understand why but it is working now, I added default views to the contentresolver like :
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
</bean>
<!-- JAXB XML View -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.chodak.tx.model.User</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
</list>
</property>
and removed the getUser method, the one annoted to produce xml and json. If I leave it with the added default views its still not working. If anyone can explain why it would be awesome :)
You can do
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
// #EnableWebMvc already autoconfigured by Spring Boot
public class MvcConfiguration {
#Bean
public WebMvcConfigurer contentNegotiationConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false)
.favorParameter(true)
.parameterName("mediaType")
.ignoreAcceptHeader(true)
.useJaf(false)
.defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML)
.mediaType("json", MediaType.APPLICATION_JSON);
// this line alone gave me xhtml for some reason
// configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8);
}
};
}
(tried with Spring Boot 1.5.x)
see https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc
"What we did, in both cases:
Disabled path extension. Note that favor does not mean use one approach in preference to another, it just enables or disables it. The order of checking is always path extension, parameter, Accept header.
Enable the use of the URL parameter but instead of using the default parameter, format, we will use mediaType instead.
Ignore the Accept header completely. This is often the best approach if most of your clients are actually web-browsers (typically making REST calls via AJAX).
Don't use the JAF, instead specify the media type mappings manually - we only wish to support JSON and XML."

How do you force a response for a RequestMapping to use the AtomFeedHttpMessageConverter?

Our Spring 3.1 application uses message converters in the following manner:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
....
....
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="writeAcceptCharset" value="false"/>
</bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
<bean class="org.springframework.http.converter.feed.AtomFeedHttpMessageConverter"/>
</list>
</property>
</bean>
<bean class="org.codehaus.jackson.map.ObjectMapper" name="objectMapper"/>
In one of my controllers, I have a RequestMapping as such:
#RequestMapping(value = "pathFoo", produces = MediaType.APPLICATION_ATOM_XML_VALUE)
public #ResponseBody Feed getFooAtomXML(HttpServletRequest request, HttpServletResponse response){
but it seems that unless I specify a request header Accept=application/atom+xml, the response comes back as JSON instead of XML. How can I configure the application so that the AtomFeedHttpMessageConverter is used at this mapping, regardless of whether the request header is present?
Would I need to rely on a ViewResolver?
The problem here is that the AnnotationMethodHandlerAdapter bean goes through your list of HttpMessageConverter beans in declared order.
It first calls the canWrite(Class, MediaType) method on each HttpMessageConverter and uses the first one that returns true.
Without providing the Accept header as application/atom+xml, the MappingJacksonHttpMessageConverter will return true first before the AtomFeedHttpMessageConverter has a chance to. This happens for two reasons.
If no Accept header is provided, Spring considers all MediaTypes as acceptable.
MappingJacksonHttpMessageConverter accepts the application/json content-type
This is because MappingJacksonHttpMessageConverter is implemented as
#Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return (this.objectMapper.canSerialize(clazz) && canWrite(mediaType));
// ^ will pretty much always return true ^ application/json
}
So since the acceptable media types include everything, the MappingJacksonHttpMessageConverter will be able to produce a response and Spring will choose it.
To change this either change the order of beans
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="writeAcceptCharset" value="false"/>
</bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean class="org.springframework.http.converter.feed.AtomFeedHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</list>
</property>
Or provide an Accept header as the HTTP specification specifies.
Or move to Spring 3.2 which uses RequestMappingHandlerAdapter instead of AnnotationMethodHandlerAdapter (which is deprecated), but also registers the AtomFeedHttpMessageConverter before the MappingJacksonHttpMessageConverter by default.

Spring 3.2 with MVC, ContentNegotation, REST and PDF Generator

Let's say, I have a REST styled controller mapping
#RequestMapping(value="users", produces = {MediaType.APPLICATION_JSON_VALUE})
public List<User> listUsers(#ReqestParams Integer offset, #ReqestParams Integer limit, #ReqestParams String query) {
return service.loadUsers(query, offset, limit);
}
Serving JSON (or even XML) is not an issue, this is easy using ContentNegotation and MessageConverters
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true" />
<property name="favorParameter" value="false" />
<property name="ignoreAcceptHeader" value="false" />
<property name="mediaTypes" >
<value>
html=text/html
json=application/json
xml=application/xml
</value>
</property>
</bean>
Now, I need to add support for PDF. Naturally, I want to use (Spring) MVC + REST as much as possible. Most examples I have found implement this with an explicit definition not using REST style, e.g.
#RequestMapping(value="users", produces = {"application/pdf"})
public ModelAndView listUsersAsPdf(#ReqestParams Integer offset, #ReqestParams Integer limit, #ReqestParams String query) {
List<User> users = listUsers(offset, limit, query); // delegated
return new ModelAndView("pdfView", users);
}
That works, but is not very comfortable because for every alternate output (PDF, Excel, ...) I would add a request mapping.
I have already added application/pdf to the content negotation resolver; unfortunately any request with a suffix .pdf or the Accept-Header application/pdf were be responded with 406.
What is the ideal setup for a REST/MVC style pattern to integrate alternate output like PDF?
You can create a WEB-INF/spring/pdf-beans.xml like below.
<bean id="listofusers" class="YourPDFBasedView"/>
And your controller method will return view name as listofusers.
#RequestMapping(value="users")
public ModelAndView listUsersAsPdf(#ReqestParams Integer offset, #ReqestParams Integer limit, #ReqestParams String query) {
List<User> users = listUsers(offset, limit, query); // delegated
return new ModelAndView("listofusers", users);
}
And you can use contentNegotiationViewResolver in this way:
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="order" value="1"/>
<property name="location" value="WEB-INF/spring/pdf-views.xml"/>
</bean>
<!--
View resolver that delegates to other view resolvers based on the content type
-->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<!-- All configuration is now done by the manager - since Spring V3.2 -->
<property name="contentNegotiationManager" ref="cnManager"/>
</bean>
<!--
Setup a simple strategy:
1. Only path extension is taken into account, Accept headers are ignored.
2. Return HTML by default when not sure.
-->
<bean id="cnManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="ignoreAcceptHeader" value="true"/>
<property name="defaultContentType" value="text/html" />
</bean>
For JSON: Create a generic JSON view resolver like below and register it as bean in context file.
public class JsonViewResolver implements ViewResolver {
/**
* Get the view to use.
*
* #return Always returns an instance of {#link MappingJacksonJsonView}.
*/
#Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
MappingJacksonJsonView view = new MappingJacksonJsonView();
view.setPrettyPrint(true); // Lay the JSON out to be nicely readable
return view;
}
}
Same for XML:
public class MarshallingXmlViewResolver implements ViewResolver {
private Marshaller marshaller;
#Autowired
public MarshallingXmlViewResolver(Marshaller marshaller) {
this.marshaller = marshaller;
}
/**
* Get the view to use.
*
* #return Always returns an instance of {#link MappingJacksonJsonView}.
*/
#Override
public View resolveViewName(String viewName, Locale locale)
throws Exception {
MarshallingView view = new MarshallingView();
view.setMarshaller(marshaller);
return view;
}
}
and register above xml view resolver in context file like this:
<oxm:jaxb2-marshaller id="marshaller" >
<oxm:class-to-be-bound name="some.package.Account"/>
<oxm:class-to-be-bound name="some.package.Customer"/>
<oxm:class-to-be-bound name="some.package.Transaction"/>
</oxm:jaxb2-marshaller>
<!-- View resolver that returns an XML Marshalling view. -->
<bean class="some.package.MarshallingXmlViewResolver" >
<constructor-arg ref="marshaller"/>
</bean>
You can find more information at this link:
http://spring.io/blog/2013/06/03/content-negotiation-using-views/
Using all view resolver techniques, you can avoid writing duplicate methods in controller, such as one for xml/json, other for excel, other for pdf, another for doc, rss and all.
Knalli, if you replace #ResponseBody with ModelAndView(), you can achieve both the features.
Is there any reason you want to keep #ResponseBody ? I just want to know if I am missing anything, just want to learn.
Other option is to write HttpMessageConverters then:
Some samples are here.
Custom HttpMessageConverter with #ResponseBody to do Json things
http://www.javacodegeeks.com/2013/07/spring-mvc-requestbody-and-responsebody-demystified.html
This is working sample. I have configured contentnegotiationviewresolver for this, and give highest order. After that I have ResourceBundleViewResolver for JSTL and Tiles View, then XmlViewResolver for excelResolver, pdfResolver, rtfResolver. excelResolver, pdfResolver, rtfResolver. XmlViewResolver and ResourceBundleViewResolver works only with MAV only, but MappingJacksonJsonView and MarshallingView takes care for both MAV and #ResponseBody return value.
<bean id="contentNegotiatingResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order"
value="#{T(org.springframework.core.Ordered).HIGHEST_PRECEDENCE}" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
<entry key="pdf" value="application/pdf" />
<entry key="xlsx" value="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
<entry key="doc" value="application/msword" />
</map>
</property>
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
<!-- XML View -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>Employee</value>
<value>EmployeeList</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"
id="resourceBundleResolver">
<property name="order" value="#{contentNegotiatingResolver.order+1}" />
</bean>
<bean id="excelResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location">
<value>/WEB-INF/tiles/spring-excel-views.xml</value>
</property>
<property name="order" value="#{resourceBundleResolver.order+1}" />
</bean>
<bean id="pdfResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location">
<value>/WEB-INF/tiles/spring-pdf-views.xml</value>
</property>
<property name="order" value="#{excelResolver.order+1}" />
</bean>
<bean id="rtfResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location">
<value>/WEB-INF/tiles/spring-rtf-views.xml</value>
</property>
<property name="order" value="#{excelResolver.order+1}" />
</bean>
And our XMLViewResolver spring-pdf-views.xml looks like this.
<bean id="employees"
class="EmployeePDFView"/>
And EmployeePDFView will have code for generating pdf and writing pdf byte stream on Response object. This will resolve to rest url that will end with .pdf extension, and when you return MAV with "employees" id.

Resources