org.springframework.webflow.action
Class FormAction

java.lang.Object
  extended by org.springframework.webflow.action.AbstractAction
      extended by org.springframework.webflow.action.MultiAction
          extended by org.springframework.webflow.action.FormAction
All Implemented Interfaces:
org.springframework.beans.factory.InitializingBean, Action

public class FormAction
extends MultiAction
implements org.springframework.beans.factory.InitializingBean

Multi-action that implements common logic dealing with input forms. This class uses the Spring Web data binding code to do binding and validation.

Several action execution methods are provided:

Since this is a multi-action a subclass could add any number of additional action execution methods, e.g. "setupReferenceData(RequestContext)", or "processSubmit(RequestContext)".

Using this action, it becomes very easy to implement form preparation and submission logic in your flow. One way to do this follows:

  1. Create a view state to display the form. In a render action of that state, invoke setupForm to prepare the new form for display.
  2. On a matching "submit" transition execute an action that invokes bindAndValidate to bind incoming request parameters to the form object and validate the form object.
  3. If there are binding or validation errors, the transition will not be allowed and the view state will automatically be re-entered.
  4. If binding and validation are successful go to an action state called "processSubmit" (or any other appropriate name). This will invoke an action method called "processSubmit" you must provide on a subclass to process form submission, e.g. interacting with the business logic.
  5. If business processing is ok, continue to a view state to display the success view.

Here is an example implementation of such a form flow:

     <view-state id="displayCriteria">
         <on-render>
             <evaluate expression="formAction.setupForm"/>
         </on-render>
         <transition on="search" to="executeSearch">
             <evaluate expression="formAction.bindAndValidate"/>
         </transition>
     </view-state>
 

When you need additional flexibility consider splitting the view state above acting as a single logical form state into multiple states. For example, you could have one action state handle form setup, a view state trigger form display, another action state handle data binding and validation, and another process form submission. This would be a bit more verbose but would also give you more control over how you respond to specific results of fine-grained actions that occur within the flow.

Subclassing hooks:

Note that this action does not provide a referenceData() hook method similar to that of Spring MVC's SimpleFormController. If you wish to expose reference data to populate form drop downs you can define a custom action method in your FormAction subclass that does just that. Simply invoke it as either a chained action as part of the setupForm state, or as a fine grained state definition itself.

For example, you might create this method in your subclass:

 public Event setupReferenceData(RequestContext context) throws Exception {
        MutableAttributeMap requestScope = context.getRequestScope();
        requestScope.put("refData", lookupService.getSupportingFormData());
        return success();
 }
 
... and then invoke it like this:
     <view-state id="displayCriteria">
         <on-render>
             <evaluate expression="formAction.setupForm"/>
             <evaluate expression="formAction.setupReferenceData"/>
         </on-render>
         ...
     </view-state>
 
This style of calling multiple action methods in a chain (Chain of Responsibility) is preferred to overriding a single action method. In general, action method overriding is discouraged.

When it comes to validating submitted input data using a registered Validator, this class offers the following options:

FormAction configurable properties

name default description
formObjectName formObject The name of the form object. The form object will be set in the configured scope using this name.
formObjectClass null The form object class for this action. An instance of this class will get populated and validated. Required when using a validator.
formObjectScope flow The scope in which the form object will be put. If put in flow scope the object will be cached and reused over the life of the flow, preserving previous values. Request scope will cause a new fresh form object instance to be created on each request into the flow execution.
formErrorsScope flash The scope in which the form object errors instance will be put. If put in flash scope form errors will be cached until the next user event is signaled.
propertyEditorRegistrar null The strategy used to register custom property editors with the data binder. This is an alternative to overriding the registerPropertyEditors(PropertyEditorRegistry) hook method.
validator null The validator for this action. The validator must support the specified form object class.
messageCodesResolver null Set the strategy to use for resolving errors into message codes.

Author:
Erwin Vervaet, Keith Donald
See Also:
PropertyEditorRegistrar, DataBinder, ScopeType

Nested Class Summary
 
Nested classes/interfaces inherited from class org.springframework.webflow.action.MultiAction
MultiAction.MethodResolver
 
Field Summary
static String DEFAULT_FORM_OBJECT_NAME
          The default form object name ("formObject").
static String VALIDATOR_METHOD_ATTRIBUTE
          Optional attribute that identifies the method that should be invoked on the configured validator instance, to support piecemeal wizard page validation ("validatorMethod").
 
Constructor Summary
FormAction()
          Bean-style default constructor; creates a initially unconfigured FormAction instance relying on default property values.
FormAction(Class formObjectClass)
          Creates a new form action that manages instance(s) of the specified form object class.
 
Method Summary
 Event bind(RequestContext context)
          Bind incoming request parameters to allowed fields of the form object.
 Event bindAndValidate(RequestContext context)
          Bind incoming request parameters to allowed fields of the form object and then validate the bound form object if a validator is configured.
 ScopeType getFormErrorsScope()
          Get the scope in which the Errors object will be placed.
 Class getFormObjectClass()
          Return the form object class for this action.
 String getFormObjectName()
          Return the name of the form object in the configured scope.
 ScopeType getFormObjectScope()
          Get the scope in which the form object will be placed.
 org.springframework.validation.MessageCodesResolver getMessageCodesResolver()
          Return the strategy to use for resolving errors into message codes.
 org.springframework.beans.PropertyEditorRegistrar getPropertyEditorRegistrar()
          Get the property editor registration strategy for this action's data binders.
 org.springframework.validation.Validator getValidator()
          Returns the validator for this action.
 Event resetForm(RequestContext context)
          Resets the form by clearing out the form object in the specified scope and recreating it.
 void setFormErrorsScope(ScopeType errorsScope)
          Set the scope in which the Errors object will be placed.
 void setFormObjectClass(Class formObjectClass)
          Set the form object class for this action.
 void setFormObjectName(String formObjectName)
          Set the name of the form object in the configured scope.
 void setFormObjectScope(ScopeType scopeType)
          Set the scope in which the form object will be placed.
 void setMessageCodesResolver(org.springframework.validation.MessageCodesResolver messageCodesResolver)
          Set the strategy to use for resolving errors into message codes.
 void setPropertyEditorRegistrar(org.springframework.beans.PropertyEditorRegistrar propertyEditorRegistrar)
          Set a property editor registration strategy for this action's data binders.
 Event setupForm(RequestContext context)
          Prepares a form object for display in a new form, creating it and caching it in the getFormObjectScope() if necessary.
 void setValidator(org.springframework.validation.Validator validator)
          Set the validator for this action.
 String toString()
           
 Event validate(RequestContext context)
          Validate the form object by invoking the validator if configured.
 
Methods inherited from class org.springframework.webflow.action.MultiAction
getMethodResolver, setMethodResolver
 
Methods inherited from class org.springframework.webflow.action.AbstractAction
afterPropertiesSet, execute, getEventFactorySupport
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface org.springframework.beans.factory.InitializingBean
afterPropertiesSet
 

Field Detail

DEFAULT_FORM_OBJECT_NAME

public static final String DEFAULT_FORM_OBJECT_NAME
The default form object name ("formObject").

See Also:
Constant Field Values

VALIDATOR_METHOD_ATTRIBUTE

public static final String VALIDATOR_METHOD_ATTRIBUTE
Optional attribute that identifies the method that should be invoked on the configured validator instance, to support piecemeal wizard page validation ("validatorMethod").

See Also:
Constant Field Values
Constructor Detail

FormAction

public FormAction()
Bean-style default constructor; creates a initially unconfigured FormAction instance relying on default property values. Clients invoking this constructor directly must set the formObjectClass property or override createFormObject(RequestContext).

See Also:
setFormObjectClass(Class)

FormAction

public FormAction(Class formObjectClass)
Creates a new form action that manages instance(s) of the specified form object class.

Parameters:
formObjectClass - the class of the form object (must be instantiable)
Method Detail

getFormObjectName

public String getFormObjectName()
Return the name of the form object in the configured scope.


setFormObjectName

public void setFormObjectName(String formObjectName)
Set the name of the form object in the configured scope. The form object will be included in the configured scope under this name.


getFormObjectClass

public Class getFormObjectClass()
Return the form object class for this action.


setFormObjectClass

public void setFormObjectClass(Class formObjectClass)
Set the form object class for this action. An instance of this class will get populated and validated. This is a required property if you register a validator with the form action (setValidator(Validator))!

If no form object name is set at the moment this method is called, a form object name will be automatically generated based on the provided form object class using ClassUtils.getShortNameAsProperty(java.lang.Class).


getFormObjectScope

public ScopeType getFormObjectScope()
Get the scope in which the form object will be placed.


setFormObjectScope

public void setFormObjectScope(ScopeType scopeType)
Set the scope in which the form object will be placed. The default if not set is flow scope.


getFormErrorsScope

public ScopeType getFormErrorsScope()
Get the scope in which the Errors object will be placed.


setFormErrorsScope

public void setFormErrorsScope(ScopeType errorsScope)
Set the scope in which the Errors object will be placed. The default if not set is flash scope.


getPropertyEditorRegistrar

public org.springframework.beans.PropertyEditorRegistrar getPropertyEditorRegistrar()
Get the property editor registration strategy for this action's data binders.


setPropertyEditorRegistrar

public void setPropertyEditorRegistrar(org.springframework.beans.PropertyEditorRegistrar propertyEditorRegistrar)
Set a property editor registration strategy for this action's data binders. This is an alternative to overriding the registerPropertyEditors(PropertyEditorRegistry) method.


getValidator

public org.springframework.validation.Validator getValidator()
Returns the validator for this action.


setValidator

public void setValidator(org.springframework.validation.Validator validator)
Set the validator for this action. When setting a validator, you must also set the form object class. The validator must support the specified form object class.


getMessageCodesResolver

public org.springframework.validation.MessageCodesResolver getMessageCodesResolver()
Return the strategy to use for resolving errors into message codes.


setMessageCodesResolver

public void setMessageCodesResolver(org.springframework.validation.MessageCodesResolver messageCodesResolver)
Set the strategy to use for resolving errors into message codes. Applies the given strategy to all data binders used by this action.

Default is null, i.e. using the default strategy of the data binder.

See Also:
createBinder(RequestContext, Object), DataBinder.setMessageCodesResolver(org.springframework.validation.MessageCodesResolver)

setupForm

public Event setupForm(RequestContext context)
                throws Exception
Prepares a form object for display in a new form, creating it and caching it in the getFormObjectScope() if necessary. Also installs custom property editors for formatting form object values in UI controls such as text fields.

A new form object instance will only be created (or more generally acquired) with a call to createFormObject(RequestContext), if the form object does not yet exist in the configured scope. If you want to reset the form handling machinery, including creation or loading of a fresh form object instance, call resetForm(RequestContext) instead.

NOTE: This action method is not designed to be overridden and might become final in a future version of Spring Web Flow. If you need to execute custom form setup logic have your flow call this method along with your own custom methods as part of a single action chain.

Parameters:
context - the action execution context, for accessing and setting data in "flow scope" or "request scope"
Returns:
"success" when binding and validation is successful
Throws:
Exception - an unrecoverable exception occurs, either checked or unchecked
See Also:
createFormObject(RequestContext)

bindAndValidate

public Event bindAndValidate(RequestContext context)
                      throws Exception
Bind incoming request parameters to allowed fields of the form object and then validate the bound form object if a validator is configured.

NOTE: This action method is not designed to be overridden and might become final in a future version of Spring Web Flow. If you need to execute custom bind and validate logic have your flow call this method along with your own custom methods as part of a single action chain. Alternatively, override the doBind(RequestContext, DataBinder) or doValidate(RequestContext, Object, Errors) hooks.

Parameters:
context - the action execution context, for accessing and setting data in "flow scope" or "request scope"
Returns:
"success" when binding and validation is successful, "error" if there were binding and/or validation errors
Throws:
Exception - an unrecoverable exception occurred, either checked or unchecked

bind

public Event bind(RequestContext context)
           throws Exception
Bind incoming request parameters to allowed fields of the form object.

NOTE: This action method is not designed to be overridden and might become final in a future version of Spring Web Flow. If you need to execute custom data binding logic have your flow call this method along with your own custom methods as part of a single action chain. Alternatively, override the doBind(RequestContext, DataBinder) hook.

Parameters:
context - the action execution context, for accessing and setting data in "flow scope" or "request scope"
Returns:
"success" if there are no binding errors, "error" otherwise
Throws:
Exception - an unrecoverable exception occured, either checked or unchecked

validate

public Event validate(RequestContext context)
               throws Exception
Validate the form object by invoking the validator if configured.

NOTE: This action method is not designed to be overridden and might become final in a future version of Spring Web Flow. If you need to execute custom validation logic have your flow call this method along with your own custom methods as part of a single action chain. Alternatively, override the doValidate(RequestContext, Object, Errors) hook.

Parameters:
context - the action execution context, for accessing and setting data in "flow scope" or "request scope"
Returns:
"success" if there are no validation errors, "error" otherwise
Throws:
Exception - an unrecoverable exception occured, either checked or unchecked
See Also:
getValidator()

resetForm

public Event resetForm(RequestContext context)
                throws Exception
Resets the form by clearing out the form object in the specified scope and recreating it.

NOTE: This action method is not designed to be overridden and might become final in a future version of Spring Web Flow. If you need to execute custom reset logic have your flow call this method along with your own custom methods as part of a single action chain.

Parameters:
context - the request context
Returns:
"success" if the reset action completed successfully
Throws:
Exception - if an exception occured
See Also:
createFormObject(RequestContext)

toString

public String toString()
Overrides:
toString in class Object