Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

This document describes how valiation works in Stripes, how you specify validations, and how ActionBeans interact with validation. It includes the following sections:

Table of Contents
minLevel2
layoutlist
anchortrue

...

All of the error messages in Stripes use java.text.MessageFormat which allows you to provide parameters to be merged in to the message. The first two parameters (0 and 1 respectively) are always the field name and field value respectively. An example follows, but check the individual error class javadocs, and the javadoc for MessageFormat for more details:

Code Block
languagebash
titleExample error message specification
 
myCustomError={0} must be formatted mm/dd/yy. {1} is not a valid date. 

...

Each @Validate can specify multiple validations for a single property. The following example demonstrates how to use the annotations:

Code Block
languagejava
titleUsing Validation Annotations
 
@Validate(required=true, minvalue=13, maxvalue=120) 
private int age; // annotated right on the field 

@ValidateNestedProperties({ 
	@Validate(field="line1", required=true, minlength=5, maxlength=50), 
	@Validate(field="line2", minlength=5, maxlength=50), 
	@Validate(field="zip", required=true, mask="\\d{5}(-\\d{4})?")
}) 
public Address getAddress() { ... } 

...

By default required field validation is applied to all events not marked with @DontValidate. However, by specifying one or more event names in the 'on' attribute it can be restricted to just those events. For example:

Code Block
language
java
@Validate(required=true, on={"save", "update"}) private String description; 
@Validate(required=true, on="delete") private boolean confirm;

The list can also be inverted by supplying event names prefixed with '!'s, for example:

Code Block
languagejava
 
@Validate(required=true, on="!delete") private String description; 
@Validate(required=true, on="delete") private boolean confirm;

...

Some examples are in order:

Code Block
languagejava
// Validate that a number is odd 
@Validate(expression="this % 2 == 1") private int oddNumber; 

// Validate that this number is bigger than the odd number 
@Validate(expression="oddNumber != null && this > oddNumber") private long biggerNumber; 

// Validate that a username is the current user's, or the current user is 'root' 
@Validate(expression="context.user.name=='root' || this==context.user.name") private String name; 

...

The @ValidationMethod annotation has three attributes that allow the application of the method to be altered, all of which are completely optional. The first is the 'when' attribute which allows the developer to specify whether or not the method should be run when errors exist, regardless of the application default policy. E.g.

Code Block
languagejava
 
@ValidationMethod(when=ValidationState.ALWAYS) public void validateSomething { ... } 
@ValidationMethod(when=ValidationState.NO_ERRORS) public void validateSomethingElse { ... } 

The 'on' attribute (similar to the 'on' attribute of @Validate) restricts the method to run only on certain events. By default validation methods are run without regard to the event being handled. The 'on' attribute can specify a single event, a list of events, or one or more events preceeded by '!'s. In the last case the meaning is inverted, and the method is executed on all events except those listed. E.g.

Code Block
languagejava
 
@ValidationMethod(on="create") public void one() { ... } 
@ValidationMethod(on="update") public void two() { ... } 
@ValidationMethod(on={"update","delete"}) public void three() { ... } 
@ValidationMethod(on="!delete") public void four() { ... } 

...

Lastly, it should be noted that there are two ways to get access to the ValidationErrors object in order to save validation error messages. Firstly, as with any other method in the ActionBean, validation methods can call getContext().getValidationErrors() to retrieve the validation errors. However, they may also take the ValidationErrors objects as a parameter, in which case it will be supplied to the method. E.g.

Code Block
language
java
@ValidationMethod public void validateSomething(ValidationErrors errors) { ... } 

...

In these situations you can create validation errors in your handler method, and send the user back to the page they came from (or elsewhere if you choose). The following is an example:

Code Block
languagejava
@HandlesEvent("Withdrawal") 
public Resolution withdrawFunds() { 
	try { 
		getAccount().withdraw( getAmount() ); 
		return new RedirectResolution("/account/summary.jsp"); 
	} 
	catch (InsufficientBalanceException ibe) { 
		ValidationErrors errors = new ValidationErrors(); 
		errors.add( "amount", new LocalizableError("/account/transaction.action.insufficientFunds") ); 
		getContext().setValidationErrors(errors); 
		return getContext().getSourcePageResolution(); 
	} 
} 

Anchor
Selectively Disabling Validation
Selectively Disabling Validation

...

(Required scripts available at http://stripes-stuff.svn.sourceforge.net/viewvc/stripes-stuff/JavaScript/trunk/scripts/jquery/)

Code Block
languagexml
<s:field-metadata var="fieldMetadata"> 
$(function(){applyStripesValidation('${fieldMetadata.formId}', ${fieldMetadata});}); 
</s:field-metadata> 

...

Note: visit the above link for updates and improvements. The code below is a skeletal example for illustration:

Code Block
language
js
/** 
 * 
 * Jquery addapter class so we can use built in Jquery validator. 
 * NOTE: this is only skeleton, implementing only small part of possible validation, 
 * Usage: 
 * &lt;s:field-metadata var="metaData"&gt; 
 * $(function(){$.fn.stripesValidation('${metaData.formId}', ${metaData});}); 
 * &lt;/s:field-metadata&gt; 
 * dependancies: 
 * jquery.1.3.1 
 * jquery.form 
 * jquery.validate 
 */ 
(function($){ 

	/** 
	 * Processess Stripes meta data and converting it so jquery 
	 * validation plugin is used for client side validation 
	 * @param formId id of a form to be processed 
	 * @param metaData metadata that is produced by stripes tag 
	 */ 
	$.fn.stripesValidation = function(formId, metaData) { 
		var form = $('#' + formId); 
		var mask_count = 0; 
	for (var fieldName in metaData) { 
		var field = form.find('[name=' + fieldName + ']'); 
		addValidation(field, metaData[fieldName]); 
		// run validation: 
		form.validate(); 
	} 

	function addValidation(field, obj) { 
		for (var prop in obj) { 
			debug(prop); 
			switch(prop){ 
				case 'label': 
					break; 
				case 'required': 
					if (obj[prop]) { // add only if true 
						field.addClass(prop); 
}					} 
					break; 
				case 'minlength': // should already be there 
					field.attr(prop, obj[prop]); 
					break; 
				case 'maxlength': // should already be there 
					field.attr(prop, obj[prop]); 
					break; 
				case 'mask': 
					setMask(field, obj[prop]); 
					break; 
				case 'typeConverter': 
					setConverter(field, obj[prop]); 
					break; 
				default: 
					debug('missing this:' + prop + ':' + [obj[prop]]); 
			} 
		}


	} 

	/** 
	 * Adds regular expression validation 
	 * @param field field reference 
	 * @param mask regular expression mask 
	 */ 
	function setMask(field, mask) { 
		mask_count++; 
		var methodRef = 'maskMethod' + mask_count; 
		field.addClass(methodRef); 
		$.validator.addClassRules({ 
			methodRef: { 
				methodRef: true 
			} 
		}); 
		$.validator.addMethod(methodRef, function (value) { 
			return mask.test(value); 
		}, 'Value is invalid'); 
	} 

	/** 
	 * Add converter mappings 
	 * @param field field reference 
	 * @param converter converter used by stripes for given field 
	 */ 
	function setConverter(field, converter) { 
		if (converter == 'EmailTypeConverter') { 
			field.addClass('email'); 
		} 
		else { 
			debug('missing converter mapping:' + converter); 
		} 
	} 

	function debug(msg){ 
		if (window.console && window.console.log) { 
			window.console.log(msg); 
		} 
	} 

}; 
})(jQuery);