Server side validation
The GWT Validation Library makes it easy to do server side validation and automates the process of showing the validation errors "nicely" on the client side. That is for showing validation errors rooted on the server side the same functionality that is used for showing client side validation errors is used. That means if you bound for example a StyleAction to an Validator which was added to a TextBox that sets a red border when validation fails, that same functionality is accessed while processing validation errors from the server side, with a minimum amount of additional effort on the developers side.
On the server side we have one special object which you will work with: The ServerValidation.
It provides methods for doing your validation checks, so you can validate if the data sent by the client is correct. The main functionality that the ServerValidation provides is the possibility to throw an ValidationException. This ValidationException can be understood by the client side code of the library and will result in the invocation of the actions added to the field that failed validation. So let's jump right into how you would do server side validation:
public void saveCar(Car car) throws ValidationException { ServerValidation() .notNull(car, "car") .inRange(car.getPS(), 40, 230, "ps") .min(car.getSeats(), 2, "seats") .max(car.getDoors(), 5, "doors"); //If we come here no validation errors, so invoke business logic carDao.save(car); }
What we have here is a method of some service invoked via RCP. Note that it declares throws ValidationException.
We then use the ServerValidation object to do some validations. Per default the ServerValidation will follow a "fail fast" approach (can be configured). That means the first validation constraint that is not met, will be send back to the client. So in this case the client would only see one validation failure even if there might have been more, because in the "fail fast" mode the first validation restriction that is not met will immediately trigger an ValidationException. This way we can safely assume that after the validation calls are over and there was no exception thrown, the validations went through successfully. If you would rather like to validate all the validations and only throw the ValidationException after all validations are validated you can do the following:
public void saveCar(Car car) throws ValidationException { ServerValidation(false) .notNull(car, "car") .inRange(car.getPS(), 40, 230, "ps") .min(car.getSeats(), 2, "seats") .max(car.getDoors(), 5, "doors") .validate(); //This will throw an ValidationException if there //were one or more errors //If we come here no validation errors, so invoke business logic carDao.save(car); }
In this case all validations will be run and only at the end (at the call to validate()) a ValidationException might be thrown. This lets the client side part of the library be notified not only of the first validation that failed, like in the first example, it hands back ALL the errors to the client side that occured. This will in most cases probably be the better method to use the ServerValidation.
If you have validation needs that the ServerValidation does not provide (you will most likely have) than there is a easy way to still profit from the GWT Validation Libraries infrastructure. See this example:
public void createUser(User newUser) throws ValidationException { if(usernameTaken(newUser.getUsername())) { ServerValidation.exception("username_exists", "username"); } userDao.create(newUser); }
The value of the first parameter is the message key which is given by you and can be fully i18n on the client side (see the section about i18n). The second argument specifies the property that this validation error will be associated to on the client side.
Server side to client side validation
Lets look at a full example of validation that utilizes client side and server side validations. We assume we have a client side as shown in client side validation chapter. On the corresponding server side we want to store the entered year of birth. For exemplary reasons we also need this year to be unique. This unique check can only be done on the server side. So we could develop the server side something like this:
public void saveBirthYear(int birthYear) throws ValidationException { if(birthYearExists(birthYear)) { ServerValidation.exception("birth_year_exists", "birthYear"); } birthYearsDao.create(birthYear); }
The important part here is that the second parameter ("birthYear") to the ServerValidation.execption() method is called exactly the same like on the client side were we added a validator to the TextBox that contains the user input for the year of birth:
ValidationProcessor validator = new DefaultValidationProcessor(); validator.addValidators( "birthYear", new IntegerValidator(birthYearTextBox, 1890, 2009) .addActionForFailure(new StyleAction("validationFailedBorder")) .addActionForFailure(new LabelTextAction(errorLabel)) );
The result is, that the user is provided with a validation message (through the LabelTextAction and a custom style (in this case the StyleAction) is added no matter if the error occured on the client side (through the IntegerValidator) or on the server side (through ServerValidation.exception()). So if you needed to change the visual appearence of validation errors you only need to change the client side code as the server side code just forwards to whatever you defined on the client side. You can take this approach even further by providing custom Validators that already come with the actions you seem fit pre-initialized, so you don't even have to add the actions over and over again. Because of this modularity it should be really time saving to build a rich visual user feedback.