Spring – Why failed to convert from string to Date in this case

springspring-mvc

I try to convert from String to Date by doing this:

Form:

   <tr>
        <td><form:label path="dateOfBirth" cssErrorClass="error"><spring:message
                code="account.dob"/></form:label></td>
        <td><form:input path="dateOfBirth" type="date"/></td>
        <td><form:errors path="dateOfBirth"/></td>
    </tr>

in configuration class

import org.springframework.format.datetime.DateFormatter
// .....

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "..." })
public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter {

    //....
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new DateFormatter("yyyy-MM-dd"));
    }
}

The input value return correct string format for date

enter image description here

But it keep reporting an error

Failed to convert property value of type java.lang.String to required
type java.util.Date for property dateOfBirth; nested exception is
org.springframework.core.convert.ConversionFailedException: Failed to
convert from type java.lang.String to type java.util.Date for value
1999-01-01; nested exception is java.lang.IllegalArgumentException:
Unable to parse 1999-01-01

What did i probably miss here?

UPDATE:

My validator

 @Override
    public void validate(Object target, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors, "username", "required", new Object[] { "Username" });
        ValidationUtils.rejectIfEmpty(errors, "password", "required", new Object[] { "Password" });
        ValidationUtils.rejectIfEmpty(errors, "emailAddress", "required", new Object[] { "Email address" });
        ValidationUtils.rejectIfEmpty(errors, "address.street", "required", new Object[] { "Street" });
        ValidationUtils.rejectIfEmpty(errors, "address.city", "required", new Object[] { "City" });
        ValidationUtils.rejectIfEmpty(errors, "address.country", "required", new Object[] { "Country" });

        if (!errors.hasFieldErrors("emailAddress")) {
            Account account = (Account) target;
            String email = account.getEmailAddress();
            if (!email.matches(EMAIL_PATTERN)) {
                errors.rejectValue("emailAddress", "invalid");
            }
        }
    }

My handler

@RequestMapping(method = { RequestMethod.POST, RequestMethod.PUT })
public String handleRegistration(@Valid @ModelAttribute Account account,
                                 BindingResult result)
{
    this.logger.info("Registering account: {}", account);

    if (result.hasErrors()) {
        return "customer/register";
    }
    this.accountService.save(account);
    return "redirect:/customer/account/" + account.getId();
}

Here is full stacktrace

14:06:44.556 [http-bio-8080-exec-6] TRACE o.s.web.servlet.DispatcherServlet - Bound request context to thread: org.apache.catalina.connector.RequestFacade@3f2c9e94
14:06:44.557 [http-bio-8080-exec-6] DEBUG o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 'dispatcher' processing POST request for [/chapter6-bookstore/customer/register]
14:06:44.557 [http-bio-8080-exec-6] TRACE o.s.web.servlet.DispatcherServlet - Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@27a9283] in DispatcherServlet with name 'dispatcher'
14:06:44.557 [http-bio-8080-exec-6] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /customer/register
14:06:44.557 [http-bio-8080-exec-6] TRACE o.s.w.s.m.m.a.RequestMappingHandlerMapping - Found 1 matching mapping(s) for [/customer/register] : [{[/customer/register],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}]
14:06:44.557 [http-bio-8080-exec-6] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.String com.apress.prospringmvc.bookstore.web.controller.RegistrationController.handleRegistration(com.apress.prospringmvc.bookstore.domain.Account,org.springframework.validation.BindingResult)]
14:06:44.557 [http-bio-8080-exec-6] TRACE o.s.web.servlet.DispatcherServlet - Testing handler adapter [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@46b61f25]
14:06:44.557 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@7f22c404] supports [class com.apress.prospringmvc.bookstore.domain.Account]
14:06:44.558 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver@71e75afc] supports [class com.apress.prospringmvc.bookstore.domain.Account]
14:06:44.558 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver@57ffc75d] supports [class com.apress.prospringmvc.bookstore.domain.Account]
14:06:44.558 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@2aea9f96] supports [class com.apress.prospringmvc.bookstore.domain.Account]
14:06:44.558 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@7f22c404] supports [interface org.springframework.validation.BindingResult]
14:06:44.558 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver@71e75afc] supports [interface org.springframework.validation.BindingResult]
14:06:44.558 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver@57ffc75d] supports [interface org.springframework.validation.BindingResult]
14:06:44.558 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@2aea9f96] supports [interface org.springframework.validation.BindingResult]
14:06:44.558 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@38670b9] supports [interface org.springframework.validation.BindingResult]
14:06:44.558 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver@510ffbf9] supports [interface org.springframework.validation.BindingResult]
14:06:44.558 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver@61bc5ad9] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver@1cdf3eeb] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver@1f36d53b] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver@303156f7] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver@1907d2c7] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver@3b130da9] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@7e1194af] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.servlet.mvc.method.annotation.RedirectAttributesMethodArgumentResolver@14a6f81a] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.method.annotation.ModelMethodProcessor@4fa50c24] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.method.annotation.MapMethodProcessor@6cf83e3c] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodArgumentResolverComposite - Testing if argument resolver [org.springframework.web.method.annotation.ErrorsMethodArgumentResolver@1e3e6be0] supports [interface org.springframework.validation.BindingResult]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodReturnValueHandlerComposite - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler@2f504468] supports [class java.lang.String]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodReturnValueHandlerComposite - Testing if return value handler [org.springframework.web.method.annotation.ModelMethodProcessor@8e63aaf] supports [class java.lang.String]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodReturnValueHandlerComposite - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler@37bf1fd4] supports [class java.lang.String]
14:06:44.559 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodReturnValueHandlerComposite - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@4351dda1] supports [class java.lang.String]
14:06:44.560 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodReturnValueHandlerComposite - Testing if return value handler [org.springframework.web.method.annotation.ModelAttributeMethodProcessor@4673cae7] supports [class java.lang.String]
14:06:44.560 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodReturnValueHandlerComposite - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@3dfb2615] supports [class java.lang.String]
14:06:44.563 [http-bio-8080-exec-6] TRACE o.s.w.m.s.HandlerMethodReturnValueHandlerComposite - Testing if return value handler [org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler@7edf47aa] supports [class java.lang.String]
14:06:44.564 [http-bio-8080-exec-6] TRACE o.s.w.m.s.InvocableHandlerMethod - Invoking [countries] method with arguments [en_US]
14:06:44.565 [http-bio-8080-exec-6] TRACE o.s.w.m.s.InvocableHandlerMethod - Method [countries] returned [{=, AE=United Arab Emirates, AL=Albania, AR=Argentina, AT=Austria, AU=Australia, BA=Bosnia and Herzegovina, BE=Belgium, BG=Bulgaria, BH=Bahrain, BO=Bolivia, BR=Brazil, BY=Belarus, CA=Canada, CH=Switzerland, CL=Chile, CN=China, CO=Colombia, CR=Costa Rica, CS=Serbia and Montenegro, CU=Cuba, CY=Cyprus, CZ=Czech Republic, DE=Germany, DK=Denmark, DO=Dominican Republic, DZ=Algeria, EC=Ecuador, EE=Estonia, EG=Egypt, ES=Spain, FI=Finland, FR=France, GB=United Kingdom, GR=Greece, GT=Guatemala, HK=Hong Kong, HN=Honduras, HR=Croatia, HU=Hungary, ID=Indonesia, IE=Ireland, IL=Israel, IN=India, IQ=Iraq, IS=Iceland, IT=Italy, JO=Jordan, JP=Japan, KR=South Korea, KW=Kuwait, LB=Lebanon, LT=Lithuania, LU=Luxembourg, LV=Latvia, LY=Libya, MA=Morocco, ME=Montenegro, MK=Macedonia, MT=Malta, MX=Mexico, MY=Malaysia, NI=Nicaragua, NL=Netherlands, NO=Norway, NZ=New Zealand, OM=Oman, PA=Panama, PE=Peru, PH=Philippines, PL=Poland, PR=Puerto Rico, PT=Portugal, PY=Paraguay, QA=Qatar, RO=Romania, RS=Serbia, RU=Russia, SA=Saudi Arabia, SD=Sudan, SE=Sweden, SG=Singapore, SI=Slovenia, SK=Slovakia, SV=El Salvador, SY=Syria, TH=Thailand, TN=Tunisia, TR=Turkey, TW=Taiwan, UA=Ukraine, US=United States, UY=Uruguay, VE=Venezuela, VN=Vietnam, YE=Yemen, ZA=South Africa}]
14:06:44.565 [http-bio-8080-exec-6] TRACE o.s.w.m.s.InvocableHandlerMethod - Invoking [initBinder] method with arguments [org.springframework.web.servlet.mvc.method.annotation.ExtendedServletRequestDataBinder@6256041a]
14:06:44.566 [http-bio-8080-exec-6] TRACE o.s.w.m.s.InvocableHandlerMethod - Method [initBinder] returned [null]
14:06:44.579 [http-bio-8080-exec-6] TRACE o.s.w.s.m.m.a.ServletInvocableHandlerMethod - Invoking [handleRegistration] method with arguments [com.apress.prospringmvc.bookstore.domain.Account@64f6614c, org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'account' on field 'dateOfBirth': rejected value [1999-01-01]; codes [typeMismatch.account.dateOfBirth,typeMismatch.dateOfBirth,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [account.dateOfBirth,dateOfBirth]; arguments []; default message [dateOfBirth]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'dateOfBirth'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type java.util.Date for value '1999-01-01'; nested exception is java.lang.IllegalArgumentException: Unable to parse '1999-01-01']]
14:06:44.579 [http-bio-8080-exec-6] TRACE o.s.w.s.m.m.a.ServletInvocableHandlerMethod - Method [handleRegistration] returned [customer/register]
14:06:44.583 [http-bio-8080-exec-6] DEBUG o.s.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.tiles2.TilesView: name 'customer/register'; URL [customer/register]] in DispatcherServlet with name 'dispatcher'
14:06:44.584 [http-bio-8080-exec-6] TRACE o.s.w.servlet.view.tiles2.TilesView - Rendering view with name 'customer/register' with model {countries={=, AE=United Arab Emirates, AL=Albania, AR=Argentina, AT=Austria, AU=Australia, BA=Bosnia and Herzegovina, BE=Belgium, BG=Bulgaria, BH=Bahrain, BO=Bolivia, BR=Brazil, BY=Belarus, CA=Canada, CH=Switzerland, CL=Chile, CN=China, CO=Colombia, CR=Costa Rica, CS=Serbia and Montenegro, CU=Cuba, CY=Cyprus, CZ=Czech Republic, DE=Germany, DK=Denmark, DO=Dominican Republic, DZ=Algeria, EC=Ecuador, EE=Estonia, EG=Egypt, ES=Spain, FI=Finland, FR=France, GB=United Kingdom, GR=Greece, GT=Guatemala, HK=Hong Kong, HN=Honduras, HR=Croatia, HU=Hungary, ID=Indonesia, IE=Ireland, IL=Israel, IN=India, IQ=Iraq, IS=Iceland, IT=Italy, JO=Jordan, JP=Japan, KR=South Korea, KW=Kuwait, LB=Lebanon, LT=Lithuania, LU=Luxembourg, LV=Latvia, LY=Libya, MA=Morocco, ME=Montenegro, MK=Macedonia, MT=Malta, MX=Mexico, MY=Malaysia, NI=Nicaragua, NL=Netherlands, NO=Norway, NZ=New Zealand, OM=Oman, PA=Panama, PE=Peru, PH=Philippines, PL=Poland, PR=Puerto Rico, PT=Portugal, PY=Paraguay, QA=Qatar, RO=Romania, RS=Serbia, RU=Russia, SA=Saudi Arabia, SD=Sudan, SE=Sweden, SG=Singapore, SI=Slovenia, SK=Slovakia, SV=El Salvador, SY=Syria, TH=Thailand, TN=Tunisia, TR=Turkey, TW=Taiwan, UA=Ukraine, US=United States, UY=Uruguay, VE=Venezuela, VN=Vietnam, YE=Yemen, ZA=South Africa}, account=com.apress.prospringmvc.bookstore.domain.Account@64f6614c, org.springframework.validation.BindingResult.account=org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'account' on field 'dateOfBirth': rejected value [1999-01-01]; codes [typeMismatch.account.dateOfBirth,typeMismatch.dateOfBirth,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [account.dateOfBirth,dateOfBirth]; arguments []; default message [dateOfBirth]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'dateOfBirth'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type java.util.Date for value '1999-01-01'; nested exception is java.lang.IllegalArgumentException: Unable to parse '1999-01-01'], randomBooks=[com.apress.prospringmvc.bookstore.domain.Book@5d3dc8bb[
  title=Refactoring: Improving the Design of Existing Code
  author=Martin Fowler
  isbn=9780201485677
], com.apress.prospringmvc.bookstore.domain.Book@5528c285[
  title=Clean Code: A Handbook of Agile Software Craftsmanship
  author=Robert C. Martin
  isbn=9780132350884
]]} and static attributes {}

Best Answer

Add this to your controller:

@InitBinder
public void initBinder(final WebDataBinder binder){
  final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); 
  binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
Related Topic