Search code examples
springvalidationspring-roo

@AssertTrue validation for Date field in Spring Roo application not working


I'm struggling with validation of my model in application based on Spring Roo. Let's describe in more details what I have so far:

public class Record {
   // ... some other fields

   @NotNull
   @Future 
   @Temporal(TemporalType.TIMESTAMP)
   @DateTimeFormat(style="M-")
   Date generatedDate;

   @AssertTrue(message="blahblahblah")
   public Boolean isGeneratedDate() {
       // validation code, let's presume it return false all the time
       return false;
   }
}

Once I will run it like this, then I'll get following exception:

    SEVERE: Servlet.service() for servlet Portal threw exception
java.lang.IllegalArgumentException: The source to convert from must be an instance of @javax.validation.constraints.NotNull @javax.validation.constrai
nts.Future @javax.persistence.Temporal @org.springframework.format.annotation.DateTimeFormat java.util.Date; instead it was a java.lang.Boolean
        at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:166)
        at org.springframework.validation.AbstractPropertyBindingResult.formatFieldValue(AbstractPropertyBindingResult.java:125)
        at org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:222)
        at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:120)
        at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:178)
        at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:198)
        at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:164)
        at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:127)
        at org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:421)
        at org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:142)
        at org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:102)
        at org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:79)
        at org.apache.jsp.tag.web.form.fields.datetime_tagx._jspx_meth_form_005finput_005f0(datetime_tagx.java:711)
        at org.apache.jsp.tag.web.form.fields.datetime_tagx.doTag(datetime_tagx.java:318)
        at org.apache.jsp.WEB_002dINF.views.portationrecords.create_jspx._jspx_meth_field_005fdatetime_005f1(create_jspx.java:302)
        at org.apache.jsp.WEB_002dINF.views.portationrecords.create_jspx.access$7(create_jspx.java:281)
        at org.apache.jsp.WEB_002dINF.views.portationrecords.create_jspx$Helper.invoke0(create_jspx.java:378)
        at org.apache.jsp.WEB_002dINF.views.portationrecords.create_jspx$Helper.invoke(create_jspx.java:397)
        at org.apache.jsp.tag.web.form.create_tagx$Helper.invoke0(create_tagx.java:688)
        at org.apache.jsp.tag.web.form.create_tagx$Helper.invoke(create_tagx.java:729)
        at org.apache.jsp.tag.web.util.panel_tagx._jspx_meth_c_005fif_005f0(panel_tagx.java:184)
        at org.apache.jsp.tag.web.util.panel_tagx.doTag(panel_tagx.java:130)
        at org.apache.jsp.tag.web.form.create_tagx.doTag(create_tagx.java:233)
        at org.apache.jsp.WEB_002dINF.views.portationrecords.create_jspx._jspx_meth_form_005fcreate_005f0(create_jspx.java:102)
        at org.apache.jsp.WEB_002dINF.views.portationrecords.create_jspx._jspService(create_jspx.java:66)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
        at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:551)
        at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:488)
        at org.apache.jasper.runtime.JspRuntimeLibrary.include(JspRuntimeLibrary.java:968)
        at org.apache.jasper.runtime.PageContextImpl.doInclude(PageContextImpl.java:650)
        at org.apache.jasper.runtime.PageContextImpl.include(PageContextImpl.java:644)
        at org.apache.tiles.jsp.context.JspTilesRequestContext.include(JspTilesRequestContext.java:103)
        at org.apache.tiles.jsp.context.JspTilesRequestContext.dispatch(JspTilesRequestContext.java:96)
        at org.apache.tiles.renderer.impl.TemplateAttributeRenderer.write(TemplateAttributeRenderer.java:44)
        at org.apache.tiles.renderer.impl.AbstractBaseAttributeRenderer.render(AbstractBaseAttributeRenderer.java:106)
        at org.apache.tiles.renderer.impl.ChainedDelegateAttributeRenderer.write(ChainedDelegateAttributeRenderer.java:76)
        at org.apache.tiles.renderer.impl.AbstractBaseAttributeRenderer.render(AbstractBaseAttributeRenderer.java:106)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:670)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:336)
        at org.apache.tiles.template.InsertAttributeModel.renderAttribute(InsertAttributeModel.java:210)
        at org.apache.tiles.template.InsertAttributeModel.end(InsertAttributeModel.java:126)
        at org.apache.tiles.jsp.taglib.InsertAttributeTag.doTag(InsertAttributeTag.java:311)
        at org.apache.jsp.WEB_002dINF.layouts.default_jspx._jspx_meth_tiles_005finsertAttribute_005f2(default_jspx.java:224)
        at org.apache.jsp.WEB_002dINF.layouts.default_jspx._jspService(default_jspx.java:87)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
        at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
        at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
        at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
        at org.apache.tiles.servlet.context.ServletTilesRequestContext.forward(ServletTilesRequestContext.java:241)
        at org.apache.tiles.servlet.context.ServletTilesRequestContext.dispatch(ServletTilesRequestContext.java:222)
        at org.apache.tiles.renderer.impl.TemplateAttributeRenderer.write(TemplateAttributeRenderer.java:44)
        at org.apache.tiles.renderer.impl.AbstractBaseAttributeRenderer.render(AbstractBaseAttributeRenderer.java:106)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:670)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:690)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:644)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:627)
        at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:321)
        at org.springframework.web.servlet.view.tiles2.TilesView.renderMergedOutputModel(TilesView.java:124)
        at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:262)
        at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1180)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:950)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:147)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:311)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:101)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
        at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:5
4)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
        at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
        at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java
:182)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)

It looks like Spring (or Roo?) is trying to fetch the result of validation and show it in the jspx. On the view I'm using create.jspx generated by Roo, where this tag is defined as following:

<field:datetime dateTimePattern="${record_generateddate_date_format}" field="generatedDate" future="true" id="c_com_namespace_Record_generatedDate" required="true" z="ByZXwLcdD87pSCjgpCV7ac0ASq4="/>

I also observed, that once I will rename validating method to something like isValid(), validation runs correctly, eventhough this time the non-existing field valid is marked as causing problems (obviously based on the method's name). As a result, I'm not able to display message for correct field in the view. (yeah, I could switch it it RecordController, but it feels sooo wrong). Any hints how to overcome this?


Solution

  • It is, because you violate some java bean naming covention, or at least confuse the validator.

    You have a field generatedDate with getters and setters (generated by Roo):

    Date generatedDate;
    Date getGeneratedDate()...
    void setGeneratedDate(Date d)...
    

    And then you have this method isGeneratedDate(). Unfortunaly this method match the java bean naming convention for a boolean value named generatedDate too!

    I would recommend to rename isGeneratedDate() so something like: isGeneratedDateValid()