11. Example 09 - Conversion and validation of integers
We will now look at a series of examples on converting and validating form parameters. The problem is as follows. To process a URL of the form [http://machine:port/.../Action], the [FilterDispatcher] controller instantiates the class that implements the requested action and executes one of its methods—by default, the method called execute. The call to this execute method passes through a series of interceptors:
![]() |
The list of interceptors is defined in the [struts-default.xml] file at the root of the [struts2-core.jar] archive. The list of interceptors defined there is as follows:
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
Among the interceptors, there is one that is responsible for injecting the values of the parameters accompanying the request into the action in the form parami=values. We know that values will be injected into the parami field of the action via the setParami method if it exists. Otherwise, no injection occurs and no error is reported.
The string parami=values is a character string. So far, the injection of values has been performed into parami fields of type String:
Injecting the string valeuri as the value of the parami string posed no problem. If parami is not of type String, then valeuri must be converted to the type Ti of parami. This is the conversion problem. For example, we might want an age to be an integer and write in the action:
Furthermore, we might want to restrict the age to between 1 and 150. This presents a validation issue. The parami parameter can be converted to the correct type without necessarily being valid. There are therefore two steps to complete. Returning to the request processing diagram:
![]() |
Two interceptors will handle the conversion and validation of the parameters, respectively. If either step fails, the request does not proceed to the action (red path above). The form from which the incorrect parameters were submitted is redisplayed with error messages.
The interceptors involved in parameter conversion and validation are the conversionError and validation interceptors on lines 19 and 20 of the interceptor list shown earlier. Note on lines 20–22 that the validation interceptor is not applied if the called method is one of the input, back, cancel, or browse methods. We will use this property later on.
We’ll start by examining the conversion and validation of integers. We’ll spend some time on this first example because the validation involves many elements. Once we understand these, we’ll move more quickly through the examples that follow.
11.1. The form
![]() |
- in [1], the input form
- in [2], the result when validating without entering any values
11.2. The NetBeans project
The NetBeans project is as follows:
![]() |
- in [1], the three views of the application
- in [2], the source code, the internationalized message files, and the Struts configuration files.
11.3. Struts Configuration
The application is configured by the [struts.xml] and [example.xml] files.
The [struts.xml] file is as follows:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.custom.i18n.resources" value="messages" />
<include file="example/example.xml"/>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">Home</param>
<param name="namespace">/example</param>
</result>
</action>
</package>
</struts>
Lines 12–18 define the [/example/Home] action as the default action when the user does not specify one.
The [example.xml] file is as follows:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Home">
<result name="success">/example/Home.jsp</result>
</action>
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Home.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
</package>
</struts>
- Lines 8–10: The [Home] action displays the [Home.jsp] view
- line 11: the [FormInt] action executes the execute method of the [example.FormInt] class by default. We will see that two other methods will be executed: the input and cancel methods. These methods will then be specified in the request parameters.
- line 12: the input key will display the [FormInt.jsp] view (line 5). This view is the form view.
- line 13: the cancel key will be returned by a cancel method associated with the [Cancel] link. The view rendered will then be the [Home.jsp] view after a redirect (type=redirect).
- Line 14: The `success` key is returned by the `execute` method of the [FormInt] action. If the request reaches the `execute` method, it means it has successfully passed through all interceptors, particularly those that verify the validity of the parameters. The `execute` method then simply returns the `success` key, which will display the confirmation view [ConfirmationInt.jsp].
11.4. Message files
The [messages.properties] file is as follows:
Home.title=Home
Home.title=Struts 2 - Conversions and Validations
Home.FormInt=Enter integers
Form.title=Conversions and validations
FormInt.message=Struts 2 - Integer conversion and validation
Form.submitText=Validate
Form.cancelText=Cancel
Form.clearModel=Clear model
Confirmation.title=Confirmation
Confirmation.message=Confirmation of entered values
Confirmation.field=field
Confirmation.value=value
Confirmation.link=Test form
In addition to this file, the views use the following [FormInt.properties] file:
int1.prompt=1-Two-digit positive integer
int1.error=Enter a two-digit positive integer
int2.prompt=2-Integer
int2.error=Enter an integer
int3.prompt=3-Integer >=-1
int3.error=Enter an integer >= -1
int4.prompt=4-Integer <=10
int4.error=Enter an integer <=10
int5.prompt=5-Integer in the range [1,10]
int5.error=Enter an integer in the range [1,10]
int6.prompt=6-Integer in the range [2,20]
int6.error=Enter an integer in the range [2,20]
The [FormInt.properties] file is only used when the action that generated the view is the [FormInt] action. This is a way to split the message file if it becomes too large. The messages for the Action action are localized in the [Action.properties] file.
11.5. Views and Actions
We will now present the views and actions of the application. Based on the application configuration:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="Home">
<result name="success">/example/Home.jsp</result>
</action>
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Home.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
</package>
</struts>
We can see that there are three views [Home.jsp, FormInt.jsp, ConfirmationFormInt.jsp] and two actions [Home, FormInt].
11.5.1. Home.jsp
The view [Home.jsp] is as follows:

Its code is as follows:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Home.title"/></title>
<s:head/>
</head>
<body background="<s:url value="/resources/standard.jpg"/>">
<h2><s:text name="Home.message"/></h2>
<ul>
<li>
<s:url id="url" action="FormInt!input"/>
<s:a href="%{url}"><s:text name="Home.FormInt"/></s:a>
</li>
</ul>
</body>
</html>
The link on line 14 generates the following HTML code:
<a href="<a href="view-source:http://localhost:8084/exemple-09/example/FormInt.action">/exemple-09/example/FormInt!input.action</a>">Enter integers</a>
This is therefore a link to the [FormInt] action configured as follows in [example.xml]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Home.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
Clicking the link will instantiate the [example.FormInt] class and execute its input method. Since it does not exist, the input method of the parent ActionSupport class will be executed. This method does nothing except return the input key. Therefore, the [/example/FormInt.jsp] view will be displayed.
Furthermore, the input method is one of the methods ignored by the validation interceptor:
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
Therefore, there will be no parameter validation. This is important because there are no parameters here, and we will see later that the validation rules require the presence of six parameters.
11.5.2. The [FormInt] action
The [FormInt] action is associated with the following [FormInt] class:
package example;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
import org.apache.struts2.interceptor.validation.SkipValidation;
public class FormInt extends ActionSupport implements ModelDriven, SessionAware {
// constructor without parameters
public FormInt() {
}
// action model
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
public String cancel() {
// clear the model
((FormIntModel) getModel()).clearModel();
// result
return "cancel";
}
@SkipValidation
public String clearModel() {
// Clear the model
((FormIntModel) getModel()).clearModel();
// result
return INPUT;
}
// SessionAware
private Map<String, Object> session;
public void setSession(Map<String, Object> session) {
this.session = session;
}
// validation
@Override
public void validate() {
// Is the int6 input valid?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
}
}
We will comment on this code as needed. For now:
- line 9, the [FormInt] class implements two interfaces:
- ModelDriven, which has only one method, getModel on line 16
- SessionAware, which has only one method, setSession on line 41
- lines 16–21: implementation of the ModelDriven interface. Recall that this interface allows the model of a view to be delegated to an external class, in this case the following [FormIntModel] class:
package example;
public class FormIntModel {
// constructor without parameters
public FormIntModel() {
}
// form fields
private String int1;
private Integer int2;
private Integer int3;
private Integer int4;
private Integer int5;
private String int6;
// clear model
public void clearModel(){
int1 = null;
int2 = null;
int3 = null;
int4 = null;
int5 = null;
int6 = null;
}
// getters and setters
...
}
The [FormIntModel] model has six fields corresponding to the six input fields in the [FormInt.jsp] view. These six fields will receive the posted values. Four of them are of type Integer. Therefore, the issue of converting String to Integer will arise for them. The clearModel method allows you to reset the model.
Let’s return to the getModel method of the [FormInt] action:
// action model
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
- Lines 3–5: The model is retrieved from the session. If it is not there, an instance of the model is created and placed in the session.
- Line 6: While an instance of the action is created with each new request made to the action, its model remains in the session.
We see that the class does not define an input method, but the parent class has one that returns the input key. Executing this method displays the [FormInt.jsp] view, which we will now present.
11.5.3. The [FormInt.jsp] view
The [FormInt.jsp] view is as follows:
![]() |
- in [1], the blank form
- in [2], the form after validation of incorrect parameters.
Its code is as follows:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Form.title"/></title>
<s:head/>
</head>
<body background="<s:url value="/resources/standard.jpg"/>">
<h2><s:text name="FormInt.message"/></h2>
<s:form name="form" action="FormInt">
<s:textfield name="int1" key="int1.prompt"/>
<s:textfield name="int2" key="int2.prompt"/>
<s:textfield name="int3" key="int3.prompt"/>
<s:textfield name="int4" key="int4.prompt"/>
<s:textfield name="int5" key="int5.prompt"/>
<s:textfield name="int6" key="int6.prompt"/>
<s:submit key="Form.submitText" method="execute"/>
</s:form>
<br/>
<s:url id="url" action="FormInt" method="cancel"/>
<s:a href="%{url}"><s:text name="Form.cancelText"/></s:a>
<br/>
<s:url id="url" action="FormInt" method="clearModel"/>
<s:a href="%{url}"><s:text name="Form.clearModel"/></s:a>
</body>
</html>
- lines 12–17: the six input fields corresponding to the six fields of the [FormIntModel] model for the [FormInt] action. When the view is displayed, the value attributes of the input fields are used for the values displayed by these fields. If the value attribute is missing, then the name attribute is used.
- line 12: the input field is associated (name) with the int1 field of the action or its model if the action implements the ModelDriven interface. This is the case here. This is also true for all other fields.
- Line 18: The [Submit] button posts the entries to the [FormInt] action defined on line 11. Its execute method will be executed.
- Lines 21–22: The [Cancel] link executes the [FormInt.cancel] method.
- Lines 24–25: The [Clear Model] link executes the [FormInt.clearModel] method.
11.5.4. The [ConfirmationFormInt.jsp] view
![]() |
It is displayed when all entries in the [FormInt.jsp] form are valid.
- In [1], valid values are submitted
- In [2], the confirmation page
The code for the [ConfirmationInt.jsp] view is as follows:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="Confirmation.title"/></title>
<s:head/>
</head>
<body background="<s:url value="/resources/standard.jpg"/>">
<h2><s:text name="Confirmation.message"/></h2>
<table border="1">
<tr>
<th><s:text name="Confirmation.field"/></th>
<th><s:text name="Confirmation.value"/></th>
</tr>
<tr>
<td><s:text name="int1.prompt"/></td>
<td><s:property value="int1"/></td>
</tr>
<tr>
<td><s:text name="int2.prompt"/></td>
<td><s:property value="int2"/></td>
</tr>
<tr>
<td><s:text name="int3.prompt"/></td>
<td><s:property value="int3"/></td>
</tr>
<tr>
<td><s:text name="int4.prompt"/></td>
<td><s:property value="int4"/></td>
</tr>
<tr>
<td><s:text name="int5.prompt"/></td>
<td><s:property value="int5"/></td>
</tr>
<tr>
<td><s:text name="int6.prompt"/></td>
<td><s:property value="int6"/></td>
</tr>
</table>
<br/>
<s:url id="url" action="FormInt" method="input"/>
<s:a href="%{url}"><s:text name="Confirmation.link"/></s:a>
</body>
</html>
To understand this code, remember that the view is displayed after the [FormInt] class is instantiated. The fields of this class and its model [FormIntModel] are therefore accessible to the view.
- lines 16–38: the values of the six fields are displayed
- lines 42-43: a link to the [FormInt] action. The code generated for this link is as follows:
<a href="/exemple-09/example/FormInt!input.action">Test form</a>
The specific URL of the link indicates that the input method of the [FormInt] action must handle the request. Recall the configuration of the [FormInt] action in [example.xml]:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Home.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
The input method of the [FormInt] class will be that of its parent class, ActionSupport. The input method of the [FormInt] class is executed after the interceptors have been executed
![]() |
We know that the call to the input method is ignored by the validation interceptor. Therefore, there will be no validation.
The [FormInt.jsp] view is displayed:
![]() |
In [2], the input fields revert to their default values. This may seem normal, but it isn’t. Since the [FormInt] action was called, the associated [FormInt] class was instantiated. Because this class implements the ModelDriven interface, its getModel method was called:
// action model
public Object getModel() {
if (session.get("model") == null) {
session.put("model", new FormIntModel());
}
return session.get("model");
}
We can see that the action's model is retrieved from the session. In the previous step, this model was updated with the posted values. We therefore retrieve these values. If we hadn't put the model in the session, we would have had six empty fields in the [FormInt.jsp] view.
11.5.5. The [FormInt!clearModel] action
The [FormInt!clearModel] action is triggered by clicking the [Clear Model] link:
![]() |
- in [1], the form after an incorrect entry
- in [2], the form after clicking the [Clear Model] link.
The [FormInt.clearModel] method is as follows:
@SkipValidation
public String clearModel() {
// reset the model
((FormIntModel) getModel()).clearModel();
// result
return INPUT;
}
- line 1: there is no validation to perform. We use the @SkipValidation annotation to indicate this. The validation interceptor will therefore not perform any validations.
- line 4: the [FormIntModel].clearModel method is executed. We have already encountered it. It resets the six fields of the model to null.
- line 7: the method returns the input key.
Returning to the configuration of the [FormInt] action:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Home.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
We can see that the input key will display the [FormInt.jsp] view. This view displays the six fields of the model. Since these are null, the view displays six empty fields [2].
11.5.6. The [FormInt!cancel] action
The [FormInt!cancel] action is triggered by clicking the [Cancel] link:
![]() |
- in [1], the form after an incorrect entry
- in [2], the home page after clicking the [Cancel] link.
The [FormInt.cancel] method is as follows:
public String cancel() {
// clear the model
((FormIntModel) getModel()).clearModel();
// result
return "cancel";
}
- line 1: Note that the method is not preceded by the SkipValidation annotation. However, we do not want to perform validations. The cancel method is one of the four methods (input, back, cancel, browse) ignored by the validation interceptor, so the SkipValidation annotation is not necessary.
- line 3: this clears the model
- line 5: it returns the cancel key
Returning to the configuration of the [FormInt] action:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Home.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
We can see that the "cancel" key will display the [Home.jsp] view after a client-side redirect. This is shown in view [2].
11.6. The validation process
We will now address the validation of the six input fields associated with the following six fields in the model:
// form fields
private String int1;
private Integer int2;
private Integer int3;
private Integer int4;
private Integer int5;
private String int6;
This validation occurs every time the [FormInt] class is instantiated and the executed method is not ignored by the validation interceptor. It is controlled by:
- the [FormInt-validation.xml] file, if it exists in the same folder as the [FormInt] class
- the [FormInt.validate] method, if it exists.
![]() |
- in [1]: the [xwork-validator-1.0.2.dtd] file required for the validation process
- in [2]: the [FormInt-validation.xml] file in the same folder as the [FormInt] class
The [FormInt-validation.xml] file is as follows:
<!--
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//
EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
-->
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//
EN" "http://localhost:8084/exemple-09/example/xwork-validator-1.0.2.dtd">
<validators>
<field name="int1" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int1.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{2}$</param>
<param name="trim">true</param>
<message key="int1.error"/>
</field-validator>
</field>
<field name="int2" >
...
</field>
...
</validators>
- in [3], the URL of the DTD (Document Type Definition) for the validation file. This must be accessible; otherwise, the validation file will not be used.
- in [7], the URL of the DTD used by the application. We have placed the DTD file in the [example] folder of the example-09 project [1] so that it is available even if there is no Internet access.
- Lines 11–20: Set the validation conditions for the int1 parameter associated with the int1 field in the model.
The tag named int1 in the form is as follows:
<s:textfield name="int1" key="int1.prompt" />
The int1 field in the model is declared as follows:
<div class="odt-code-rich" data-linenums="false" style="counter-reset: odtline 0;"><pre><code class="language-text">
<span class="odt-code-line"><span style="font-weight:bold;color:#7f0055">private </span><span style="color:#000000">String int1;</span></span>
</code></pre></div>
- Lines 12–14: verify that the int1 parameter exists (is not null) and has a non-zero length. If this is not the case, an error message is associated with the input field. It is defined in [FormInt.properties] as follows:
int1.error=Enter a two-digit positive integer
If there is an error, the validation process for the int1 parameter stops (short-circuit=true).
- Lines 15–19: The validity of the int1 parameter is checked using a regular expression.
- Line 16: The regular expression, in this case two digits with nothing before or after.
- line 17: Before being compared to the regular expression, the int1 parameter will have its leading and trailing spaces removed.
- Line 18: The error message, if any. It is the same as for the previous validator.
Let's see how this works:
![]() |
- in [1], an incorrect entry for the int1 field
- in [2], the page returned:
- The error message for the int1.error key is displayed. It is in red.
- The label of the incorrect field is also in red.
- The incorrect entry is displayed again. This must be anticipated because it is not necessarily the default behavior.
We have seen that form validation triggers the execution of the [FormInt].execute method if the request manages to pass through all the interceptors, particularly the validation interceptor:
![]() |
- If the request reaches the action’s execute method, it returns the success key to the controller, as we have seen.
- If the validation interceptor stops the request because the tested parameters are invalid, then the `input` key is returned to the controller.
Since the [FormInt] action is configured as follows:
<action name="FormInt" class="example.FormInt">
<result name="input">/example/FormInt.jsp</result>
<result name="cancel" type="redirect">/example/Home.jsp</result>
<result name="success">/example/ConfirmationFormInt.jsp</result>
</action>
When there is a validation error, the [FormInt.jsp] view is displayed, i.e., the form. Struts tags are designed to display any error messages associated with them. We will therefore see the [FormInt.jsp] view with error messages attached to the various fields. This is shown in view [2].
Let’s now examine the validation of the int2 field, declared as follows in the model:
private Integer int2;
The validation of the int2 field in [FormInt-validation.xml] is as follows:
<field name="int2" >
<field-validator type="required" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
</field>
- Lines 2–4: verify that the int2 parameter exists.
- lines 5-7: verify that the String-to-Integer conversion is possible
- Lines 3, 6: The error message for the int2.error key is as follows:
int2.error=Enter an integer
The validation for the Integer field int3 in the model in [FormInt-validation.xml] is as follows:
<field name="int3" >
<field-validator type="required" short-circuit="true">
<message key="int3.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">-1</param>
<message key="int3.error"/>
</field-validator>
</field>
- Lines 8–11: verify that the int3 field is an integer >= -1
- Lines 3, 7: The error message for the int3.error key is as follows:
int3.error=Enter an integer >=-1
The validation of the Integer field int4 in the model in [FormInt-validation.xml] is as follows:
<field name="int4" >
<field-validator type="required" short-circuit="true">
<message key="int4.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="max">10</param>
<message key="int4.error"/>
</field-validator>
</field>
- lines 8-11: verify that it is an integer <=10
- Lines 3, 7: The error message for the int4.error key is as follows:
int4.error=Enter an integer <=10
The validation for the Integer field int5 in the model in [FormInt-validation.xml] is as follows:
<field name="int5" >
<field-validator type="required" short-circuit="true">
<message key="int5.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">1</param>
<param name="max">10</param>
<message key="int5.error"/>
</field-validator>
</field>
- Lines 5–9: verify that the value is an integer in the range [1, 10].
- Lines 3, 8: The error message for the int5.error key is as follows:
int5.error=Enter an integer in the range [1,10]
The validation for the String int6 field in the model in [FormInt-validation.xml] is as follows:
<field name="int6" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int6.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{1,2}$</param>
<param name="trim">true</param>
<message key="int6.error"/>
</field-validator>
</field>
- Lines 5–9: verify that int6 is a 2-digit string.
- Lines 3, 8: The error message for the int6.error key is as follows:
int6.error=Enter an integer in the range [2,20]
The previous validation does not check that the int6 parameter is an integer in the range [2,20]. This check is performed in the [FormInt].validate method, which is executed after the [FormInt-validation.xml] file has been processed. This method is as follows:
// validation
@Override
public void validate() {
// Is the int6 input valid?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
}
- Line 5: We check if there are any errors associated with the int6 field. If so, we stop here.
- line 6: if there were no errors, we retrieve the int6 String field from the model and convert it to an integer.
- line 7: We verify that the retrieved integer is in the range [2,20].
- line 8: if this is not the case, an error message is attached to the int6 field. This error message is retrieved from the messages file using the key int6.error.
If errors are found at the end of this validation process, the call to the [FormInt].execute method is terminated, and the input key is returned to the Struts controller.
![]() |
11.7. Final Details
We have seen several ways to enter integers. They are not all equivalent. Consider, for example, the int5 and int6 input fields:
In the [FormInt.jsp] view, they are declared as follows:
<s:textfield name="int5" key="int5.prompt"/>
<s:textfield name="int6" key="int6.prompt"/>
Their model is declared in [FormIntModel.java]:
private Integer int5;
private String int6;
The int5 field is of type Integer, while the int6 field is of type String. Their validation rules are different:
<field name="int5" >
<field-validator type="required" short-circuit="true">
<message key="int5.error"/>
</field-validator>
<field-validator type="conversion" short-circuit="true">
<message key="int2.error"/>
</field-validator>
<field-validator type="int" short-circuit="true">
<param name="min">1</param>
<param name="max">10</param>
<message key="int5.error"/>
</field-validator>
</field>
<field name="int6" >
<field-validator type="requiredstring" short-circuit="true">
<message key="int6.error"/>
</field-validator>
<field-validator type="regex" short-circuit="true">
<param name="expression">^\d{1,2}$</param>
<param name="trim">true</param>
<message key="int6.error"/>
</field-validator>
</field>
Validation of the int6 field is performed by the validate method of the [FormInt] action:
public void validate() {
// Is the int6 input valid?
if (getFieldErrors().get("int6") == null) {
int int6 = Integer.parseInt(((FormIntModel) getModel()).getInt6());
if (int6 < 2 || int6 > 20) {
addFieldError("int6", getText("int6.error"));
}
}
Although expressed differently, both validation rules aim to verify that the entered value is an integer within a specified range. However, the behavior of the int5 and int6 fields differs at runtime, as shown in the following screenshots:
![]() |
- in [1], the same incorrect entry for both fields
- in [2], the error page returned. The two fields have different error messages.
- In [3], an unwanted message appears for the int5 field because it is in English. It results from the failed String-to-Integer conversion. There is also an exception in the Apache logs:
Curiously enough, Struts looked for a method FormIntModel.setInt5(String value) but couldn't find it.
The key for the error message is xwork.default.invalid.fieldvalue. To translate it into French, simply associate a French text with this key. We therefore add the following line to the [messages.properties] file:
...
xwork.default.invalid.fieldvalue=Invalid value for the "{0}" field.
11.8. Conclusion
This concludes our study of this first application dedicated to parameter validation. It was complex to explain. We will now examine similar applications. Therefore, we will only comment on what has changed.














