Below is the screen-shot of a sample edit page created with the JSR 303 Bean Validation:
To apply JSR 303 Bean Validation a project, we need to do the following steps:
- Download the JSR 303 reference implementation from Hibernate.
- Add the 5 jar files into your Model project's Libraries and Classpath (Project Properties).
- Annotate your entities with validation annotations like the sample code snippet below:
... import javax.validation.constraints.DecimalMax; import javax.validation.constraints.Max; import javax.validation.constraints.Size; ... public class Employee implements Serializable { @Id @Column(name="EMPLOYEE_ID", nullable = false) private Long employeeId; @Column(name="FIRST_NAME", length = 20) @Size(min = 3, max = 20) private String firstName; @Column(name="LAST_NAME", nullable = false, length = 25) @Size(min = 3, max = 20) private String lastName; @Max(1000000) private Double salary; @Column(name="COMMISSION_PCT") @DecimalMax("1.00") private Double commissionPct; ...
- Create a utility class that will handle extraction of validation messages like the one below:
package com.blogspot.soadev.util; import java.util.Set; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.ValidatorFactory; public class MyUtils { public static javax.validation.Validator getValidator() { ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); return factory.getValidator(); } public static String extractConstraintViolationMessages(Set violations) { StringBuilder builder = new StringBuilder(); for (Object obj : violations) { if (obj instanceof ConstraintViolation) { builder.append(((ConstraintViolation)obj).getMessage()); builder.append("\n"); } } return builder.toString(); } //This method returns a set of validation constraint errors public static Set validateEntity(Object object) { javax.validation.Validator validator = getValidator(); return validator.validate(object); } // returns null if no violation public static String getEntityValidationErrorMsg(Object object) { Set violations = validateEntity(object); if (violations.size() > 0) { return extractConstraintViolationMessages(violations); } return null; } }
- In the ViewController project, create the following class that implements javax.faces.validator.Validator.
package com.blogspot.soadev.view.validator; import com.blogspot.soadev.util.MyUtils; import com.blogspot.soadev.view.util.JSFUtils; import java.util.Set; import javax.el.ELException; import javax.faces.FacesException; import javax.faces.application.FacesMessage; import javax.faces.component.EditableValueHolder; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.validator.Validator; import javax.faces.validator.ValidatorException; import javax.validation.ConstraintViolation; import javax.validation.Validation; public class BeanValidator implements Validator { private static final String DOT_REGEX = "[.]"; private static final String BINDINGS = "bindings"; private static final String INPUT_VALUE = "inputValue"; private static final String NAME = "name"; private static final String EMPTY_STRING = ""; private static final String END_CURLY_BRACKET = "}"; private static final String DATA_PROVIDER = "currentRow.dataProvider"; private static final String DOT = "."; public BeanValidator() { super(); } public void validate(FacesContext facesContext, UIComponent component, Object object) throws ValidatorException { if (component instanceof EditableValueHolder) { // Validate input component EditableValueHolder input = (EditableValueHolder)component; try { String expression = component.getValueExpression("value").getExpressionString(); if (null != expression) { Set<ConstraintViolation<Object>> constraintViolations = validateValue(object, expression); if (constraintViolations.size() > 0) { input.setValid(false); // send all validation messages. String msg = MyUtils.extractConstraintViolationMessages(constraintViolations); FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, null); throw new ValidatorException(fm); } } } catch (ELException e) { throw new FacesException(e); } } } private Set<ConstraintViolation<Object>> validateValue(Object object, String expression) { Object targetObject = getTargetObject(expression); String property = getProperty(expression); javax.validation.Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); Set constraintViolations = validator.validateValue(targetObject.getClass(), property, object); return constraintViolations; } public String getProperty(String expression){ if (expression.contains(BINDINGS) && expression.contains(INPUT_VALUE)){ expression = expression.replaceFirst(INPUT_VALUE, NAME); return JSFUtils.resolveExpression(expression).toString(); } String [] tokens = expression.split(DOT_REGEX); String result = tokens[tokens.length-1]; result = result.replaceAll(END_CURLY_BRACKET, EMPTY_STRING); return result; } public Object getTargetObject(String expression){ if (expression.contains(BINDINGS) && expression.contains(INPUT_VALUE)){ expression = expression.replaceFirst(INPUT_VALUE, DATA_PROVIDER); return JSFUtils.resolveExpression(expression); } String [] tokens = expression.split(DOT_REGEX); StringBuilder builder = new StringBuilder(tokens[0]); for (int i = 1; i < tokens.length - 1; i++){ builder.append(DOT); builder.append(tokens[i]); } builder.append(END_CURLY_BRACKET); return JSFUtils.resolveExpression(builder.toString()); } }
- Add the JSR303BeanValidator class above to the list of validators in faces-config.xml
- Apply the JSR303BeanValidator to your input components in ADF Faces.
<af:inputText value="#{bindings.firstName.inputValue}" label="#{bindings.firstName.hints.label}" required="#{bindings.firstName.hints.mandatory}" columns="#{bindings.firstName.hints.displayWidth}" maximumLength="#{bindings.firstName.hints.precision}" shortDesc="#{bindings.firstName.hints.tooltip}" id="it2" autoSubmit="true"> <f:validator validatorId="JSR303BeanValidator"/> </af:inputText> <af:inputText value="#{bindings.lastName.inputValue}" label="#{bindings.lastName.hints.label}" required="#{bindings.lastName.hints.mandatory}" columns="#{bindings.lastName.hints.displayWidth}" maximumLength="#{bindings.lastName.hints.precision}" shortDesc="#{bindings.lastName.hints.tooltip}" id="it4" autoSubmit="true"> <f:validator validatorId="JSR303BeanValidator"/> </af:inputText> <af:inputText value="#{bindings.salary.inputValue}" label="#{bindings.salary.hints.label}" required="#{bindings.salary.hints.mandatory}" columns="#{bindings.salary.hints.displayWidth}" maximumLength="#{bindings.salary.hints.precision}" shortDesc="#{bindings.salary.hints.tooltip}" id="it3" autoSubmit="true"> <f:validator validatorId="JSR303BeanValidator"/> <af:convertNumber groupingUsed="false" pattern="#{bindings.salary.format}"/> </af:inputText>
- Run your project and try to input invalid values. To display the validation error messages after you tab out of a component, ensure to set the "AutoSubmit" attribute of the component to true.
To know more about JSR 303, click here and here.
Related Posts
- JSR 303 Bean Validation: @AssertMethodAsTrue - A reusable constraint annotation that spans multiple properties.
- JSR 303 Bean Validation: @ValidateDateRange - A reusable constraint annotation to validate date ranges
- JSR 303 Bean Validation: Error "java.lang.NoSuchMethodError: javax.persistence.Persistence.getPersistenceUtil()Ljavax/persistence/PersistenceUtil;"
No comments:
Post a Comment