miercuri, 9 decembrie 2015

JSF 2.3 Class-level bean validation on CDI based backing beans

JSF 2.3 will come with a new tag named, <f:validateWholeBean/>. As its name suggest, this tag enables class level validation. This tag contains two important attributes:

·         value - A ValueExpression referencing the bean to be validated.
·         validationGroups -  A comma-separated list of validation groups. A validation group is a fully-qualified class name.

This feature causes a temporary copy of the bean referenced by the value attribute.

Here is a brief example to ensure that the provided name and e-mail fields (contacts) are individually valid and also the e-mail start with that name (e.g. valid: nick, nick_ulm@yahoo.com).

ContactValidator

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class ContactValidator implements ConstraintValidator<ValidContact, ContactBean> {
   
 @Override
 public void initialize(ValidContact constraintAnnotation) {
  // NOOP
 }
   
 @Override
 public boolean isValid(ContactBean value, ConstraintValidatorContext context) {
  return value.getEmail().startsWith(value.getName());
 }   
}

ValidContact 

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Constraint(validatedBy = {ContactValidator.class})
@Documented
@Target(TYPE)
@Retention(RUNTIME)
public @interface ValidContact {

 String message() default "Invalid contacts (e-mail should start with name) !";
 Class<?>[] groups() default {};
 Class<? extends Payload>[] payload() default {};
}

ContactBean 

@Named
@RequestScoped
@ValidContact(groups = validateBean.ContactGroup.class)
public class ContactBean implements Serializable, Cloneable {

 private static final long serialVersionUID = 1L;

 @Size(min = 3, max = 20, message = "Please enter a valid name (between 3-20 characters)!",
       groups = validateBean.ContactGroup.class)
 private String name;

 @Pattern(regexp = "[a-zA-Z0-9]+@[a-zA-Z0-9]+\\.[a-zA-Z0-9]+",
          message = "Please enter a valid formated e-mail !",
          groups = validateBean.ContactGroup.class)
 private String email;

 // getters and setters

@Override
protected Object clone() throws CloneNotSupportedException {
 ContactBean other = (ContactBean) super.clone();
 other.setName(this.getName());
 other.setEmail(this.getEmail());
 return other;
 }
}

ContactGroup 

package validateBean;

public interface ContactGroup {
 // NOPE  
}

Facelets

<h:body>    
 <h:form>        
  Name:
  <h:inputText value="#{contactBean.name}">     
   <f:validateBean validationGroups="validateBean.ContactGroup" />
  </h:inputText>
 
  E-mail:
  <h:inputText value="#{contactBean.email}">                     
   <f:validateBean validationGroups="validateBean.ContactGroup" />
  </h:inputText>

  <h:commandButton value="Contact Admin" action="contact_admin"/>                       
           
  <f:validateWholeBean value="#{contactBean}" validationGroups="validateBean.ContactGroup" />     
 </h:form>         
</h:body>

Note This feature must explicitly be enabled by setting the following application parameter  (context parameter)  in web.xml: javax.faces.validator.ENABLE_VALIDATE_WHOLE_BEAN. If this parameter is not set, or is set to false, this tag must be a no-op.

<context-param>
 <param-name>javax.faces.validator.ENABLE_VALIDATE_WHOLE_BEAN</param-name>
 <param-value>true</param-value>
</context-param>

Check the result of using the class-level validation in the below figure:


The complete application is available here (I've tested with Mojarra 2.3.0-m04 under Payara 4).

Special thanks to Arjan Tijms for contributing to this post.

Niciun comentariu:

Trimiteți un comentariu