I’ve been using Spring with Struts 2 for some time now– I love how it saves me from worrying about object creation and makes my code so much more testable. One recent problem I’ve encountered, though, has led to a bit of a “gotcha” that I hadn’t foreseen.
In general, I’m autowiring my Struts 2 actions by type so that I don’t have to configure beans for actions within my Spring applicationContext.xml. I tried doing this for an action that had two dependencies that I wanted to pass in through the constructor:
this.deviceService = deviceService;
this.fbFacade = fbFacade;
}
Upon executing the action I encountered the following cryptic exception (note spelling mistake):
Not terribly informative. Unfortunately Google searches yielded nothing despite that unique, improperly spelled exception message. I soon learned that any action where I wanted to pass in an IFacebookFacade suffered the same fate. After much investigation I discovered the source of my error: I had another bean defined for a class that was a subclass of an IFacebookFacade implementation in my applicationContext.xml. Thus, Spring found two objects that corresponded to the same interface and wasn’t sure how to autowire by type. It would be helpful if the error message was a little more informative..
Anyhow, the solution I used was to pass the fbFacade into UsersAction by setter injection:
this.deviceService = deviceService;
}
public void setFbFacade(IFacebookFacade fbFacade) {
this.fbFacade = fbFacade;
}
This way, Spring will autowire by name and look for a bean with the same name as the property addressed by the setter. Job done.
Note that you could also resolve this issue by explicity defining a bean for the action in applicationContext.xml, but it is recommended to use declarative ways of specifying dependencies so as to minimise the amount of config in your applicationContext.xml. See this link for more info.