Help

Article updated. Mistake with 3.3.x functionality description corrected in Implementation details section

Introduction

As we reviewed in a previous blog with JSF 2 and RichFaces 4 you already have the Bean Validation support all the way to the browser with our client side validation. So you can effectively work with your server side object without any additional view level code related to validation.

This blog is going to review the last (but not least) validation feature which RichFaces 4 adds to JSF 2 . It's called Object Validation and provides a way to validate all your model Object fields considering even ones which were not used in the current view.

Why do you need that? The very first example which came to my mind as it appears frequently on various forums is dependent fields validation.

Password Validation Example

Let's check the password validation example:

<h:form>
	<rich:panel header="Change password" style="width:500px">
		<h:panelGrid columns="3">
			<h:outputText value="Enter new password:" />
			<h:inputSecret value="#{userBean.password}" id="pass"/>
			<rich:message for="pass"/>
			<h:outputText value="Confirm the new password:" />
			<h:inputSecret value="#{userBean.confirm}" id="conf"/>
			<rich:message for="conf"/>
		</h:panelGrid>
		<a4j:commandButton value="Store changes"
			action="#{userBean.storeNewPassword}" />
	</rich:panel>
</h:form>

And the simple managed bean source:

@ManagedBean
@RequestScoped
public class UserBean {

    @Size(min = 5, max = 15, message="Wrong size for password")
    private String password;
    @Size(min = 5, max = 15, message="Wrong size for confirmation")
    private String confirm; 
//...
    public void storeNewPassword(){
        FacesContext.getCurrentInstance().addMessage("", new FacesMessage(FacesMessage.SEVERITY_INFO, "Succesfully changed!", "Succesfully changed!"));
    }

//Getters and setters
}

So we solved half of the problem:

We are seeing the error messages if the password fields do not satisfy the validation rules given. Nothing is checking if passwords are the same though, just that they are independently valid. So what is the easiest way to validate if the fields are equals? We could perform that in action but that is quite late in the JSF lifecycle for validation. We could use some solutions using f:attribute in order to pass dependent field id to the other input and find the component by that id in custom validate method. There are also some other ways which are pretty easy to find across different knowledge-bases'. But most of them are either invoked in an improper phase (like action at INVOKE_APPLICATION) or has possible maintenance problems(f:attribute solution requires us to be patient with id's changes in view as validation depends on them).

RichFaces 4 Object Validation for cross-field validation

This is where RichFaces 4 Object Validation feature come in play! Here is what we propose to use:

<h:form>
	<rich:graphValidator value="#{userBean}" id="gv">
		<rich:panel header="Change password" style="width:500px">
			<rich:messages globalOnly="true"/>
			<rich:messages for="gv"/>
			<h:panelGrid columns="3">
				<h:outputText value="Enter new password:" />
				<h:inputSecret value="#{userBean.password}" id="pass"/>
				<rich:message for="pass"/>
				<h:outputText value="Confirm the new password:" />
				<h:inputSecret value="#{userBean.confirm}" id="conf"/>
				<rich:message for="conf"/>
			</h:panelGrid>
			<a4j:commandButton value="Store changes"
				action="#{userBean.storeNewPassword}" />
		</rich:panel>
	</rich:graphValidator>
</h:form>

And the Bean(Updated with implements Cloneable):

@ManagedBean
@RequestScoped
public class UserBean implements Cloneable{

    @Size(min = 5, max = 15, message="Wrong size for password")
    private String password="";
    @Size(min = 5, max = 15, message="Wrong size for confirmation")
    private String confirm="";

    @AssertTrue(message = "Different passwords entered!")
    public boolean isPasswordsEquals() {
        return password.equals(confirm);
    }

    public void storeNewPassword(){
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Succesfully changed!", "Succesfully changed!"));
    }

So lets look through the sample details. rich:graphValidator tag should wrap the inputs bound to the object which we are interested in validating. The value attribute should be pointed to that bean name. Then at PROCESS_VALIDATION phase all the object fields will be validated according to constraints added. And in that particular case isPassWordEquals will be validated using AssertTrueValidator. That looks just like we expected!

Different passwords entered(but valid according to size):

Verification successful:

Implementation Details

UPDATED(28.02) section below. Actually 3.3.x used the same way. Was written that it worked at model updates by mistake.

Just one question appears. Those who know the JSF life-cycle will ask immediately about how the bean could be validated before the model updates? Does RichFaces propose to use validation after process updates phase? No. We perform a clone() on your bean instance at validation phase and updating new instance with all the new values submitted(that's why we still need to wrap all the inputs related to rich:graphValidator). We then validate the cloned object firing validation messages if needed. Your model objects remains clean, lifecycle gets interrupted properly after Process Validations phase and messages encoded to client during Render Response.

NOTE: if cloneNotSupportedException thrown from the object – validation will be done at model updates. And that is the only exception to our architecture which really can't be workaround-ed.

Try it out!

Now having JSF 2 Bean Validation support standardized, RichFaces 4 Client Side Validation and Object Validation features we believe you will be able completely concentrate on your business tasks and will not spend time for any additional JSF development in the validation phase. Try our new features in RichFaces 4.0.0.M6 and let us know about any problems or questions appeared. That will help us greatly to provide those features stable and well documented prior to RichFaces 4 Final release!


[Get updates of my blogs in twitter]

[My jroller.com blog]

13 comments:
 
24. Feb 2011, 18:35 CET | Link
Paul Mooney | paul.mooney(AT)live.com

I like the @AssertTrue annotation and how it separates the validation from the action and doesn't require those extra JSF parameters (ie, FacesContext)

Does it create a deep clone of the UserBean? If not, I'm not sure I see the point since in the case of a sub property it will still ultimately 'dirty' the bean. If so, isn't it a potentially expensive operation?

My ignorance is going to shine here (and maybe this isn't the place to ask): What's wrong with doing some validation after updating the model? The user has to keep retrying until they get it right so the model will be correct, or they give up in which case the context dies anyways (if conversation) and the model goes away and no changes are applied (if entity in conversation). In cases the user alters, say a session or view scoped bean, would it be better to control if/how properties are updated manually through the action method instead of going through a cloning process (which might have one of the two issues mentioned above) before invoke application?

ReplyQuote
 
25. Feb 2011, 20:05 CET | Link

How to implement this pattern to CDI beans?

 
26. Feb 2011, 02:18 CET | Link
Flávio Henrique Almeida

It works with CDI beans (I have just tested it). No special configuration :) You only have to change de annotations:

import javax.inject.Named; import javax.enterprise.context.RequestScoped; @Named @RequestScoped public class UserBean {

 
26. Feb 2011, 22:58 CET | Link

Thank you very much. What library implements bean validation? Weld-servlet?

 
27. Feb 2011, 13:40 CET | Link
Flávio Henrique Almeida

You can go with HibernateValidation implementation. You will need validation-api-1.0.0.GA.jar (JSR-303) and hibernate-validator-4.1.0.Final.jar. It would be nice if you post your questions in the RF forun. Give it a try!

Weld-servlet is the library to enable CDI in Tomcat or Jetty container, it doesn´t have JSR-303 library.

 
28. Feb 2011, 09:16 CET | Link

Paul, sorry for the delay. Here is the comments to your question.

1) default clone() method doesn't make deep copies - it should be performed by developer.

2) having dirty values in scenario does the same thing: user creates temporary copy ( DTO ), updates it with new values and performs validation before persist() call. The only difference that richfaces creates temporary object and forget it on every request, so if user press 'back()' button, cancel conversation or performs some other action, data object doesn't keep dirty values.

 
02. Sep 2011, 08:28 CET | Link
Jernej Kovse

First of all, this is a great feature. It also works in RichFaces 3.3.

Ilya, what I am struggling with:

Is there a way to display the message from AssertTrue (Different passwords entered) next to a field (instead of above the fields), i.e., even though the validation is global I would like the message to appear next to the password field.

Another example is a validation whether a value (email, username) already exists in the database. Implementing the same approach as above with AssertTrue (instead of writing a custom Hibernate validator) will display the message above / belove the fields. So how do I bind the message to the field (email or username).

Kind regards, Jernej

 
20. Jun 2012, 23:20 CET | Link
Ernesto Hernandez | ealonso04(AT)hotmail.com

Hi everybody!

Im new to Richfaces, especially with Object Validation. So im trying to implement Object Validation in my project, just like Showcase dictates. I have a problem with this: when I click the button Store changes always shows the message Succesfully changed! No matter password and confirm are differents. Not even validates the lenght of the inputSecret and I'm getting a kind of error in console: JSF1005: Cannot instantiate validator of type javax.faces.Bean.

I have in my classpath the following libraries: richfaces-components-ui-4.2.2.Final.jar, javax.faces-2.1.7.jar, validation-api-1.0.0.GA.jar, hibernate-validator-4.2.0.Final.jar, hibernate-annotations-3.2.1.ga.jar. Im using IBM Integration Designer 7.5 built on Eclipse.

Any kind of help you can give me I would appreciate so much.

Thanks in advance!!! :)

17. May 2013, 08:45 CET | Link
Gilene Pacheco | vegigi(AT)uol.com.br
Save Friends ..

there is some form of set the focu on <rich:autocomplete>
with "#{rich:element('id')}.focus();"
because I'm not getting

from already thank you very much
 
11. Dec 2013, 10:46 CET | Link

I would like to thank you for the efforts you have made in writing this article. Luckily these are mostly UI issues with some Javascript that doesn't work in whatever browser.

 
13. Sep 2014, 09:50 CET | Link
Louis Vuitton Replica

handbags are gaining worldwide popularity recently. You will discover millions who wish to own a true designer bag but do not want to do so. The reason being an original designer handbags have become expensive. Christmas is originating,do you want a pleasant cute gift yourself,your friend and your loved ones!?we could give you all kinds of high-quality bags at the Lowest price.Do you want?Join now!!we're going to send you free tiffany bracelet free of charge gift inside your order package.Thus, the replica or duplicate replica Dior handbags have the world market of handbags completely by storm and are also in great demand.

The style industry has captured the global market completely.These handbags will also be popularly referred to as œhandbag knockoff? since they will be especially built to resemble and feel similar to the main product. The worldwide inhabitants are increasingly fashion replica watches uk conscious with every passing day. Globally reputed fashion designers are gaining more popularity and a few are recording high sales everywhere. Therefore is producing even higher pricing of designer products and accessories and women's handbags work just like exception. The solution to it's are available in the type of replica or duplicate handbags.

The replica designer handbags typically includes collections of Gucci, Balenciaga, Christian Dior, Prada, Marc Jacobs, Versace, Chanel, Mulberry, Miu Miu, Dolce AND Gabbana, Chloe and many others. Duplicate designer replica bags are of several types. As an example, these bags are available in different shapes, sizes and quality. They come for sale in huge numbers both online as well as offline.It's famous due to the branded footwear like sheep skin boots together with outerwear, clothing, bags, slippers, shoes, gloves along with goods.

01. Nov 2014, 15:13 CET | Link
George Bush jnr

Casele cu mansardă au devenit un înlocuitor pentru apartamentele de multe ori incomode din cauza vecinilor zgomotoși, sau a nesiguranței blocurilor, cauzată de vechimea imobilului. Pentru o familie medie, acest proiect este alternativa perfectă. Costurile ridicării unei astfel de case sunt mici, iar proiectarea ei este direct proporțională cu aceste costuri. Cu un design modern, … http://blog.looktvplus.com/cum-putem-maximiza-eficienta-unui-spatiu-limitat/ ...

 
24. Nov 2014, 03:50 CET | Link
moncler
Post Comment