Announcement Announcement Module
Collapse
No announcement yet.
Quick MultiActionController question Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Quick MultiActionController question

    I'm doing my first system using Spring MVC, and there's a lot to learn (normally because I'm spoiled for choice). I've just switched from using an AbstractController to using a MultiActionController and am now a little puzzled by the function of the 'handleRequestInternal' method. I thought that in an MAC, all the handling was done by different non-standard methods, chosen either by matching the last bit of the URL to a method name or by some other means, depending on resolver. So where does 'handleRequestInternal' come in? Is this a fallback, which handles the request if no other specific handlers are matched?

  • #2
    handleRequestInternal is called by the super class. The implementation in MultiActionController does the actual dispatching to the appropriate method.

    If it cannot resolve the method to execute it will throw a NoSuchRequestHandlingMethodException.

    Hmm, maybe handleRequestInternal should be final because it really shouldn't be overridden.

    Does that help?

    Comment


    • #3
      The thing which is puzzling me is that I have a class which extends MultiActionController, which used to extend AbstractController instead, and I have just left the 'handleRequestInternal' method in place and it continues to work, even though there is no method name resolver and no mapping defined. That is, the URL ends in /listAccounts.htm, but there is no method 'listAccounts', and yet instead of throwing an error telling me there is no method set up to handle the request, it runs the 'handleRequestInternal' method.

      Comment


      • #4
        Yes, MultiActionController should *always* run handleRequestInternal because it is handleRequestInternal which determines which of *your* methods should be executed.

        If you have written your own handleRequestInternal then it will be called instead of the MultiActionControllers (assuming you are not calling super.handleRequestInternal)

        Have a read of the javadoc


        To be clear; this is *bad*:
        Code:
          public class MyMultiActionController extends MultiActionController {
            public ModelAndView handleRequestInternal(HttpServletRequest req, HttpServletResponse resp) {
             ....
            }
          }
        while this is good:

        Code:
          public class MyMultiActionController extends MultiActionController {
            public ModelAndView yourActionName(HttpServletRequest req, HttpServletResponse resp) {
             ....
            }
          }
        so according to your code you want:

        Code:
          public class MyMultiActionController extends MultiActionController {
            public ModelAndView listAccounts(HttpServletRequest req, HttpServletResponse resp) {
             ....
            }
          }
        Hope this helps

        Comment


        • #5
          Yes it does help, thanks. I've renamed the method to listAccounts and specified a method name resolver to ensure it gets called. It would actually be quite convenient, though, if it were indeed possible to have a fallback or default method which gets used if there is no match on a mapping. The reason why is that I have created a CrudListController, for use in CRUD applications, which extends MultiActionController and is used in producing a list view of different business objects. Certain types of object don't require multiple methods - a simple list of all objects in the database is all that is required (SystemUser, for example), which means a single method will suffice. Having to create a method name resolver and associated mappings for each controller is, of course, no huge task but I am always reluctant to write anything which isn't necessary, because it introduces clutter into the system. I'm sure there is a simple way around this, but I'm not sufficiently familiar with Spring MVC yet to immediately spot it. Does a solution spring to mind?

          Comment


          • #6
            Could you not extend (or wrap) one of the MethodNameResolver implementations and if the Spring one cannot find a method, return the default one.

            Something like:

            Code:
              public final class DefaultMethodNameResolver implements 
            MethodNameResolver {
                private final MethodNameResolver decorated;
                private final String defaultMethod;
            
                public DefaultMethodNameResolver(final MethodNameResolver decoratedResolver, final String theDefaultMethod) {
                    this.resolver = decoratedResolver;
                    this.defaultMethod = theDefaultMethod;
                }
            
                public String getHandlerMethodName(HttpServletRequest request) throws NoSuchRequestHandlingMethodException {
                    String result;
                    try {
                        result = decorated.getHandlerMethodName(request);
                    } catch (final NoSuchRequestHandlingMethodException e) {
                        result = defaultMethod;
                    } 
                    return result;
                  }
               }
            Maybe one of the Spring implementations already does this, not sure

            Comment


            • #7
              Config would be :

              Code:
                <bean id="yourMultiActionController" class="org.spr....MultiActionController"> 
                  <property name="methodNameResolver">
                    <bean class="DefaultMethodNameResolver">
                      <constructor-args index="0">
                        <bean class="org.spring....SomeImplementationOfMethodNameResolver"/>
                      </constructor-args>
                      <constructor-args index="1" value="nameOfTheDefaultMethod"/>
                    </bean>
                  </property>
                </bean>

              Comment


              • #8
                That's great, thanks very much for your help!

                Comment


                • #9
                  My pleasure

                  Comment


                  • #10
                    Originally posted by yatesco
                    Maybe one of the Spring implementations already does this, not sure
                    Yep, ParameterMethodNameResolver.setDefaultMethodName() already does that: "Set the name of the default handler method that should be used when no parameter was found in the request"

                    Comment


                    • #11
                      Originally posted by Aramir
                      Yep, ParameterMethodNameResolver.setDefaultMethodName() already does that: "Set the name of the default handler method that should be used when no parameter was found in the request"
                      That is slightly different

                      The OP wanted a method to be executed if there wasn't a method which matched the *value of the specified parameter* (i.e. ?methodName=noSuchMethod&param1=value1).

                      Code:
                      ParameterMethodNameResolver.setDefaultMethodName()
                      sets the method to be executed if the specified parameter has *no value*.

                      Maybe setDefaultMethodName will work for both. Not sure

                      Comment


                      • #12
                        Originally posted by yatesco
                        Maybe setDefaultMethodName will work for both. Not sure
                        Nah, you're right, my mistake. It only works if there is no parameter. Will throw this no-method-found-exception if the paramether is there but with a wrong method name.

                        However, - this is good, I think. We already lost compile-time checking for missing methods with this model. To loose a runtime checking by not throwing exceptions but falling back to a default method, that would be a *huge* hole for errors. Not good..

                        Comment


                        • #13
                          Originally posted by Aramir
                          We already lost compile-time checking for missing methods with this model. To loose a runtime checking by not throwing exceptions but falling back to a default method, that would be a *huge* hole for errors. Not good..
                          I absolutely agree with you

                          I personally do not like MAC purely because of this looseness of binding. I think it is much better to explicitly map URLs to functional areas, even it is a bit more config.... those "simple" usecases always get a little bit more complex anyway

                          Comment

                          Working...
                          X