Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-12054

Allow configuring custom redirect prefix in HandlerMethodReturnValueHandler's

    XMLWordPrintable

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Major
    • Resolution: Complete
    • Affects Version/s: 4.0.6
    • Fix Version/s: 4.1 GA
    • Component/s: Web
    • Labels:
      None
    • Last commented by a User:
      true

      Description

      In multiple projects I've implemented custom ViewResolvers that issue redirects based on view names. Similar to how redirect: and forward: works. They've interpreted these view names and built the redirects based on context and various factors such as locale of the logged in user. For instance "my-project:checkout-page" or "project:2156".

      However flash attributes don't work for the redirects these ViewResolvers issue.

      The reason is that the ModelAndViewContainer needs to have redirectModelScenario set in order for them to work. The only place I've found where I can set it is in a HandlerMethodReturnValueHandler. Unfortunately the ViewNameMethodReturnValueHandler eats all returned Strings so I have to extend it and replace the default one with my own. The same goes for ModelAndViewMethodReturnValueHandler. Replacing any of them means explicitly configuring all of the default ones since the custom ones that I could add to RequestMappingHandlerAdapter are executed after the default ones and so can't operate on String or ModelAndViewContainer.

      I've come up with a solution but it's not very elegant so I'm wondering if you know of a better solution. Ideally ViewResolvers should be able to output redirects with flash attributes.

      My solution extends RequestMappingHandlerAdapter and detects whether the returned view name is in a format that will be processed by a custom ViewResolver later. I'm not happy with how the logic for this gets duplicated.

      Attached is maven projects with two DispatcherServlets that illustrate the problem, one where it works and one where it doesn't. It's runnable from command line with mvn jetty:run.

      Here's my custom RequestMappingHandlerAdapter:

      public class CustomRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {
      
          @Override
          public void afterPropertiesSet() {
              super.afterPropertiesSet();
      
              ArrayList<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>(super.getReturnValueHandlers());
              for (int i = 0; i < handlers.size(); i++) {
                  HandlerMethodReturnValueHandler handler = handlers.get(i);
                  if (handler instanceof ViewNameMethodReturnValueHandler) {
                      handlers.set(i, new ViewNameMethodReturnValueHandler() {
      
                          @Override
                          protected boolean isRedirectViewName(String viewName) {
                              return super.isRedirectViewName(viewName) || CustomRequestMappingHandlerAdapter.this.isRedirectViewName(viewName);
                          }
                      });
                  }
                  if (handler instanceof ModelAndViewMethodReturnValueHandler) {
                      handlers.set(i, new ModelAndViewMethodReturnValueHandler() {
      
                          @Override
                          public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
                              if (returnValue != null) {
                                  ModelAndView mav = (ModelAndView) returnValue;
                                  if (mav.isReference()) {
                                      String viewName = mav.getViewName();
                                      if (viewName != null && CustomRequestMappingHandlerAdapter.this.isRedirectViewName(viewName)) {
                                          mavContainer.setRedirectModelScenario(true);
                                      }
                                  }
                              }
                              super.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
                          }
                      });
                  }
              }
              super.setReturnValueHandlers(handlers);
          }
      
          protected boolean isRedirectViewName(String viewName) {
              return viewName.startsWith(CustomRedirectViewResolver.CUSTOM_REDIRECT_PREFIX);
          }
      }
      

        Attachments

          Activity

            People

            Assignee:
            rstoya05-aop Rossen Stoyanchev
            Reporter:
            tmattsson Tobias Mattsson
            Last updater:
            Spring Issues Spring Issues
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:
              Days since last comment:
              3 years, 19 weeks, 4 days ago