Integrate ZK with JSR 303: Bean Validation"

From Documentation
(12 intermediate revisions by the same user not shown)
Line 4: Line 4:
 
|version=ZK 5.0.7
 
|version=ZK 5.0.7
 
}}
 
}}
 
{{Template:UnderConstruction}}
 
  
 
==What is JSR 303: Bean Validation==
 
==What is JSR 303: Bean Validation==
 
JSR 303 is a standard designed for working on property validation in Java beans. In brief, the constraints of a bean property are specified by Java annotations, and validation against the bean can be invoked by API.
 
JSR 303 is a standard designed for working on property validation in Java beans. In brief, the constraints of a bean property are specified by Java annotations, and validation against the bean can be invoked by API.
  
See also: [http://people.redhat.com/~ebernard/validation/ JSR 303 Documentation]
+
A known implementation of JSR 303 is [http://docs.jboss.org/hibernate/validator/4.0.1/reference/en/html_single/ Hibernate Validator]. In the following section we will use Hibernate Validator to demonstrate how to utilize this tool in a ZK application.
  
  
Line 51: Line 49:
 
 
 
 
 
==How to use Bean Validation in your ZK application==
 
==How to use Bean Validation in your ZK application==
 +
The following is a step-by-step guide to show a simple integration of JSR 303 with data binding.
  
 +
===Required Jars===
 +
The following is a sample dependency list for setting up Hibernate Validator to work with data binding:
 +
<source lang="xml">
 +
<!-- required for data binding -->
 +
<dependency>
 +
<groupId>org.zkoss.zk</groupId>
 +
<artifactId>zkplus</artifactId>
 +
<version>5.0.7</version>
 +
</dependency>
 +
 +
<dependency>
 +
<groupId>org.hibernate</groupId>
 +
<artifactId>hibernate-validator</artifactId>
 +
<version>4.0.2.GA</version>
 +
</dependency>
 +
<dependency>
 +
<groupId>org.slf4j</groupId>
 +
<artifactId>slf4j-api</artifactId>
 +
<version>1.6.1</version>
 +
</dependency>
 +
<dependency>
 +
<groupId>org.slf4j</groupId>
 +
<artifactId>slf4j-log4j12</artifactId>
 +
<version>1.6.1</version>
 +
</dependency>
 +
</source>
 +
Hibernate Validator assumes the use of log4j to log information. You can use any log4j implementation you prefer.
  
 
&nbsp;
 
&nbsp;
===Jar Dependencies===
+
===Setup===
 +
Under project classpath, you need to prepare
 +
#<tt>log4j.properties</tt>
 +
#<tt>META-INF/validation.xml</tt>
  
 +
Here are examples of minimal settings in these files:
 +
 +
<tt>log4j.properties</tt>
 +
<source lang="php">
 +
log4j.rootLogger=info, stdout
 +
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 +
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 +
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
 +
</source>
 +
 +
<tt>META-INF/validation.xml</tt>
 +
<source lang="xml">
 +
<?xml version="1.0" encoding="UTF-8"?>
 +
<validation-config
 +
xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
 +
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 +
xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration">
 +
<default-provider>org.hibernate.validator.HibernateValidator</default-provider>
 +
<message-interpolator>org.hibernate.validator.engine.ResourceBundleMessageInterpolator</message-interpolator>
 +
<traversable-resolver>org.hibernate.validator.engine.resolver.DefaultTraversableResolver</traversable-resolver>
 +
<constraint-validator-factory>org.hibernate.validator.engine.ConstraintValidatorFactoryImpl</constraint-validator-factory>
 +
</validation-config>
 +
</source>
 +
 +
You can customize the setting depending on your requirement.
  
 
&nbsp;
 
&nbsp;
===Setup===
+
===Working with data binding===
 +
Upon the validation phase of data binding, you can use the JSR 303 Validator to verify the value against the constraints. Note that the constraints are specified on getter methods to work with data binding.
 +
 
 +
For example:
 +
 
 +
<tt>User.java</tt>
 +
<source lang="Java">
 +
public class User {
 +
 +
private String _firstName;
 +
private String _lastName;
 +
private Date _birthDate;
 +
 +
// getter, setter //
 +
@NotEmpty(message = "First name can not be null")
 +
public String getFirstName() {
 +
return _firstName;
 +
}
 +
 +
public void setFirstName(String name) {
 +
_firstName = name;
 +
}
 +
 +
@NotEmpty(message = "Last name can not be null")
 +
public String getLastName() {
 +
return _lastName;
 +
}
 +
 +
public void setLastName(String name) {
 +
_lastName = name;
 +
}
 +
 +
@Past(message = "Birth date must be in the past")
 +
public Date getBirthDate() {
 +
return _birthDate;
 +
}
 +
 +
public void setBirthDate(Date date) {
 +
_birthDate = date;
 +
}
 +
 +
}
 +
</source>
 +
 
 +
<tt>index.zul</tt>
 +
<source lang="xml">
 +
<?page title="Bean Validation" ?>
 +
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
 +
<zk>
 +
<window id="win" apply="org.zkoss.demo.DemoController">
 +
<grid width="300px">
 +
<columns>
 +
<column width="100px" />
 +
<column width="200px" />
 +
</columns>
 +
<rows>
 +
<row>
 +
First Name
 +
<textbox id="firstNameBox" value="@{win$composer.user.firstName, save-when='submit.onClick'}" />
 +
</row>
 +
<row>
 +
Last Name
 +
<textbox id="lastNameBox" value="@{win$composer.user.lastName, save-when='submit.onClick'}" />
 +
</row>
 +
<row>
 +
Birth Date
 +
<datebox id="birthDateBox" value="@{win$composer.user.birthDate, save-when='submit.onClick'}" />
 +
</row>
 +
</rows>
 +
</grid>
 +
<button id="submit" label="Submit" />
 +
</window>
 +
</zk>
 +
</source>
 +
 
 +
<tt>DemoController.java</tt>
 +
<source lang="Java">
 +
public class DemoController extends GenericForwardComposer {
 +
 +
public User getUser() {
 +
return User.getUser();
 +
}
 +
 +
public void onBindingValidate$submit(BindingValidateEvent event) {
 +
Validations.validate(event, null);
 +
}
 +
 
 +
}
 +
</source>
 +
 
 +
<tt>Validations.java</tt>
 +
<source lang="Java">
 +
public class Validations {
 +
 +
private static final Validator _validator = Validation.buildDefaultValidatorFactory().getValidator();
 +
 +
public static void validate(BindingValidateEvent event, ViolationRunner runner) {
 +
 +
Iterator<Component> refs = event.getReferences().iterator();
 +
Iterator<Binding> bindings = event.getBindings().iterator();
 +
Iterator<?> values = event.getValues().iterator();
 +
 +
List<WrongValueException> wvelist = new ArrayList<WrongValueException>();
 +
 +
while(refs.hasNext() && bindings.hasNext() && values.hasNext()) {
 +
 +
Component ref = refs.next();
 +
Binding binding = bindings.next();
 +
Object value = values.next();
 +
 +
Object bean = binding.getBean(ref);
 +
String expr = binding.getExpression();
 +
String propName = expr.substring(expr.lastIndexOf('.') + 1);
 +
 +
Set<ConstraintViolation<?>> vs = validate(bean.getClass(), propName, value);
 +
 +
// collect WrongValueException
 +
for(ConstraintViolation<?> v : vs)
 +
wvelist.add(new WrongValueException(ref, v.getMessage()));
 +
 +
// call runner
 +
if(runner != null)
 +
runner.run(vs, bean, ref);
 +
}
 +
 +
// this will interrupt binding value to bean, so bean is not modified
 +
if(!wvelist.isEmpty())
 +
throw new WrongValuesException(wvelist.toArray(new WrongValueException[0]));
 +
}
 +
 +
// interface //
 +
public interface ViolationRunner {
 +
public void run(Set<ConstraintViolation<?>> violations, Object bean, Component ref);
 +
}
 +
 +
// helper //
 +
private static Set validate(Class clazz, String propName, Object value) {
 +
return _validator.validateValue(clazz, propName, value);
 +
}
 +
 
 +
}
 +
</source>
 +
 
 +
==Demo==
 +
*[http://sourceforge.net/projects/zkforge/files/Small%20Talks/JSR%20303%20Bean%20Validation/bean-validation.zip/download Demo project]
 +
*[http://sourceforge.net/projects/zkforge/files/Small%20Talks/JSR%20303%20Bean%20Validation/bean-validation-0.8.0.war/download Demo war]
  
  
 
&nbsp;
 
&nbsp;
==Demo==
 
  
<!-- open this later
+
==References==
 +
*[http://books.zkoss.org/wiki/ZK_Developer%27s_Reference/Data_Binding/Validation Data Binding with JSR 303 Validation]
 +
*[http://jackson.codehaus.org/javadoc/bean-validation-api/1.0/index.html JSR 303 Javadoc]
 +
*[http://people.redhat.com/~ebernard/validation/ JSR 303 Documentation]
 +
*[http://docs.jboss.org/hibernate/validator/4.0.1/reference/en/html_single/ Hibernate Validator Reference]
 +
 
 +
 
 +
&nbsp;
 
{{Template:CommentedSmalltalk_Footer|
 
{{Template:CommentedSmalltalk_Footer|
 
|name=Potix Corporation
 
|name=Potix Corporation
 
}}
 
}}
-->
 

Revision as of 08:07, 13 May 2011

DocumentationSmall Talks2011MayIntegrate ZK with JSR 303: Bean Validation
Integrate ZK with JSR 303: Bean Validation

Author
Simon Pai, Engineer, Potix Corporation
Date
May 20, 2011
Version
ZK 5.0.7

What is JSR 303: Bean Validation

JSR 303 is a standard designed for working on property validation in Java beans. In brief, the constraints of a bean property are specified by Java annotations, and validation against the bean can be invoked by API.

A known implementation of JSR 303 is Hibernate Validator. In the following section we will use Hibernate Validator to demonstrate how to utilize this tool in a ZK application.


 

How to use Bean Validation

The usage of this tool is quite straightforward: You just need to specify property constraints and invoke validation.

Bean

public class User {
	
	@NotEmpty(message = "Last name can not be null.")
	private String _lastName;
	
	@Past(message = "Birth date must be in the past.")
	private Date _birthDate;
	
}

Invoke Validation

// prepare for Validator
ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
Validator validator = vf.getValidator();

// suppose we have a bean of User like this:
User user = new User();
user.setLastName(""); // wrong, should not be empty

// invoke validation, which will return a set of violations to the constraints
Set<ConstraintViolation<User>> violations = validator.validate(user);
for(ConstraintViolation<User> v : violations)
	System.out.println(v.getMessage()); // will print out: "Last name can not be null."


 

How to use Bean Validation in your ZK application

The following is a step-by-step guide to show a simple integration of JSR 303 with data binding.

Required Jars

The following is a sample dependency list for setting up Hibernate Validator to work with data binding:

	<!-- required for data binding -->
	<dependency>
		<groupId>org.zkoss.zk</groupId>
		<artifactId>zkplus</artifactId>
		<version>5.0.7</version>
	</dependency>
	
	<dependency>
		<groupId>org.hibernate</groupId>
		<artifactId>hibernate-validator</artifactId>
		<version>4.0.2.GA</version>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-api</artifactId>
		<version>1.6.1</version>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-log4j12</artifactId>
		<version>1.6.1</version>
	</dependency>

Hibernate Validator assumes the use of log4j to log information. You can use any log4j implementation you prefer.

 

Setup

Under project classpath, you need to prepare

  1. log4j.properties
  2. META-INF/validation.xml

Here are examples of minimal settings in these files:

log4j.properties

log4j.rootLogger=info, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

META-INF/validation.xml

<?xml version="1.0" encoding="UTF-8"?>
<validation-config
	xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration">
	<default-provider>org.hibernate.validator.HibernateValidator</default-provider>
	<message-interpolator>org.hibernate.validator.engine.ResourceBundleMessageInterpolator</message-interpolator>
	<traversable-resolver>org.hibernate.validator.engine.resolver.DefaultTraversableResolver</traversable-resolver>
	<constraint-validator-factory>org.hibernate.validator.engine.ConstraintValidatorFactoryImpl</constraint-validator-factory>
</validation-config>

You can customize the setting depending on your requirement.

 

Working with data binding

Upon the validation phase of data binding, you can use the JSR 303 Validator to verify the value against the constraints. Note that the constraints are specified on getter methods to work with data binding.

For example:

User.java

public class User {
	
	private String _firstName;
	private String _lastName;
	private Date _birthDate;
	
	// getter, setter //
	@NotEmpty(message = "First name can not be null")
	public String getFirstName() {
		return _firstName;
	}
	
	public void setFirstName(String name) {
		_firstName = name;
	}
	
	@NotEmpty(message = "Last name can not be null")
	public String getLastName() {
		return _lastName;
	}
	
	public void setLastName(String name) {
		_lastName = name;
	}
	
	@Past(message = "Birth date must be in the past")
	public Date getBirthDate() {
		return _birthDate;
	}
	
	public void setBirthDate(Date date) {
		_birthDate = date;
	}
	
}

index.zul

<?page title="Bean Validation" ?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<zk>
	<window id="win" apply="org.zkoss.demo.DemoController">
		<grid width="300px">
			<columns>
				<column width="100px" />
				<column width="200px" />
			</columns>
			<rows>
				<row>
					First Name
					<textbox id="firstNameBox" value="@{win$composer.user.firstName, save-when='submit.onClick'}" />
				</row>
				<row>
					Last Name
					<textbox id="lastNameBox" value="@{win$composer.user.lastName, save-when='submit.onClick'}" />
				</row>
				<row>
					Birth Date
					<datebox id="birthDateBox" value="@{win$composer.user.birthDate, save-when='submit.onClick'}" />
				</row>
			</rows>
		</grid>
		<button id="submit" label="Submit" />
	</window>
</zk>

DemoController.java

public class DemoController extends GenericForwardComposer {
	
	public User getUser() {
		return User.getUser();
	}
	
	public void onBindingValidate$submit(BindingValidateEvent event) {
		Validations.validate(event, null);
	}

}

Validations.java

public class Validations {
	
	private static final Validator _validator = Validation.buildDefaultValidatorFactory().getValidator();
	
	public static void validate(BindingValidateEvent event, ViolationRunner runner) {
		
		Iterator<Component> refs = event.getReferences().iterator();
		Iterator<Binding> bindings = event.getBindings().iterator();
		Iterator<?> values = event.getValues().iterator();
		
		List<WrongValueException> wvelist = new ArrayList<WrongValueException>();
		
		while(refs.hasNext() && bindings.hasNext() && values.hasNext()) {
			
			Component ref = refs.next();
			Binding binding = bindings.next();
			Object value = values.next();
			
			Object bean = binding.getBean(ref);
			String expr = binding.getExpression();
			String propName = expr.substring(expr.lastIndexOf('.') + 1);
			
			Set<ConstraintViolation<?>> vs = validate(bean.getClass(), propName, value);
			
			// collect WrongValueException
			for(ConstraintViolation<?> v : vs)
				wvelist.add(new WrongValueException(ref, v.getMessage()));
			
			// call runner
			if(runner != null)
				runner.run(vs, bean, ref);
		}
		
		// this will interrupt binding value to bean, so bean is not modified
		if(!wvelist.isEmpty())
			throw new WrongValuesException(wvelist.toArray(new WrongValueException[0]));
	}
	
	// interface //
	public interface ViolationRunner {
		public void run(Set<ConstraintViolation<?>> violations, Object bean, Component ref);
	}
	
	// helper //
	private static Set validate(Class clazz, String propName, Object value) {
		return _validator.validateValue(clazz, propName, value);
	}

}

Demo


 

References


 

Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.