Announcement Announcement Module
Collapse
No announcement yet.
Form controllers, binding and the "Cancel" action Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Form controllers, binding and the "Cancel" action

    This is a continuation of an earlier post of mine and several others that have appeared on this general topic. Having poured over the source code and thought about the problem a bit more, I think I can state it more succinctly:

    Both SimpleFormController and AbstractWizardController make the assumption (i.e., the decision is made in final methods up the inheritance chain) that any submit action by the user necessitates a data bind. This only works well if the result of a cancel is to abandon the form altogether. Often a cancel means only abandoning one branch of a work flow, in which case you'd like to be able to preempt the bind so that the command object is not modified. The only way to prevent the bind is to override isFormSubmission, in which case you lose control of the flow (the same view is redisplayed).

    So far I've only come up with 2 solution possibilities:
    1. Make a copy of the relevant portion of the command object, allow the binding and restore the copy in case of a cancel.
    2. Rewrite the controller hierarchy to allow control of data binding in implementation classes.

    1 seems inelegant and 2 would be a lot of work. What I'm looking for by way of a response is for someone knowledgable to say, "yes, you have it right, your stuck" or "no, here's a more direct way to handle it". Thanks!

    BTW, I'm aware of the various workflow frameworks available. I'm planning to move to SpringWebflow as soon is it's stable (and I understand it). In spite of it having been around for a while it's clear that they have been ripping out some wires to make it better.[/list]

  • #2
    I'd think avoid 1., and maybe 2. is a bit extreme, but along the lines of 2.... could you override createBinder in BaseCommandController.

    You could return your own ServletRequestDataBinder subclass that basically does nothing in the bind method? e.g. MyDoesNothingServletRequestDataBinder extends ServletRequestDataBinder

    If you did this, I imagine you'd probably also want to override the suppressValidation template method in BaseCommandController since if you don't want to bind, you probably also don't want to validate.

    It might be good if there were a suppressBinding template method in BaseCommandController or something so this was easier to do.

    Comment


    • #3
      Thanks. That's exactly what I was looking for.

      However, I'm finding that in general the provided form controllers don't extend very well to anything beyond very basic form handling. In particular, the Wizard controller model starts to break down as soon as your state transitions become anything but linear. I generalized the model to handle arbitrary page transitions with named actions rather than page numbers, but now I have several giant unwieldy switch statements. Any further down this road and I'm reinventing SWF, so I think I'll stop and wait for the release.

      Anyway, thanks for the tip.

      Comment


      • #4
        What I did (please see note at bottom) was created a subclass of ServletRequestDataBinder

        Code:
        public class CancelServletRequestDataBinder extends ServletRequestDataBinder{
            public CancelServletRequestDataBinder(Object target, String objectName) {
                super(target, objectName);
            }
        
            public void bind(ServletRequest servletRequest) {
                // do not do any binding
            }
        }
        then in my controller, I overrode createBinder

        Code:
        protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object command) throws Exception {
                
                if(request.getParameter(InvestmentState.CANCEL.toString()) != null){
                    return new CancelServletRequestDataBinder(command, getCommandName());
                }
                return super.createBinder(request, command);
            }
        *Note I just implemented this today. I don't know if there are any unforseen repercussion, but initial testing seems to show that it works.

        Comment


        • #5
          Well I may have already found a problem. I have a validator that check that certain fields must be >=0 and everything works fine. But now there is a loophole.

          User enters a negative number, clicks save, the user is notified that there is an error but the object's field has been bound to the negative value. The user instead of fixing the error, clicks cancel. The field now has a negative value.

          Comment


          • #6
            Nevermind. I still had override of processFormSubmission in my controller used in a previous attempt. Now the problem is if the user follows the same scenario given in my prevois post, the user must correct the problem before he/she can cancel.

            All I want is everything. :wink: My only solution might be to keep a old copy of the command object in the session which I really didn't want to do.


            Originally posted by mfuller
            Well I may have already found a problem. I have a validator that check that certain fields must be >=0 and everything works fine. But now there is a loophole.

            User enters a negative number, clicks save, the user is notified that there is an error but the object's field has been bound to the negative value. The user instead of fixing the error, clicks cancel. The field now has a negative value.

            Comment

            Working...
            X