Many of the action bean annotations are related to dependency injection navigation. In this section we look at annotations supplied with Strecks which are also used in action beans, but are not related to dependency injection or navigation.
The @Controller
annotation is necessary for every action bean because it
identifies the controller action which will execute the action bean's methods.
The controller action identified using this annotation must be interface compatible with
the action bean. Every controller action defines an interface which collaborating
action beans must implement. The action bean which attempts to use this
controller action must implement the interface.
Consider for example the following action bean:
@Controller(name = BasicController.class) public class ExampleBasicAction implements BasicAction { public String execute() { return "success"; } }
The action bean implements the interface BasicAction
. This corresponds with the
BasicController
's @ActionInterface
annotation,
which specifies the interface
that the action bean should implement, as shown below:
@ActionInterface(name = BasicAction.class) public class BasicController extends BaseBasicController { protected ViewAdapter executeAction(Object actionBean, ActionContext context) { //implementation omitted } }
Location | Class declaration |
Purpose | Identify the controller implementation class |
Usage |
Every action bean needs to contain a @Controller annotation
|
The @InitMethod
annotation is used to indicate an action bean method which should be executed
after dependencies have been injected, but before any interceptors or action bean interface
methods are called. The method annotated using the @InitMethod
annotation must
return void and cannot define parameters. The init method can be used to perform post-dependency
injection initialisation tasks. A (rather trivial) example is shown below:
@Controller(name = BasicController.class) public class ExampleLifecycleAction implements BasicAction { private static int initCount; @InitMethod public void init() { initCount++; } public String execute() { return "success"; } public String getMessage() { return "init() called " + initCount; } }
Note that in this example, the initCount
field is static because the action bean
is instantiated on a per-request basis.
The @InitMethod
annotation does not take any parameters.
The @CloseMethod
annotation is the analogue of the
@InitMethod
annotation. It is executed after the action bean methods as well as
any post-execution interceptors are called. Also, it will always be called. For
example, if one of the post-execution interceptors throws an exception, this
will be logged, but the subsequent close method will still be called. An example is
shown below.
@Controller(name = BasicController.class) public class ExampleLifecycleAction implements BasicAction { private static int closeCount; public String execute() { return "success"; } public String getMessage() { return "close() called " + closeCount; } @CloseMethod public void close() { closeCount++; } }
Like @InitMethod
annotation,
the @CloseMethod
annotation does not take any parameters.
Struts includes a LookupDispatchAction
which is useful in handling submission
of forms containing multiple buttons. When using LookupDispatchAction
, you need to
implement an abstract getKeyMethodMap()
to determine a mapping from
message keys (used to name the buttons) to method names.
Streck's replacement for LookupDispatchAction
is through the use of controllers
which implement the LookupDispatchActionController
interface. Two implementations are
provided:
BasicLookupDispatchController
and NavigableLookupDispatchController
.
Action beans which use these controllers define a message key to method mapping not through
an abstract method implementation, but through the use of the @DispatchMethod
annotation.
An example is shown below, with method implementations omitted:
@Controller(name = NavigableLookupDispatchController.class) public class ExampleNavigableLookupSubmitAction implements NavigableSubmitAction { public void preBind() { } public void execute() { } @DispatchMethod(key = "button.add") public void insert() { } @DispatchMethod(key = "button.delete") public void delete() { } public void cancel() { } @NavigateForward public String getResult() { return "success"; } }
Location | Method to be executed in multi-button form |
Purpose | Executes request processing logic specific to one of the buttons in a multi-button form |
Usage |
In action beans which use NavigableLookupDispatchController
or BasicLookupDispatchController
as action controllers
|
Strecks provides mechanisms not only for action beans to be injected with Spring beans,
but also for action beans themselves to be Spring beans. This is achieved
using the @SpringBean
annotation, as shown in the example below:
@Controller(name = BasicController.class) @SpringBean(name = "springActionBean") public class SpringControlledAction implements BasicAction { private String message; private SpringService springService; public String execute() { //execute SpringService methods } public void setSpringService(SpringService service) { this.springService = service; } }Note the absence of the
@InjectSpringBean
annotation for setSpringService()
.
This is because dependency injection of Spring beans is provided by the Spring
container. Note that use of Spring beans as action beans does not stop any
of the Strecks annotation-based dependency injectors from being used.
The Spring application context needs to be initialized
using an entry such as the following in web.xml.
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-context.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>
Of course, the Spring configuration file needs a bean entry corresponding
with the name used in the @SpringBean
annotation.
The bean needs to be defined as a non-singleton
(i.e. with singleton = "false"
)
Location | Class declaration |
Purpose | Identify the action bean as a Spring action bean |
Usage | The Spring application context must be present. The action bean must be configured as a non-singleton Spring bean in the Spring application context, under the name used in the annotation |