Struts 2 Validation using Annotations

In a week where the Raptors bowed out of the playoffs there was some good news: I was pleasantly surprised how easy it was to get fairly complex server side validation working with Struts 2 by just using annotations. No XML whatsoever. Going into this task I was pretty sure annotations would let me down by having a shortcoming which could only be compensated for by writing validation files, but unlike my attempt at using all annotations for action configuration, this endeavor was successful.

I had written a java.net article about WebWork Validation and everything said there applies here too with the major add-on that we can now use annotations.  So let’s get to an example of visitor field validation where we annotate the properties of a Java bean and have it’s validation rules apply to a form written using <s:form>.  Note that in the same manner we annotate the bean, we an also annotate the actual action class, the concept is similar.

The form has three fields:

  • name: text input
  • gender: select box
  • favoriteTeams: checkbox

This translates to the following HTML form written using Struts tags:

<s:form>
<s:textfield name="person.name" label="'Name'"/>
<s:select name="person.gender" label="'Gender'"
      list="#{'M':'Male', 'F':'Female'}" />
<s:checkboxlist name="person.favoriteTeams"
      list="#{'RAP':'Raptors', 'ARS':'Arsenal'}"
      label="'Teams'"/>
<s:submit cssClass="submit"
      value="'Submit'"/>
</s:form>

In the action class PersonAction, just the following is needed:

@Validation
public class PersonAction extends ActionSupport {

  private Person person;

  // don't provide message, it is supplied by
  // annotations in Person class
  @VisitorFieldValidator(message="")
  public Person getPerson() {
    return person;
  }
  public void setPerson(Person person) {
    this.person = person;
  }

  public String execute() {
    // do processing
    return SUCCESS;
  }
}

Two annotations are needed, the @Validation annotation is needed to tell Struts that actions in this class might need to be validated. The @VisitorFieldValidator is telling Struts that the person object properties need validation. If you had multiple actions mapped to the same action class, all actions would be validated. Now this might not be desirable because if you had say two actions called viewForm and submitForm, you would only want to validate the latter. To get around this problem while still using annotations all we have to do is add the @SkipValidation annotation on the action method:

@SkipValidation
public String viewForm() {
  return SUCCESS;
}

As the name suggests @SkipValidation will bypass validation for calls to this method.

Now we must specify the actual rules for the properties to be validated. This must be done in the Java bean:

@Validation
public class Person {
  private String name;
  private String gender;
  private String[] favoriteTeams;

  @RequiredStringValidator(message="Supply name")
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  @RequiredStringValidator(message="Supply gender")
  public String getGender() {
    return gender;
  }

  public void setGender(String gender) {
    this.gender = gender;
  }

  @RequiredFieldValidator(message="Supply a team")
  public String[] getFavoriteTeams() {
    return favoriteTeams;
  }

  public void setFavoriteTeams(String[] favoriteTeams) {
    this.favoriteTeams = favoriteTeams;
  }

}

It’s a fairly straightforward class where @RequiredStringValidator is used for both the text input and the select box since they can only hold a singular value. The interesting part of this bean is how favoriteTeams is validated. We specify a String[] instead of a String as multiple checkboxes can be selected, Struts is smart enough to populate it properly. The other difference is that @RequiredFieldValidator is specified which enforces at least one checkbox to be selected. As a side-note, when using a radio button you would still use @RequiredStringValidator since only a single value is passed through. A multiple select box would require the use of an array and @RequiredFieldValidator.

A small quirk that I noticed is that even though the @*Validator annotations have a message and a key attribute to specify a message or a resource key, the message attribute is mandatory. So even if you’re specifying a resource key for your validation message, you still have to specify message=””.
The benefit of using visitor field validation is that the same properties can be validated in different actions without writing any new rules. Since the rules (annotations) reside in the Java bean, the Java bean can be specified as a property in different action classes to the same effect.

If you’re looking to perform client-side validation, check out Really easy field validation by Dexagogo, a powerful JavaScript library that’s based on Prototype and happens to be super-easy to use.

About these ads

20 thoughts on “Struts 2 Validation using Annotations

  1. musachy

    by the way Struts 2 also supports some client-side validation. (set validate=”true” on the form tag)

    Reply
  2. arsenalist

    If you’re referring to DWR thats hardly client side. It’s a matter of preference though, I think ‘Really easy field validation’ is too slick and easy to not be used.

    Reply
  3. Dave

    The DWR isn’t, but the JavaScript validation is.

    It can also be very convenient to annotate the Action with validations rather than the bean, because different Actions may expect different bean data.

    Reply
  4. Mohana Priya

    @SkipValidation annotation on the action method doesnt work for me .Validation occurs for all the actions mapped to the same action class. Why so ?

    Reply
  5. rangana

    I have 2 mothods caled edit() and create() I used annotation based validation
    but tthing is i want to validate some of experssions in edit method and some of the in create() method
    cant use @skipValidation in this
    my problem is i can not difine this seperatly in my actiion class ..both methods get validate from all expressions? any 1 have a ida?

    Reply
  6. hildi

    Can we use annotation to dependents fields? For example, if we have to validate fields: “password” and “repeat password”, this values must be the same. How we can do it?
    Thanx!

    Reply
  7. starmer

    Hildi:
    @FieldExpressionValidator(expression = “(confirmPassword == password)”, fieldName = “confirmPassword”, message = “Passwords must match”)

    Reply
  8. ichigo

    Can a message be parameterized in the key attribute?

    like:
    @RequiredFieldValidator(message=””, key=”required.field”)

    and the key with a param:
    required.field = The field {0} is required.

    how can I pass the param?

    Reply
  9. Himanshu Ranavat

    For some people, if the validation does not fire, you want to add the ValidationInterceptor to interceptor stack of the action in the struts action-view xml mapping file

    Reply
  10. Himanshu Ranavat

    To use the SkipValidation you may have to use the AnnotationValidationInterceptor which also extends ValidationInterceptor.

    Reply
  11. kislaychandra

    I am using validation using annotations for a form . And say , there is a field called Nickname . Now this is how the form is :-

    Label for NickName – textbox to Enter the nickname

    Whenever the validation takes place, the error message replaces the label(on the left side of the textbox) . Is there any way to ensure that the label stays put , and the error message is displayed on the right side of the textbox ?

    Reply
  12. SakthiPriya

    Ichigo, Did you get the solution for this?

    Can a message be parameterized in the key attribute?

    like i want to give as
    page.error.required={0} is required

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s