Spring validation: can't convert from String to Date - spring

I'm doing some spring form validation, however I'm getting:
Failed to convert property value of type 'java.lang.String' to required type 'ja
va.util.Date' for property 'birthdate'; nested exception is java.lang.Illega
lStateException: Cannot convert value of type [java.lang.String] to required typ
e [java.util.Date] for property 'birthdate': no matching editors or conversi
on strategy found
However, in my modelAttribute form I have:
#NotNull
#Past
#DateTimeFormat(style="S-")
private Date birthdate;
I thought the DateTimeFormat was responsible for this?
I'm using the hibernate-validator 4.0.

Theres a chance you'll have to use register a CustomDateEditor in your controller(s) to convert from a String to a Date. The example method below goes in your controller, but you'll have to change the date format to match whatever you're using.
#InitBinder
public void initBinder(WebDataBinder binder) {
CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("MM/dd/yyyy"), true);
binder.registerCustomEditor(Date.class, editor);
}

In order to use #DateTimeFormat you need to install FormattingConversionServiceFactoryBean. <mvc:annotation-driven> does it implicitly, but if you cannot use it you need something like this:
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
<bean id="annotationMethodHandlerAdapter"
class="org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean id="configurableWebBindingInitializer"
class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator"><ref bean="validator"/>
<proeprty name = "conversionService" ref = "conversionService" />
</bean>
</property>
</bean>

Related

How to use MappingJackson2HttpMessageConverter to convert Maps and List correctly?

In my Spring MVC project MappingJackson2HttpMessageConverter configured as follows:
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonMessageConverter" />
</list>
</property>
</bean>
For plain simple Java POJO Beans, serialization works well. All good. But, i also have Beans that include Maps that needed to be serialized as well, and it's fails (JsonMappingException).
From Jackson instructions, I know that to solve this what needed is to indicate the actual type for the object mapper. It looks like that:
Map<String, ResultValue> results = mapper.readValue(jsonSource,
new TypeReference<Map<String, ResultValue>>() { } );
How can be the same configuration be done to MappingJackson2HttpMessageConverter (with based on Jackson2 object mapper)?
It's not clear from your question what doesn't work, but I'm guessing that you have a bean that contains java.util.Map or java.util.List property and you're getting com.fasterxml.jackson.databind.JsonMappingException when deserializing that bean.
In that case you can give hints on fields with #JsonDeserialize annotation. So for instance if you have a java.util.Map<String, ResultValue> field, you can annotate it like:
#JsonDeserialize(keyAs = String.class, contentAs = ResultValue.class)
public Map<String, ResultValue> map;

Spring id-reference not working as expected

I'm working my way through the Spring Framework reference documentation with some very basic application code. So far, I've created an ApplicationContext from an XML file and loaded some beans. I believe I understand this process pretty well. I've loaded some basic beans with attributes based on fundamental types and found that straight-forward.
I'm now working on a composite bean with other beans as its attributes. So far, I've been able to set these attributes using a direct reference to a bean and an inner bean. However, when I try to get the idref element to work (see http://docs.spring.io/spring/docs/3.2.4.RELEASE/spring-framework-reference/html/beans.html#beans-idref-element) I get the following exception:
java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.example.BasicBean] for property 'idRef': no matching editors or conversion strategy found
Code snippets below:
Application Context XML
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="id-bean" class="com.example.BasicBean" scope="singleton">
<property name="value" value="31"/>
</bean>
<bean id="ref-bean" class="com.example.BasicBean" scope="singleton">
<property name="value" value="37"/>
</bean>
<bean id="cb" class="com.example.CompositeBean" scope="singleton">
<property name="id" ref="id-bean"/> <!-- works -->
<property name="inner"> <!-- works -->
<bean class="com.example.BasicBean">
<property name="value" value="43"/>
</bean>
</property>
<property name="idRef"> <!-- exception thrown -->
<idref bean="ref-bean"/>
</property>
</bean>
</beans>
Java App Code
public void main()
{
context = new ClassPathXmlApplicationContext("beans.xml");
CompositeBean cb = context.getBean("cb", CompositeBean.class);
}
Java Bean Code
public class CompositeBean
{
private BasicBean id;
private BasicBean idRef;
private BasicBean inner;
// Default constructor exists
// Setters, getters for each attribute exist
...
}
public class BasicBean
{
private int value;
// Default constructor exists
// Setters, getters for each attribute exist
...
}
Version info: I'm using Eclipse IDE (Kepler), Maven 3.1, Java 7 (1.7.45), Spring 3.2.4
Any thoughts on what I'm doing wrong?
Thanks #Farid for pointing out that I was mis-using the idref attribute in this instance. As the Spring doco points out (which I'd read several times and still missed this) it's designed for passing the id of a bean around a container and not the actual bean. So, stick to the first two means above (ref and inner bean) for passing a bean around.

Spring MVC #PathVariable with dot (.) is getting truncated

This is continuation of question
Spring MVC #PathVariable getting truncated
Spring forum states that it has fixed(3.2 version) as part of ContentNegotiationManager. see the below link.
https://jira.springsource.org/browse/SPR-6164
https://jira.springsource.org/browse/SPR-7632
In my application requestParameter with .com is truncated.
Could anyone explain me how to use this new feature? how is it configurable at xml?
Note: spring forum- #1
Spring MVC #PathVariable with dot (.) is getting truncated
As far as i know this issue appears only for the pathvariable at the end of the requestmapping.
We were able to solve that by defining the regex addon in the requestmapping.
/somepath/{variable:.+}
Spring considers that anything behind the last dot is a file extension such as .jsonor .xml and trucate it to retrieve your parameter.
So if you have /somepath/{variable} :
/somepath/param, /somepath/param.json, /somepath/param.xml or /somepath/param.anything will result in a param with value param
/somepath/param.value.json, /somepath/param.value.xml or /somepath/param.value.anything will result in a param with value param.value
if you change your mapping to /somepath/{variable:.+} as suggested, any dot, including the last one will be consider as part of your parameter :
/somepath/param will result in a param with value param
/somepath/param.json will result in a param with value param.json
/somepath/param.xml will result in a param with value param.xml
/somepath/param.anything will result in a param with value param.anything
/somepath/param.value.json will result in a param with value param.value.json
...
If you don't care of extension recognition, you can disable it by overriding mvc:annotation-driven automagic :
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useSuffixPatternMatch" value="false"/>
</bean>
So, again, if you have /somepath/{variable} :
/somepath/param, /somepath/param.json, /somepath/param.xml or /somepath/param.anything will result in a param with value param
/somepath/param.value.json, /somepath/param.value.xml or /somepath/param.value.anything will result in a param with value param.value
note : the difference from the default config is visible only if you have a mapping like somepath/something.{variable}. see Resthub project issue
if you want to keep extension management, since Spring 3.2 you can also set the useRegisteredSuffixPatternMatch property of RequestMappingHandlerMapping bean in order to keep suffixPattern recognition activated but limited to registered extension.
Here you define only json and xml extensions :
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="contentNegotiationManager" ref="contentNegotiationManager"/>
<property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false"/>
<property name="favorParameter" value="true"/>
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
Note that mvc:annotation-driven accepts now a contentNegotiation option to provide a custom bean but the property of RequestMappingHandlerMapping has to be changed to true (default false) (cf. https://jira.springsource.org/browse/SPR-7632).
For that reason, you still have to override the all mvc:annotation-driven configuration. I opened a ticket to Spring to ask for a custom RequestMappingHandlerMapping : https://jira.springsource.org/browse/SPR-11253. Please vote if you are intereted in.
While overriding, be carreful to consider also custom Execution management overriding. Otherwise, all your custom Exception mappings will fail. You will have to reuse messageCoverters with a list bean :
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
<util:list id="messageConverters">
<bean class="your.custom.message.converter.IfAny"></bean>
<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>
</util:list>
<bean name="exceptionHandlerExceptionResolver"
class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver">
<property name="order" value="0"/>
<property name="messageConverters" ref="messageConverters"/>
</bean>
<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 name="validator" ref="validator" />
</bean>
</property>
<property name="messageConverters" ref="messageConverters"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
</bean>
I implemented, in the open source project Resthub that I am part of, a set of tests on these subjects : see https://github.com/resthub/resthub-spring-stack/pull/219/files & https://github.com/resthub/resthub-spring-stack/issues/217
Update for Spring 4: since 4.0.1 you can use PathMatchConfigurer (via your WebMvcConfigurer), e.g.
#Configuration
protected static class AllResources extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseRegisteredSuffixPatternMatch(true);
}
}
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
In xml, it would be (https://jira.spring.io/browse/SPR-10163):
<mvc:annotation-driven>
[...]
<mvc:path-matching registered-suffixes-only="true"/>
</mvc:annotation-driven>
In addition to Martin Frey's answer, this can also be fixed by adding a trailing slash in the RequestMapping value:
/path/{variable}/
Keep in mind that this fix does not support maintainability. It now requires all URI's to have a trailing slash - something that may not be apparent to API users / new developers. Because it's likely not all parameters may have a . in them, it may also create intermittent bugs
In Spring Boot Rest Controller, I have resolved these by following Steps:
RestController :
#GetMapping("/statusByEmail/{email:.+}/")
public String statusByEmail(#PathVariable(value = "email") String email){
//code
}
And From Rest Client:
Get http://mywebhook.com/statusByEmail/abc.test#gmail.com/
adding the ":.+" worked for me, but not until I removed outer curly brackets.
value = {"/username/{id:.+}"} didn't work
value = "/username/{id:.+}" works
Hope I helped someone :)
/somepath/{variable:.+} works in Java requestMapping tag.
Here's an approach that relies purely on java configuration:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
#Configuration
public class MvcConfig extends WebMvcConfigurationSupport{
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
handlerMapping.setUseSuffixPatternMatch(false);
handlerMapping.setUseTrailingSlashMatch(false);
return handlerMapping;
}
}
One pretty easy way to work around this issue is to append a trailing slash ...
e.g.:
use :
/somepath/filename.jpg/
instead of:
/somepath/filename.jpg
In Spring Boot, The Regular expression solve the problem like
#GetMapping("/path/{param1:.+}")
The complete solution including email addresses in path names for spring 4.2 is
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true" />
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
<mvc:annotation-driven
content-negotiation-manager="contentNegotiationManager">
<mvc:path-matching suffix-pattern="false" registered-suffixes-only="true" />
</mvc:annotation-driven>
Add this to the application-xml
If you are using Spring 3.2.x and <mvc:annotation-driven />, create this little BeanPostProcessor:
package spring;
public final class DoNotTruncateMyUrls implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerMapping) {
((RequestMappingHandlerMapping)bean).setUseSuffixPatternMatch(false);
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
Then put this in your MVC config xml:
<bean class="spring.DoNotTruncateMyUrls" />
Finally I found solution in Spring Docs:
To completely disable the use of file extensions, you must set both of the following:
useSuffixPatternMatching(false), see PathMatchConfigurer
favorPathExtension(false), see ContentNegotiationConfigurer
Adding this to my WebMvcConfigurerAdapter implementation solved the problem:
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
#Override
public void configurePathMatch(PathMatchConfigurer matcher) {
matcher.setUseSuffixPatternMatch(false);
}
For me the
#GetMapping(path = "/a/{variableName:.+}")
does work but only if you also encode the "dot" in your request url as "%2E" then it works. But requires URL's to all be that...which is not a "standard" encoding, though valid. Feels like something of a bug :|
The other work around, similar to the "trailing slash" way is to move the variable that will have the dot "inline" ex:
#GetMapping(path = "/{variableName}/a")
now all dots will be preserved, no modifications needed.
If you write both back and frontend, another simple solution is to attach a "/" at the end of the URL at front. If so, you don't need to change your backend...
somepath/myemail#gmail.com/
Be happy!
As of Spring 5.2.4 (Spring Boot v2.2.6.RELEASE)
PathMatchConfigurer.setUseSuffixPatternMatch and ContentNegotiationConfigurer.favorPathExtension have been deprecated ( https://spring.io/blog/2020/03/24/spring-framework-5-2-5-available-now and https://github.com/spring-projects/spring-framework/issues/24179).
The real problem is that the client requests a specific media type (like .com) and Spring added all those media types by default. In most cases your REST controller will only produce JSON so it will not support the requested output format (.com).
To overcome this issue you should be all good by updating your rest controller (or specific method) to support the 'ouput' format (#RequestMapping(produces = MediaType.ALL_VALUE)) and of course allow characters like a dot ({username:.+}).
Example:
#RequestMapping(value = USERNAME, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public class UsernameAPI {
private final UsernameService service;
#GetMapping(value = "/{username:.+}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.ALL_VALUE)
public ResponseEntity isUsernameAlreadyInUse(#PathVariable(value = "username") #Valid #Size(max = 255) String username) {
log.debug("Check if username already exists");
if (service.doesUsernameExist(username)) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
return ResponseEntity.notFound().build();
}
}
Spring 5.3 and above will only match registered suffixes (media types).
If you are using Spring 3.2+ then below solution will help. This will handle all urls so definitely better than applying regex pattern in the request URI mapping to allow . like /somepath/{variable:.+}
Define a bean in the xml file
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="useSuffixPatternMatch" value="false"/>
<property name="useRegisteredSuffixPatternMatch" value="true"/>
</bean>
The flags usage can be found on the documentation. I am putting snipped to explain
exlanation of useRegisteredSuffixPatternMatch is said to be resolving the issue. From the java doc in the class
If enabled, a controller method mapped to "/users" also matches to
"/users.json" assuming ".json" is a file extension registered with the
provided {#link #setContentNegotiationManager(ContentNegotiationManager)
contentNegotiationManager}. This can be useful for allowing only specific
URL extensions to be used as well as in cases where a "." in the URL path
can lead to ambiguous interpretation of path variable content, (e.g. given
"/users/{user}" and incoming URLs such as "/users/john.j.joe" and
"/users/john.j.joe.json").
Simple Solution Fix: adding a regex {q:.+} in the #RequestMapping
#RequestMapping("medici/james/Site")
public class WebSiteController {
#RequestMapping(value = "/{site:.+}", method = RequestMethod.GET)
public ModelAndView display(#PathVariable("site") String site) {
return getModelAndView(site, "web site");
}
}
Now, for input /site/jamesmedice.com, “site” will display the correct james'site

Using <form:select> and <form:option> with converter but conversion does not happens, why?

I have this form for creating an Enrichment:
<form:form method="post" action="..." modelAttribute="enrichment">
...
<form:select path="tag">
<form:options items="${tagList}" itemValue="id" itemLabel="label" />
</form:select>
...
The Enrichment class has a Tag attribute. So when th user has selected a tag in the Tag list, tag.id (wich is a String) is sent throught the form. I don't think I could directly send a tag object am I wright? So I wrote a Converter to convert a String to a Tag, according to http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html#core-convert-Converter-API. So I did this :
public class IdToTagConverter implements Converter<String, Tag> {
#Autowired
TagService tagService;
public Tag convert(String id) {
return tagService.findTagById(Integer.parseInt(id));
}
}
And I created the bean :
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="exemple.IdToTagConverter"/>
</list>
</property>
</bean>
And I thought it would do the convertion automatically. But the error message is still here :
[Failed to convert property value of type 'java.lang.String' to
required type 'exemple.Tag' for property 'tag'; nested exception is
java.lang.IllegalStateException: Cannot convert value of type
[java.lang.String] to required type [exemple.Tag] for property 'tag':
no matching editors or conversion strategy found]
What did I miss?
Found the solution here :
http://forum.springsource.org/showthread.php?84003-Converters-no-matching-editors-or-conversion-strategy-found
I just replaced
<mvc:annotation-driven />
by
<mvc:annotation-driven conversion-service="conversionService" />
and it worked. Why? Spring MVC Voodoo.
Looks like Spring is not aware of your converter, or Conversion Service. Follow this part of the documentation to register your custom converter - > http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/validation.html#format-configuring-FormattingConversionService

Hibernate Validation and localized error messages?

hibernate and i want to provide localized error messages for hibernate annotations
so i created to properties files ValidatorMessages.properties, ValidatorMessages_ar.properties
and put them in resources folder, and i am using messageSource to read from property files:
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:messages</value>
<value>classpath:errors</value>
<value>classpath:app</value>
<value>classpath:ValidatorMessages</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8" />
</bean>
and in the class i use something like:
#NotNull(message = "{validation.notEmpty.password}")
private string password;
and when calling the validator i use:
Validator validator = Validation.buildDefaultValidatorFactory()
.getValidator();
Set<ConstraintViolation<MyClass> cvs = validator
.validate(myObject);
for (ConstraintViolation<MyClass> cv : cvs) {
String field = cv.getPropertyPath().toString();
result.addError(new FieldError("version", field, cv.getMessage()));
}
if (result.hasErrors()) {
initModel();
result.reject("add.version.errors");
return "manageVersions";
}
it works fine with english, it displays english messages correctly, but when switching to arabic it still displays the english messages instead of arabic, although that
LocaleContextHolder.getLocale() indicates that the language is changed and it's arabic, so is there are something missing with the configuration or any ideas what might cause that ?
In your Spring config when you are setting up your validator bean, I think you need to set the message interpolator:
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="messageInterpolator" ref="interpolator" />
</bean>
where the interpolator bean would be of type LocaleContextMessageInterpolator (see here for more info). Hibernate Validator doesn't automatically know to look at LocaleContextHolder.
You might also need to set validationMessageSource property but I think its defaulted properly since you are at least getting the English error messages.

Resources