springMVC3.0 response body encoding issue - spring-mvc

the default charset of #ResponseBody is iso-8859-1,
how to change to utf8?
configuration below does't seem to work.
<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name = "messageConverters">
<list>
<bean class = "org.springframework.http.converter.StringHttpMessageConverter">
<property name = "supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>

You can add produces = "text/plain;charset=UTF-8" to request mapping
#RequestMapping(value = "/rest/create/document", produces = "text/plain;charset=UTF-8")
#ResponseBody
public void create(Document document, HttpServletRespone respone) throws UnsupportedEncodingException {
Document newDocument = DocumentService.create(Document);
return jsonSerializer.serialize(newDocument);
}

If you are using tomcat you also need to specifying URIEncoding="UTF-8" on <Connector> in the Tomcat server.xml config, as described here:
http://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q8

Related

org.hibernate.validator.constraints not picking reloaded messages

I am trying to use Spring's ReloadableResourceBundleMessageSource for LocalValidatorFactoryBean so that when I update an error message it should reflect without requiring the server to be restarted. I am using Spring 4.1.4, hibernate-validator 4.3.2.Final.
Below are the code details -
context.xml -
<mvc:annotation-driven validator="validator" />
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>file:../conf/fileapplication</value> <!-- Messages here will override the below properties file-->
<value>/WEB-INF/application</value>
</list>
</property>
<property name="cacheSeconds" value="10"></property> <!-- Will check for refresh every 10 seconds -->
</bean>
<bean name="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource">
<ref bean="messageSource"/>
</property>
</bean>
Model -
import org.hibernate.validator.constraints.NotBlank;
public class InputForm {
#NotBlank ( message = "{required.string.blank}")
String requiredString;
Controller -
#RequestMapping(value = "/check/string", method = RequestMethod.POST)
public String checkString(
#ModelAttribute("formModel") #Valid InputForm inputForm ,
BindingResult result, Model model, HttpServletResponse response,
HttpServletRequest request) {
if (result.hasErrors()) {
model.addAttribute("formModel", inputForm);
return "userInput";
}
// Do some backend validation with String
result.reject("string.not.valid",
"String is Invalid");
model.addAttribute("formModel", inputForm);
return "userInput";
}
application.properties (in /WEB_INF/ folder)
required.string.blank=Please enter the required string.
string.not.valid=Please enter a valid string.
fileapplication.properties (in /conf/ folder. Will override above file)
required.string.blank=You did not enter the required string. #Does not reflect when I change here
string.not.valid=You did not enter a valid string. #Reflects when I change here
Now the problem I am facing is, when I update "string.not.valid" in fileapplication.properties it reflects at runtime and I see the updated message. But when I update "required.string.blank" in fileapplication.properties it does not reflect at runtime.
Note that the overriding part is working fine for both messages upon application start up. But the "reloading" part is not working fine for "required.string.blank".
This is what I figured out based on my research - We need to create our own MessageInterpolator and add it as dependency to the validator instead of message source. Because when we add a messageSource as dependency, it is cached by default by the validator and any message reloads spring does won't take effect in the validator's cached instance of messageSource.
Below are the details:
In context.xml, add the custom MessageInterpolator as dependency to LocalValidatorFactoryBean instead of messageSource:
<mvc:annotation-driven validator="validator" />
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>file:../conf/fileapplication</value> <!-- Messages here will override the below properties file-->
<value>/WEB-INF/application</value>
</list>
</property>
<property name="cacheSeconds" value="10"></property> <!-- Will check for refresh every 10 seconds -->
</bean>
<bean name="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="messageInterpolator">
<ref bean="messageInterpolator"/>
</property>
</bean>
<bean name="messageInterpolator"
class="com.my.org.support.MyCustomResourceBundleMessageInterpolator">
<constructor-arg ref="messageSource" />
</bean>
Create your custom MessageInterpolator by extending Hibernate's org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.
public class MyCustomResourceBundleMessageInterpolator extends
ResourceBundleMessageInterpolator {
public MyCustomResourceBundleMessageInterpolator(MessageSource messageSource)
{
// Passing false for the second argument
// in the super() constructor avoids the messages being cached.
super(new MessageSourceResourceBundleLocator(messageSource), false);
}
}
Model, Controller and properties file can be same as in the question.

Spring RestTemplate failure with upper case element names

I have a simple Spring MVC application that makes an Ajax call to a ReST service using the RestTemplate class. Some of the elements in the schema start with uppercase letters. The 2 elements (code, message) with lowercase letters cause no problems. The classes generated by JAXB have the #XmlElement annotation and name property. This seems to be ignored. I've read that the JaxbAnnotationIntrospector needs to be used but none of the changes make that take effect. See class below. I've tried adding a bean class definition for RestTemplate in the Spring config, adding an object mapper but nothing helps. See error on OTPRO element in first few lines of stack trace:
[4/18/16 9:52:43:988 EDT] 00000024 SystemErr R org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unrecognized field "OTPRO" (class com.ssdr.rest.message.SSDRResponse), not marked as ignorable (7 known properties: "dt", "ot", "message", "otpro", "otphone", "code", "dtphone"])
at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream#4ccbe679; line: 4, column: 14] (through reference chain: com.ssdr.rest.message.SSDRResponse["OTPRO"]); nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "OTPRO" (class com.ssdr.rest.message.SSDRResponse), not marked as ignorable (7 known properties: "dt", "ot", "message", "otpro", "otphone", "code", "dtphone"])
at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream#4ccbe679; line: 4, column: 14] (through reference chain: com.ssdr.rest.message.SSDRResponse["OTPRO"])
[4/18/16 9:52:44:019 EDT] 00000024 SystemErr R at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readInternal(MappingJackson2HttpMessageConverter.java:126)
[4/18/16 9:52:44:019 EDT] 00000024 SystemErr R at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153)
[4/18/16 9:52:44:019 EDT] 00000024 SystemErr R at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:81)
JAXB generated class:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for documentResponse complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="documentResponse">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="code" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="message" type="{http://www.w3.org/2001/XMLSchema}string"/>
* <element name="OTPRO" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="OT" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="OTPhone" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="DT" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="DTPhone" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "documentResponse", propOrder = {
"code",
"message",
"otpro",
"ot",
"otPhone",
"dt",
"dtPhone"
})
public class DocumentResponse {
#XmlElement(required = true)
protected String code;
#XmlElement(required = true)
protected String message;
#XmlElement(name = "OTPRO", nillable = true)
protected String otpro;
#XmlElement(name = "OT", nillable = true)
protected String ot;
#XmlElement(name = "OTPhone", nillable = true)
protected String otPhone;
#XmlElement(name = "DT", nillable = true)
protected String dt;
#XmlElement(name = "DTPhone", nillable = true)
protected String dtPhone;
...
Service class:
SSDRResponse resp = null;
RestTemplate restTemplate = new RestTemplate();
HttpEntity<SSDRRequest> httpRequest = new HttpEntity<SSDRRequest>(req, createHeaders());
resp = restTemplate.postForObject(SERVICE_URI, httpRequest, SSDRResponse.class);
Spring config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<context:annotation-config />
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<context:component-scan base-package="com.ssdr" />
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
<!-- Forwards requests to the "/" resource to the "index" view -->
<!--
<mvc:view-controller path="/" view-name="index" />
-->
<!-- Make webapp/resources directory accessible to web app -->
<mvc:resources location="/resources/" mapping="/resources/**" />
<!-- Resolves view names to protected .jsp resources within the context root directory -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="annotationIntrospector">
<bean
class="com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector" />
</property>
</bean>
</property>
</bean>
</list>
</property>
</bean>
<!-- <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="html" value="text/html"/>
<entry key="json" value="application/json"/>
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="prefixJson" value="true"/>
</bean>
</list>
</property>
</bean> -->
</beans>
NOTE: I do not want to simply ignore the upper case elements.
The solution was to use a combination of JacksonAnnotationIntrospector and JaxbAnnotationIntrospector. In this case Jackson was needed to recognize the #JsonIgnoreProperties and #JsonInclude annotations in the request. But Jackson always threw the "Unrecognized field" errors. JAXB could read the response with the uppercase fields but would not recognize the annotations on the request.
To use both introspectors the following code was added to the service class:
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
MappingJackson2HttpMessageConverter jaxMsgConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objMapper = new ObjectMapper();
/*
* Jackson introspector needed for #JsonIgnoreProperties and #JsonInclude annotations
* JAXB introspector is needed to handle the uppercase element names in the response
*/
AnnotationIntrospector primary = new JacksonAnnotationIntrospector();
AnnotationIntrospector secondary = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
AnnotationIntrospector pair = AnnotationIntrospector.pair(primary, secondary);
objMapper.setAnnotationIntrospector(pair);
jaxMsgConverter.setObjectMapper(objMapper);
messageConverters.add(jaxMsgConverter);
SSDRResponse resp = null;
RestTemplate restTemplate = new RestTemplate();
// Set message converter with Jackson and JAXB introspectors in RestTemplate
restTemplate.setMessageConverters(messageConverters);
HttpEntity<SSDRRequest> httpRequest = new HttpEntity<SSDRRequest>(req, createHeaders());
resp = restTemplate.postForObject(SERVICE_URI, httpRequest, SSDRResponse.class);
To use only the JAXB introspector:
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
MappingJackson2HttpMessageConverter jaxMsgConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper jaxMapper = new ObjectMapper();
AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
jaxMapper.setAnnotationIntrospector(introspector);
jaxMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // ignore unknown properties
jaxMsgConverter.setObjectMapper(jaxMapper);
messageConverters.add(jaxMsgConverter);
My spring boot configuration (ready to use):
#Configuration
#EnableWebMvc
#EnableAutoConfiguration
#ComponentScan(basePackages = {"path.to.your.package"})
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Bean
public ObjectMapper objectMapper() {
ObjectMapper jacksonMapper = new ObjectMapper();
AnnotationIntrospector primary = new JacksonAnnotationIntrospector();
AnnotationIntrospector secondary = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
AnnotationIntrospector pair = AnnotationIntrospector.pair(primary, secondary);
jacksonMapper.setAnnotationIntrospector(pair);
jacksonMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
return jacksonMapper;
}
#Bean
public RestTemplate getRestTemplate() {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
MappingJackson2HttpMessageConverter jaxMsgConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = objectMapper();
jaxMsgConverter.setObjectMapper(objectMapper);
messageConverters.add(jaxMsgConverter);
HttpClientBuilder builder = HttpClientBuilder.create();
HttpClient httpClient = builder.build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate template = new RestTemplate(new BufferingClientHttpRequestFactory(factory));
template.setMessageConverters(messageConverters);
return template;
}
}

Errors using Spring 4.1 #RestController

I'm trying to return JSON when using the #RestController. I'm using Spring 4.1.
Here's the exception I'm getting when calling listrestsites.html using a GET request.
I have the fasterxml Jackson core and databind jars in my build path.
Output of the accept from #requestheader = accept: application/json, text/javascript, /; q=0.01
Any help is appreciated. Thank you,
[DEBUG,ExceptionHandlerExceptionResolver] Resolving exception from
handler [public java.util.List
com.amci.spring3.controller.SitesRestController.listRestSites(java.lang.String)]:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not
find acceptable representation [DEBUG,DefaultListableBeanFactory]
Returning cached instance of singleton bean
'exceptionControllerAdvice' [DEBUG,ExceptionHandlerExceptionResolver]
Invoking #ExceptionHandler method: public
org.springframework.web.servlet.ModelAndView
Here's my Restcontroller class:
#RestController
public class SitesRestController {
#Autowired
private AssetService assetService;
#RequestMapping("/listrestsites.html")
public List<Asset> listRestSites(#RequestHeader(value="accept") String accept) {
System.out.println(getLogLevel());
System.out.println("accept: " + accept);
return assetService.findAssets();
}
}
Also, snippet from my spring.xml:
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
Please make sure that you have the following in your Spring xml file:
<context:annotation-config/>
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
</list>
</property>
</bean>
and all items of your POJO should have getters/setters. Hope it helps
Credit answer to this question

How do I restrict route extensions in #RequestMapping paths for Spring MVC controllers?

I have a fairly simple task that I want to accomplish, but can't seem to find information for Spring MVC routing about it. I have a very simple controller that routes a path to a view:
#Controller
#RequestMapping(value = "/help")
public class HelpController {
private static final String HELP = "help";
#RequestMapping(method = RequestMethod.GET)
public String help(Model model, Locale locale) {
model.addAttribute("locale", locale);
return HELP;
}
}
I would like to throw a 404 if http://mysite.com/help.some.extension.is.entered, but Spring seems to resolve the example to /help. The javadoc says that the #RequestMapping annotation is just a servlet URI mapping, but I thought /help means it needs to be an exact match. Any clarification would be appreciated.
For Spring 4 it's pretty easy to solve:
<mvc:annotation-driven>
<mvc:path-matching suffix-pattern="false" />
</mvc:annotation-driven>
So you still can use mvc:annotation-driven for your config.
You can mention it in the #RequestMapping annotation
it is same as Servlet URL pattern only.
#Controller
public class HelpController {
private static final String HELP = "help";
#RequestMapping(value = "/help" method = RequestMethod.GET)
public String help(Model model, Locale locale) {
model.addAttribute("locale", locale);
return HELP;
}
#RequestMapping(value = "help/*" method = RequestMethod.GET)
public String helpWithExtraWords() {
return "error";
}
}
The best way I can think of is to configure your RequestMappingHandlerMapping explicitly to not consider suffixpaths, this way:
<bean name="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="useSuffixPatternMatch" value="false"></property>
</bean>
However, if you have configured your Spring MVC using mvc:annotation-driven, this will not work, you will have to expand out the entire handlerAdapter definition, which is not that difficult to do, along these lines(this is not complete, you can look through org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser for the entire definition):
<bean name="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"></property>
<property name="validator">
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</property>
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
<bean name="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="useSuffixPatternMatch" value="false"></property>
</bean>
With Spring 3.0.X You can use the useDefaultSuffixPattern property.
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="useDefaultSuffixPattern" value="false" />
</bean>
You will need to remove </mvc:annotation-driven>
Refer URL Pattern Restricting in SPRING MVC

How to deserialize xml using XStream in spring mvc

Im receiving this
<header><h1>001</h1><h2>002</h2></header>
my dispatcher looks like this
<bean id="annotatedMarshaller" class="org.springframework.oxm.xstream.AnnotationXStreamMarshaller">
<property name="annotatedClasses">
<list>
<value>someClasses</value>
<value>someClasses</value>
<value>someClasses</value>
</list>
</property>
</bean>
And here I try to use the unmarchal method from XstreamMarshaller and return the Object to cast
public static Object deserializeXml(String xml) {
StringReader sr =new StringReader(xml);
StreamSource ss=new StreamSource(sr);
Object o=null;
try {
o = xStreamMarshaller.unmarshal(ss);
} catch (XmlMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return o;
}
The problem came when I realized that the unmarshal method marshals the given object to a given javax.xml.transform.Result and not a simple String as the fromXml method from XStream.
thanks to THIS i figured out how to get a Result Object from a String, but not sure if is the best way to do it.
Totally agree with thought that spring should handle all marshaling/unmarshalling stuff.
Everything you need is to declare XStreamMarshaller as one of message converters.
That can be achieved via mvc:annotation section:
<mvc:annotation-driven>
<mvc:message-converters>
<!-- Your XStream converter. -->
</mvc:message-converters>
</mvc:annotation-driven>
or via AnnotationMethodHandlerAdapter:
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<!-- Your XStream converter. -->
</list>
</property>
</bean>

Resources