Announcement Announcement Module
Collapse
No announcement yet.
Using Spring 2.5 annotations with struts plugin Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Using Spring 2.5 annotations with struts plugin

    I am trying to convert an application to use spring annotations. However, I have struts 1.3.x in the pictures as well. I have been able to get most of this working except for one thing.

    I added @Controller("myAction") to my action classes and added the following to my action-servlet.xml.

    Code:
    <context:component-scan base-package="com.abc.web.struts.action"/>
    This successfully registers all of my action classes. Now I am trying to map multiple url patterns (aka struts actions) to the same action class. In my action-servlet.xml it would look like this.

    Code:
    <bean name="myAction" class="com.abc.action.MyAction" />
    <bean name="/view" parent="myAction" />
    <bean name="/search" parent="myAction" />
    <bean name="/detail" parent="myAction" />
    So, my thought was to use the @RequestMapping annotation in my action class.

    Code:
    @Controller("myAction")
    @RequestMapping({"/view","/search","/detail"})
    public class MyAction {...}
    As I mentioned earlier the @Controller works fine, but I need to modify how Spring processes the @RequestMapping annotations. Instead of or in addition to creating the HandlerMapping, I need to create a bean definition for each url pattern whose parent bean is 'myAction'.

    I've looked at extending DefaultAnnotationHandlerMapping and injecting the bean creation logic into the determineUrlsForHandler method. However I have not been able to figure out how to register the bean with the context from here.

    Code:
    public class StrutsPluginAnnotationHandlerMapping extends DefaultAnnotationHandlerMapping {
    
        @Override
        protected String[] determineUrlsForHandler(String beanName) {
            String[] urls = super.determineUrlsForHandler(beanName);
            if (urls.length > 0) {
                //Somehow create and register beans
            }
            return urls;
        }
    
    }
    
    Include this in the action-servlet.xml:
    
    <bean id="urlMapping" class="com.abc.web.spring.StrutsPluginAnnotationHandlerMapping"/>
    So, I am looking for some guidance. Is this the best approach to accomplish this, or should I look at injecting this logic somewhere else? How would I register the new beans from this location? Would it be better to extend one of the classes that processes the @Controller annotations (maybe ClassPathBeanDefinitionScanner) that has access to the BeanDefinitionRegistry? If so, how would I tell Spring to use my DefinitionScanner? Do you have any other solutions to consider? Any help is appreciated.

  • #2
    Using Spring 2.5 annotations with struts plugin

    I just had a thought about this. Would it be possible to come at this issue from the other direction. I am using the DelegatingActionProxy in my struts-config.xml. This class grab the application context and looks for a bean with the matching url pattern.

    Would it be possible to extend DelegatingActionProxy and have it act more like Spring MVC and find the proper action bean using the handler mappings? Maybe having the ActionProxy act more like MultiActionController in some way might be an option to solve my problem?

    Maybe someone with some knowledge of the internal workings of Spring MVC could point me in the right direction to accomplish this if it seems like a better solution.

    Comment


    • #3
      Using Spring 2.5 annotations with struts plugin

      I think I have solution. It seems to work properly. However, I'd like to get some feedback on it from someone smarter than me about the internal workings of Spring. I'm looking for a sanity check to make sure I didn't miss something or maybe there is a better way to accomplish this.

      I went with the second option and extended the DelegatingActionProxy and DelegatingTilesRequestProcessor. Here is what I came up with.

      this is my action-servlet.xml entries
      Code:
      <context:component-scan base-package="com.abc.web.struts.action"/>
      
      <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>

      I extended DelegatingActionProxy.
      Code:
      public class AnnotationActionProxy extends DelegatingActionProxy {
      
          @Override
          public ActionForward execute(ActionMapping mapping, ActionForm form,
                  HttpServletRequest request, HttpServletResponse response) throws Exception {
              Action delegateAction = null;
              WebApplicationContext wac = getWebApplicationContext(getServlet(), mapping
                      .getModuleConfig());
              delegateAction = AnnotationActionUtils.getHandler(request, wac);
              if (delegateAction == null) {
                  String beanName = determineActionBeanName(mapping);
                  delegateAction = (Action) wac.getBean(beanName, Action.class);
              }
              return delegateAction.execute(mapping, form, request, response);
          }
      
      }
      I also extended DelegatingTilesRequestProcessor to test that option.
      Code:
      public class AnnotationTilesRequestProcessor extends DelegatingTilesRequestProcessor {
      
          @Override
          protected Action processActionCreate(
                  HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
                  throws IOException {
              Action action = AnnotationActionUtils.getHandler(request, getWebApplicationContext());
              if (action == null) {
                  action = getDelegateAction(mapping);
              }
              if (action != null) {
                  return action;
              }
              return super.processActionCreate(request, response, mapping);
          }
          
      }
      Here's my utility class shared by both of the above classes.
      Code:
      public abstract class AnnotationActionUtils {
      
          private static final Log logger = LogFactory.getLog(AnnotationActionUtils.class);
      
          public static Action getHandler(HttpServletRequest request, ApplicationContext context) {
              Action action = null;
              HandlerExecutionChain handlerChain = null;
              Map<String, HandlerMapping> handlerMap = context.getBeansOfType(HandlerMapping.class);
              for (HandlerMapping handlerMapping : handlerMap.values()) {
                  if (logger.isDebugEnabled()) {
                      logger.debug("Testing handler map [" + handlerMapping + "]");
                  }
                  try {
                      handlerChain = handlerMapping.getHandler(request);
                  } catch (Exception e) {
                      throw new RuntimeException(e.toString(), e);
                  }
                  if (handlerChain != null) {
                      action = (Action) handlerChain.getHandler();
                      if (action != null) {
                          break;
                      }
                  }
              }
              if (logger.isDebugEnabled()) {
                  logger.debug("Action lookup result [" + action + "]");
              }
              return action;
          }
      
      }

      Comment


      • #4
        Since Spring allows multiple aliases for a bean
        e.g.

        Code:
        <bean name="name1,/module1/name1,/module1/name2" ..../>
        I believe the @Controller annotation could also specify multiple aliases in a similar manner. This way Spring should be able to handle it all.

        Code:
         @Controller("name1,/module1/name1,/module1/name2")

        Comment

        Working...
        X