Announcement Announcement Module
Collapse
No announcement yet.
Binding error - SimpleFormController Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Binding error - SimpleFormController

    Hi, I have a problem with the SimpleFormClass.
    I would like write a simple class to render a form with only one text field, I use velocity and spring.vm macro. If I send a empty field my Validator fills the errors collection, but if I fill the filed with a String the result is this:

    HTTP Status 500 -

    --------------------------------------------------------------------------------

    type Exception report

    message

    description The server encountered an internal error () that prevented it from fulfilling this request.

    exception

    javax.servlet.ServletException: Invocation of method 'getBindStatus' in class org.springframework.web.servlet.support.RequestCon text threw exception class java.lang.IllegalStateException : Neither Errors instance nor plain target object for bean name command available as request attribute
    org.springframework.web.servlet.FrameworkServlet.s erviceWrapper(FrameworkServlet.java:382)
    org.springframework.web.servlet.FrameworkServlet.d oPost(FrameworkServlet.java:326)
    javax.servlet.http.HttpServlet.service(HttpServlet .java:763)
    javax.servlet.http.HttpServlet.service(HttpServlet .java:856)


    root cause

    org.apache.velocity.exception.MethodInvocationExce ption: Invocation of method 'getBindStatus' in class org.springframework.web.servlet.support.RequestCon text threw exception class java.lang.IllegalStateException : Neither Errors instance nor plain target object for bean name command available as request attribute
    org.apache.velocity.runtime.parser.node.ASTMethod. execute(ASTMethod.java:246)
    org.apache.velocity.runtime.parser.node.ASTReferen ce.execute(ASTReference.java:175)
    org.apache.velocity.runtime.parser.node.ASTReferen ce.value(ASTReference.java:327)
    org.apache.velocity.runtime.parser.node.ASTExpress ion.value(ASTExpression.java:51)
    org.apache.velocity.runtime.parser.node.ASTSetDire ctive.render(ASTSetDirective.java:95)
    org.apache.velocity.runtime.parser.node.ASTBlock.r ender(ASTBlock.java:55)
    org.apache.velocity.runtime.parser.node.SimpleNode .render(SimpleNode.java:230)
    org.apache.velocity.runtime.parser.node.ASTIfState ment.render(ASTIfStatement.java:89)
    org.apache.velocity.runtime.parser.node.SimpleNode .render(SimpleNode.java:230)
    org.apache.velocity.runtime.directive.VelocimacroP roxy.render(VelocimacroProxy.java:172)
    org.apache.velocity.runtime.parser.node.ASTDirecti ve.render(ASTDirective.java:114)
    org.apache.velocity.runtime.parser.node.SimpleNode .render(SimpleNode.java:230)
    org.apache.velocity.Template.merge(Template.java:2 56)
    org.springframework.web.servlet.view.velocity.Velo cityView.mergeTemplate(VelocityView.java:311)
    org.springframework.web.servlet.view.velocity.Velo cityView.renderMergedTemplateModel(VelocityView.ja va:245)
    org.springframework.web.servlet.view.AbstractTempl ateView.renderMergedOutputModel(AbstractTemplateVi ew.java:160)
    org.springframework.web.servlet.view.AbstractView. render(AbstractView.java:242)
    org.springframework.web.servlet.DispatcherServlet. render(DispatcherServlet.java:712)
    org.springframework.web.servlet.DispatcherServlet. doService(DispatcherServlet.java:572)
    org.springframework.web.servlet.FrameworkServlet.s erviceWrapper(FrameworkServlet.java:366)
    org.springframework.web.servlet.FrameworkServlet.d oPost(FrameworkServlet.java:326)
    javax.servlet.http.HttpServlet.service(HttpServlet .java:763)
    javax.servlet.http.HttpServlet.service(HttpServlet .java:856)


    note The full stack trace of the root cause is available in the Tomcat logs.


    --------------------------------------------------------------------------------

    Apache Tomcat/5.0.16


    My SimpleController class

    package example;

    import org.springframework.web.servlet.mvc.SimpleFormCont roller;
    import org.springframework.web.servlet.ModelAndView;

    import javax.servlet.ServletException;

    public class SimpleController extends SimpleFormController {

    public ModelAndView onSubmit(Object command) throws ServletException {
    return new ModelAndView(getSuccessView());
    }
    }


    and my Validator

    package example;

    import org.springframework.validation.Validator;
    import org.springframework.validation.Errors;

    public class ExampleValidator implements Validator {
    public boolean supports(Class aClass) {
    return aClass.equals(SimpleBean.class);
    }

    public void validate(Object o, Errors errors) {
    SimpleBean sb = (SimpleBean) o;

    if (sb.getName() == null || "".equals(sb.getName())) {
    errors.rejectValue("name", "nameRequired", "Il campo non puņ essere vuoto");
    }
    }
    }

  • #2
    Try using:

    Code:
    protected ModelAndView onSubmit(Object command, BindException errors){
        return new ModelAndView(getSuccessView(), errors.getModel());
    }

    Comment


    • #3
      What bothers me about this is it seems to violate the whole premise of the ModelAndView class.
      The ModelAndView class is supposed to have a view name and a model that view "knows" how to render that model, not the Errors model. This effectively cuts off the possibility for the view to re-render the model.
      A typical scenario would be:
      1) the user calls some form
      2) the user submits the form (which is validated and sent to the Controller class)
      3) The Controller will do its magic and then maybe send it to a confirmation view
      4) Confirmation view will send the Valid and Correct information to its controller which will then show the success view

      I thought the framework for the SimpleFormController is to hold the Errors Map Object for us, which we then can use via the <spring:bind> tags...

      I hope someone can correct any flaws in the theory here. Still trying to put all the pieces together in some coherent fashion.

      Thanks

      Comment


      • #4
        ... This effectively cuts off the possibility for the view to re-render the model.
        The errors.getModel() is returning a model that can be rendered with <spring:bind> tags. The model is essentially a wrapper for the command object that has the ability to re-populate fields with submitted values that could not be bound to the command object. However, in the case of a the call to onSubmit(...) the model should not contain any errors (unless you have overridden processFormSubmission()).

        I thought the framework for the SimpleFormController is to hold the Errors Map Object for us, which we then can use via the <spring:bind> tags...
        And that is exactly what it does. You would access the model returned by errors.getModel() by using the command name (default is "command") like this:

        Code:
        <spring&#58;bind path="command.property">
          ...
        </spring&#58;bind>

        Comment


        • #5
          Daniel,
          Thank you very much for your response. I really appreciate it!
          It makes more sense now. I was misunderstanding the intended process flow.

          My view will only collect the data/information from the user. It then goto the Validator. The Validator will set the error Map. If there are any errors, it gets sent back to the view and is bound with the <spring:bind> tags (both value and message). If there are no errors, it will get passed on to the Controller class ( in my case, a SimpleFormController.onSubmit( Object command ) implementation takes the request ).

          This is the kicker part. If there are no errors (because it passed the Validator class), I get that infamous "Couldn not find Errors object...call the errors.getModel() in your ModelAndView".
          I then change the onSubmit method signature to the onSubmit(Object command, BindException errors) and
          return new ModelAndView("viewname", errors.getModel()); (referring to delnoij's posting)
          The ServletException then goes away.

          I am confused by this behavior. Why do I even need the erros Map object when it already passed through my Validator? By rights, I would just forward the request to the success view, which doesn't need or use the <spring:bind> tags.
          The stack traces seem to say that there is no Error object being created when the framework is trying add objects to the Error Map object.
          I wonder when the Error object is declared, and what scope it has. If we have the page scope set to either "request" or "session" instead of "false", if that would make a difference...

          These Exceptions could also be the result of some wrongly set parameter in the action-servlet.xml file? Some other setting perhaps?
          Any suggestions at all are greatly appreciated.

          Once again,
          Thanks!

          Comment


          • #6
            If there are no errors (because it passed the Validator class), I get that infamous "Couldn not find Errors object...call the errors.getModel() in your ModelAndView".
            This error tells me that your success view contains <spring:bind> tags. In other words, the <spring:bind> tags in your view could not find an Errors object.

            I then change the onSubmit method signature to the onSubmit(Object command, BindException errors) and
            return new ModelAndView("viewname", errors.getModel()); ... The ServletException then goes away.
            The method signature doesn't have anything to do with the error. The exception went away because you returned a ModelAndView with the errors.getModel().

            Why do I even need the erros Map object when it already passed through my Validator?
            An Errors object is required when using <spring:bind> tags. In that regard, it has nothing to do with the Validator--this exception would still be thrown even if you were not using a Validator.

            By rights, I would just forward the request to the success view, which doesn't need or use the <spring:bind> tags.
            Exactly. If you were to eliminate the <spring:bind> tags from your success view and remove the errors.getModel() call in onSubmit(), you would no longer get the error.

            I wonder when the Error object is declared, and what scope it has. If we have the page scope set to either "request" or "session" instead of "false", if that would make a difference...
            The Errors object is created by the data binder. You effectively put the Errors object in the request when you use errors.getModel() while constructing your ModelAndView. Errors.getModel() actually returns a map containing two objects: the Errors (BindException) object itself, and the command object inside a BeanWrapper.

            Hope that helps.

            Comment


            • #7
              Daniel,

              You da man! I got it now!

              My dataflow needs to be modified.

              Thank you very much!

              Aloha!

              Comment

              Working...
              X