{#==========================================
Docs : "Validation"
==========================================#}
Spincast provides a good set of utilities to validate objects. We decided to base those utilities
on plain Java code and not on annotations. Validation annotations may seem convenient at first,
but, in a real project, you quickly realize that you can't express all the details you need : you can't use complex
logic, you can't validate an element
based on the result of the validation of another element, etc. In general, you end up writing plain Java code anyway
in addition to those annotations... But then your validation logic is scattered in many places and this is
not the ideal.
You use Predefined Validations or custom
validation code to actually validate the object. Those validations may result
in Validation Messages. Most of the time those
are
Validation
In Spincast, you validate an object using three main steps :
Error Validation Messages resulting from failed validations
("This email is invalid", for example).
Validation Messages by retrieving
them from the Validation Set. In general, you want to display them to a user, or
you generate some kind of report.
Here's a quick example :
// Creation of a Validation Set
ValidationSet myValidationSet = getValidationFactory().createValidationSet();
// The object we're going to validate
User user = getUser();
// Validates the email of the user using the
// "validationEmail()" predefined validation
myValidationSet.validationEmail()
.key("email")
.element(user.getEmail())
.validate();
// Validates the username of the user, using
// custom validation code
String username = user.getUsername();
if(username == null || username.length() < 3 || username.length() > 42) {
myValidationSet.addError("username",
"USERNAME_INVALID",
"Must contain between 3 and 42 characters.");
}
// Uses/Displays the resulting Validation Messages
if(!myValidationSet.isValid()) {
Map<String, List<ValidationMessage>> validationMessages = myValidationSet.getMessages();
// ... do something with the messages
}
In the JsonObject validation section, we'll see that validation is even easier when done using JsonObjects...
At the core of a validation process, is a ValidationSet.
A Validation Set is a set of Validation Messages and of
utility methods. It acts as a container to save the results of the various validations
run on an object.
For example, let's say we validate a User object. At the end of this validation, the resulting Validation Set may
contain two Validation Messages :
Error Validation Message : "The email is invalid."
Success Validation Message : "This username is available!"
There are two ways of creating a Validation Set instance :
ValidationFactory validationFactory = getValidationFactory(); ValidationSet validationSet = validationFactory.createValidationSet();
validationSet(...) method on a JsonObject :
JsonObject responseModel = context.response().getModel(); JsonObjectValidationSet validationSet = responseModel.validationSet();
Validation Set this way, it is bound to the
JsonObject it originates from. A
JsonObjectValidationSet
is returned instead of a plain Validation Set, and you have access to extra methods dedicated
to validate the associated JsonObject. We'll see that in details in the
JsonObject validation section.
A Validation Set is more than a simple container to store the
validation results. It also provides Predefined Validations
and a bunch of other utility methods. Those utility methods are :
ValidationSet addMessage(String validationKey, ValidationMessage validationMessage)
Validation Message to this set, using the
specified validation key.
ValidationSet addMessage(String validationKey, ValidationLevel messageLevel, String code, String text)
Validation Message.
ValidationSet addError(String validationKey, String code, String text)
Error Validation Message.
ValidationSet addWarning(String validationKey, String code, String text)
Warning Validation Message.
ValidationSet addSuccess(String validationKey, String code, String text)
Success Validation Message.
ValidationSet mergeValidationSet(ValidationSet set)
Validation Set.
ValidationSet mergeValidationSet(String validationKeyPrefix, ValidationSet result)
Merges an existing Validation Set but prefixes all the
validation keys with the specified validationKeyPrefix.
The validationKeyPrefix parameter allows you to merge a Validation Set
resulting from a validation not performed directly on your current Validation Set
(you may be reusing an external Validator for example) and still have the keys of
the merged Validation Messages to properly represent JsonPaths
on your current Set. We'll talk about that in a next section...
boolean hasMessages()
Validation Set contain any
Validation Messages?
boolean hasMessages(String validationKey)
Validation Messages associated with the
specified validation key?
boolean isWarning()
true if the Validation Set
contains at least one Warning Validation Message, but no
Error Validation Messages.
boolean isWarning(String validationKey)
true if there is
at least one Warning Validation Message, but no
Error Validation Messages associated with the
specified validation key.
boolean isSuccess()
true if the validation set
only contains Success Validation Messages
(or contains no messages at all).
boolean isSuccess(String validationKey)
true if there are
only Success Validation Messagesassociated with the
specified validation key (or contains no messages at all).
boolean isError()
true if the validation set
contains at least one Error Validation Message.
boolean isError(String validationKey)
true if there is at least
one Error Validation Message associated with the
specified validation key.
boolean isValid()
Returns true if the Validation Set
does not contain any Error Validation Messages.
The set can contain Warning Validation Message
and Success Validation Message.
This is a synonym of !isError().
boolean isValid(String validationKey)
Returns true if there are no
Error Validation Messages associated with the
specified validation key.
There can be Warning Validation Message
and Success Validation Message.
This is a synonym of !isError(validationKey).
Map<String, List<ValidationMessage>> getMessages()
Gets the Validation Messages, with their
associated validation keys as the leys of the Map.
The Map and the List values are immutable.
List<ValidationMessage> getMessages(String validationKey)
Gets the Validation Messages associated with the
specified validation key.
The Map and the List values are immutable.
String getMessagesFormatted(ValidationMessageFormatType formatType)
Validation Messages.
String getMessagesFormatted(String validationKey, ValidationMessageFormatType formatType)
Validation Messages
associated with the specified validation key.
public JsonObject convertToJsonObject()
Converts the Validation Set to a JsonObject object.
Read the Converting to a JsonObject
section to see what the resulting
JsonObject object looks like!
The resulting JsonObject object
is immutable.
A ValidationMessage is composed of three things :
Validation Level. This level can be :
Error
Warning
Success
text, which is the description of the validation result. For
example : "This email is invalid".
code, which in general is a constant representing the
type of validation this Validation Message is associated with.
For example : "VALIDATION_TYPE_EMAIL".
When you add a Validation Message to a Validation Set, you
do so using a validation key. The validation key allows you
to retrieve the Validation Messages associated with a specific element from
the Validation Set.
Here's a quick example where we perform a validation and create a
Validation Message :
ValidationSet validatorSet = validationFactory.createValidationSet();
JsonObject user = getUser();
String thirdBookTitle = user.getString("user.books[2].title");
if(containsNsfwWords(thirdBookTitle)) {
ValidationMessage message =
getValidationFactory().createMessage(ValidationLevel.WARNING,
"NSFW_MATERIAL",
"This book contains NSFW material.");
validatorSet.addMessage("user.books[2].title", message);
}
Explanation :
Validation Set.
user (as a JsonObject)
that we're going to validate.
user. We use a
JsonPath to target it!
Validation Message to
represent the validation result.
level of this Validation Message.
Here, it's going to be a Warning Validation Message. The two other possible levels are
Error and Success.
code (or "type") of the validation
the Validation Message is associated with.
text for the Validation Message.
Validation Message to the
Validation Set using the "user.books[2].title" validation key.
We'll see in the next section that using the
JsonPath of the validated element as its validation key is often
a good idea!
Validation Sets also provides some methods to quickly add
Validation Messages, without having to create the messages manually.
For example :
// Creates and adds an Error Validation Message
validatorSet.addError("user.books[2].title", "LENGTH", "The title is too long");
// Creates and adds a Warning Validation Message
validatorSet.addWarning("user.books[2].title", "LENGTH", "The title is rather long");
// Creates and adds a Success Validation Message
validatorSet.addSuccess("user.books[2].title", "LENGTH", "The title length is perfect");
A validation key is used to associate
Validation Messages to the validated element they have been created for.
You can think of a Validation Set as a big
Map<String, List<ValidationMessage>> where the keys
are validation keys and where the values are the
Validation Messages.
If you validate a simple email element for example, you could use "email"
or "email-validation" as the validation key. It's up to you to choose
a meaningful name for the key : you will later use it to retrieve all the Validation Messages
associated with this element so you can display them, create a report from them, etc.
Even if you can use any string as a validation key, we suggest that
you stick to some conventions since a validation key must be unique and should well
represent the element it is associated with.
The convention we suggest is that, when possible, you
use the JsonPath of the validated element as the validation key.
Let's say we validate this user object :
{
"name": "Stromgol",
"email": "test@example.com"
"books": [
{
"title" : "Dune",
"author": "Frank Herbert"
},
{
"title" : "The Hitchhiker's Guide to the Galaxy",
"author" : "Douglas Adams"
}
]
}
First, we will validate the email :
JsonObject user = getUser();
// We create a Validation Set
ValidationSet validationSet = getValidationFactory().createValidationSet();
if(!isEmailValid(user.getString("email"))) {
// We add a Validation Message using "email" as the validation key
validationSet.addError("email", "EMAIL_VALIDATION", "Invalid email");
}
We can later retrieve the Validation Messages associated
with the email element using that "email" validation key :
List<ValidationMessage> validationMessages = validationSet.getMessages("email");
Very straightforward! But now let's try to do the thing with the title of the first book :
// Gets the title of the first book, using its JsonPath
String title = user.getString("books[0].title");
if(!isTitleValid(title) {
// We add a Validation Message using "title" as the validation key...
// This may not be a good idea!
validationSet.addError("title", "TITLE_VALIDATION", "Invalid title");
}
List<ValidationMessage> validationMessages = validationSet.getMessages("title");
We may be tempted to use a very short name as the validation key, "title"
for example. It would work, but it's not a very good idea... The problem is that now
the validation key doesn't well represent
the validated element it is associated with. Remember that each validation key
must be unique. What happens if we also want to validate the
title of the second book? Or if there are more than one user with books to validate?
What validation keys will we use then? We can't use the same "title"
validation key for more than one element!
Since each element of a JsonObject already has a unique identifier, which is its
JsonPath, why not use this identifier as
its validation key?
// Gets the title of the first book, using its JsonPath
String title = user.getString("books[0].title");
if(!isTitleValid(title) {
// We add a Validation Message using the JsonPath
// of the validated element as the validation key :
// much better!
validationSet.addError("books[0].title", "TITLE_VALIDATION", "Invalid title");
}
List<ValidationMessage> validationMessages = validationSet.getMessages("books[0].title");
Now there won't be any conflict, even if there are a lot of validation keys in our
Validation Set, and every key will be clearly indicate which validated
element it is associated with!
Note that there are situations where you can't use a JsonPath
for a validation key. You don't always validate elements individually, for instance. Sometimes,
a combination of elements is invalid, and therefore no JsonPath
is available.
In those situations, we suggest that you scope the validation key as much as possible, and that you use creativity in order to make the key unique and meaningful!
For example, let's say that an HTML form has been submitted
and you need to validate that two passwords from it match. If they don't match,
you could had an Error Validation Message for both of those elements, or only
for the second one (you could say that only the second one is invalid since it doesn't match the first one).
But you could also want to add a Validation Message to represent that invalid combination,
not the fields taken individually.
You may want to display a "The passwords
don't match" error in the section where both fields are, for example.
In such situations, you can't use a JsonPath as the validation key, since you are
not referring to a single element. But we suggest that you still try to scope the validation key,
so it is as unique and meaningful as possible. For example, that key could be
"myForm.user.passwordsMatch" :
ValidationSet validationSet = getValidationFactory().createValidationSet();
JsonObject formData = context.request().getFormData();
// Gets the passwords using their JsonPath
String password1 = formData.getString("myForm.user.password1", "");
String password2 = formData.getString("myForm.user.password2", "");
if(!password1.equals(password2)) {
// Use a scoped and meaningful
// validation key, even if it's not
// a true JsonPath!
validationSet.addError("myForm.user.passwordsMatch",
"PASSWORDS_MATCH",
"The password don't match!");
A question remains : what happens to this "Use the JsonPath of a validated element as its validation key"
convention when we validate an element
using an external Validator? For example, we may have a TitleValidator
that can be reused in multiple places in our application. For example :
ValidationSet validationSet = getValidationFactory().createValidationSet();
String title = getUser().getString("books[0].title");
TitleValidator titleValidator = getTitleValidator();
ValidationSet titleValidationSet = titleValidator.validate(title);
validationSet.mergeValidationSet(titleValidationSet);
// Oups!
// The validation key is "title" here, not "books[0].title" as we
// would like...
List<ValidationMessage> messages = validationSet.getMessages("title");
External validators return a Validation Set and you merge
this set to your own local set [9] (you can learn
more about merging Validation Sets in the
Sharing / Merging Validation Sets section).
The problem here is that TitleValidator has no idea of the position of the
"title" element inside our local user object! It will see the "title" element
as being a root element and therefore it won't generate a validation key respecting our local
JsonPath... It will probably simply use "title" as the validation key.
For this reason, the mergeValidationSet(...)
method accepts a "validationKeyPrefix" parameter. If this parameter is specified, all the validation keys
will be prefixed with it when merged :
ValidationSet validationSet = getValidationFactory().createValidationSet();
String title = getUser().getString("books[0].title");
TitleValidator titleValidator = getTitleValidator();
// We use the external validator
ValidationSet titleValidationSet = titleValidator.validate(title);
// We prefixe the merged validation keys
validationSet.mergeValidationSet("books[0].", titleValidationSet);
// The Validation Messages can now be retrieved using
// JsonPaths thast are valid on our validated root object!
List<ValidationMessage> messages = validationSet.getMessages("books[0].title");
There is also a prefixValidationKeys(...)
method which can be used to prefix the validation keys of a Validation Set directly, without having to merge
this set into another one. This can be useful, for example if you want to prefix the validation keys before adding
a Validation Set to a JsonObject :
// Uses an external validator
ValidationSet validationSet = getExternalValidator().validate(someObject);
// Prefixes the resulting validation keys
// *directly on the Validation Set*
validationSet.prefixValidationKeys("someObject.");
// Adds the Validation Set (with the validation keys
// now modified) to the response model
context.response().getModel().put("validation", validationSet);
Spincast provides some predefined validations to help validate an object. They are defined on the ValidationSet interface so there are easily accessible during a validation process. Let's have a look at an example :
// We create an inital Validation Set
ValidationSet myValidatorSet = getValidationFactory().createValidationSet();
// This is a username we're going to validate!
String username = getSomeUsername();
// Validates that the username is not blank and, only if
// it's not, validates that it contains at least 3 characters.
ValidationSet lastResult = myValidatorSet.validationNotBlank()
.key("username")
.element(username)
.validate();
if(lastResult.isValid()) {
lastResult = myValidatorSet.validationMinLength(3)
.key("username")
.element(username)
.validate();
}
Notice that a predefined validation returns it's own Validation Set [9]! This
allows you to conditionally apply a validation depending on the result of a previous
one [13].
To use a predefined validation :
validateXXXXXX(...) method
on your Validation Set. For example : myValidatorSet.validationNotBlank().
This starts a builder to create the validation.
validation key
using the "key(...)" method on the builder. This key associate
the resulting Validation Messages to the validated elements.
For example :
.key("username").
element to validate. For example :
.element(username).
.validate() to perform the actual validation.
When the validate() method is called, the validation
is perform and :
Validation Messages are automatically added to the root Validation Set.
Validation Set, representing this particular validation only, is
returned. This allows you to conditionally apply a validation depending on the result of a previous
one.
Here's the list the predefined validations available on a Validation Set :
ValidationBuilderKey validationNotBlank()
null, empty or
spaces only).
ValidationBuilderKey validationBlank()
ValidationBuilderKey validationEmail()
ValidationBuilderKey validationNotNull()
ValidationBuilderKey validationNull()
ValidationBuilderKey validationPattern(String pattern)
ValidationBuilderKey validationNotPattern(String pattern)
ValidationBuilderKey validationSize(int size, boolean ignoreNullValues)
ValidationBuilderKey validationMinSize(int minSize, boolean ignoreNullValues)
ValidationBuilderKey validationMaxSize(int maxSize, boolean ignoreNullValues)
ValidationBuilderKey validationLength(int length)
ValidationBuilderKey validationMinLength(int minLength)
A null value makes this validation fail, otherwise
toString() is called on the object to
check its "length".
ValidationBuilderKey validationMaxLength(int maxLength)
A null value is a success, otherwise
toString() is called on the object to
check its "length".
ValidationBuilderKey validationEquivalent(Object reference)
Starts the creation of a "equivalent" validation.
To validate if an element is equivalent to another,
one is converted to the type of the other (when this is required).
If this conversion fails, the elements are not equivalent. When both
elements are of the same type, they are compared using their equals(...)
method. This process is done in the
ObjectConverter#isEquivalent(...)
method.
ValidationBuilderKey validationNotEquivalent(Object reference)
Starts the creation of a "not equivalent" validation.
To validate if an element is equivalent to another,
one is converted to the type of the other (when this is required).
If this conversion fails, the elements are not equivalent. When both
elements are of the same type, they are compared using their equals(...)
method. This process is done in the
ObjectConverter#isEquivalent(...)
method.
ValidationBuilderKey validationLess(Object reference) throws CantCompareException
Starts the creation of a "less than" validation.
To validate if an element is less than another,
one is converted to the type of the other (when this is required).
If this conversion fails, the elements can't be compared.
The resulting type of the elements must implement the Comparable interface,
so the compareTo(...) method is used to compare the two elements.
An null element is always less than a non-null element.
ValidationBuilderKey validationGreater(Object reference) throws CantCompareException
Starts the creation of a "greater than" validation.
To validate if an element is greater than another,
one is converted to the type of the other (when this is required).
If this conversion fails, the elements can't be compared.
The resulting type of the elements must implement the Comparable interface,
so the compareTo(...) method is used to compare the two elements.
An null element is always less than a non-null element.
ValidationBuilderKey validationEquivalentOrLess(Object reference) throws CantCompareException
Starts the creation of a "equivalent or less" validation.
To validate if an element is equivalent or less than another,
one is converted to the type of the other (when this is required).
If this conversion fails, the elements can't be compared.
The resulting type of the elements must implement the Comparable interface,
so the compareTo(...) method is used to compare the two elements.
An null element is always less than a non-null element.
ValidationBuilderKey validationEquivalentOrGreater(Object reference) throws CantCompareException
Starts the creation of a "equivalent or greater" validation.
To validate if an element is equivalent or greater than another,
one is converted to the type of the other (when this is required).
If this conversion fails, the elements can't be compared.
The resulting type of the elements must implement the Comparable interface,
so the compareTo(...) method is used to compare the two elements.
An null element is always less than a non-null element.
Some options are available during the process of using a predefine validation :
Instead of validating a single element, using the
"element(...)" method of the builder, you can validate
a JsonArray of elements by using
the "all(...)" method. Doing so, all the
elements of the array will be validated and some
Validation Messages will potentially be added
for each of them!
Note that, when such array is validated, the generated validation keys
are going to be the key of the array + the
position of the elements in the array. For example :
ValidationSet myValidatorSet = validationFactory.createValidationSet();
JsonArray titles = getJsonManager().createArray();
titles.add("A valid title");
titles.add("");
titles.add(" ");
titles.add(null);
// Using ".all(titles)", this validates all the elements
// of the array
ValidationSet lastResult = myValidatorSet.validationNotBlank()
.key("titles")
.all(titles)
.validate();
Validation Set will contain
three Error Validation Messages : one with the key "titles[1]",
one with the key "titles[2]", and one with the key "titles[3]".
The first title ("titles[0]") is valid so no Validation Message
will be added for it.
Validation Message is added
only when the validation fails. If you want to add a Success Validation Message,
when the validation is sucessful, you can use the "addMessageOnSuccess(...)" method.
For example :
ValidationSet myValidatorSet = validationFactory.createValidationSet();
JsonArray titles = getJsonManager().createArray();
titles.add("A valid title");
titles.add("");
ValidationSet lastResult = myValidatorSet.validationNotBlank()
.key("titles")
.all(titles)
.addMessageOnSuccess()
.validate();
Validation Set will contain
two Validation Messages : a Success Validation Message
with the key "titles[0]" and an Error Validation Message
with the key "titles[1]".
"addMessageOnSuccess(...)" method, you can
specify the text that is going to be used for the message
(instead of the default one). For
example :
ValidationSet myValidatorSet = validationFactory.createValidationSet();
JsonArray titles = getJsonManager().createArray();
titles.add("A valid title");
titles.add("");
ValidationSet lastResult = myValidatorSet.validationNotBlank()
.key("titles")
.all(titles)
.addMessageOnSuccess("A custom Success message!")
.validate();
Error Validation Message is generated by default.
If you want the failure of a validation to generate a
Warning Validation Message instead,
use the "treatErrorAsWarning()" method. But remember that a Validation Set
containing Warning Validation Message is still considered as being
valid, only Error Validation Messages make it invalid! For example :
ValidationSet myValidatorSet = validationFactory.createValidationSet();
String username = "";
ValidationSet lastResult = myValidatorSet.validationNotBlank()
.key("username")
.element(username)
.treatErrorAsWarning()
.validate();
// There is now one *Warning* Validation Message
// in our Validation Set
myValidatorSet.getMessages().size(); // == 1
// The level of the Validation Set is "Warning"
myValidatorSet.isWarning(); // true
myValidatorSet.isError(); // false
myValidatorSet.isSuccess(); // false
// The Validation Set is still valid!
myValidatorSet.isValid(); // true
Validation Message
when a validation fails, using the
"failMessageText(...)" method. The specified
text will then be used for the Error Validation Message if one
is generated, but also for a Warning Validation Message if
"treatErrorAsWarning()" is used.
You can specify that a validation must not be run if some Validation Messages
at a specific level already exist in the Validation Set.
Let's say for example that
you want to validate that a username contains at least 3 characters
but you only want to perform this validation if the username is not blank
in the first place! You
could do this programmatically, but you can also pass a special parameter to the
validate(...) method :
ValidationSet myValidatorSet = validationFactory.createValidationSet();
String username = "";
ValidationSet lastResult = myValidatorSet.validationNotBlank()
.key("username")
.element(username)
.validate();
// This validation is only going to be performed if
// the Validation Set doesn't contain any errors yet
lastResult = myValidatorSet.validationMinLength(3)
.key("username")
.element(username)
.validate(ValidationLevel.ERROR);
In this example, the resulting Validation Set will only contain
one Validation Message : the one for the
"Not Blank" validation. The "Minimum Length" validation
is not performed since the Validation Set already contains a
Validation Message at the Error level!
Also note that "validate(true)" is a shortcut for
"validate(ValidationLevel.ERROR)". It means
"Only run this validation
is the Validation Set is still valid!".
If you are validating a JsonArray, by using the "all(...)" method,
then a couple of extra methods are also available :
arrayItselfAddFailMessage() : if you call this
method, a Validation Message will be added for the array itself if
the validation for at least one of its elements fails. The validation key for this
message will be the specified validation key (remember that
the keys for the elements of the array are going to be the
specified validation key + the position of the elements in the array).
You can also specify the text to use for that message (instead of the default one) :
arrayItselfAddFailMessage("Some elements are invalid!")
arrayItselfAddSuccessMessage() : if you call this
method, a Validation Message will be added for the array itself if
the validation is successful for all its elements. The validation key for this
message will be the specified validation key (remember that
the keys for the elements of the array are the specified validation key +
the position of the elements in the array).
You can also specify the text to use for the message (instead of the default one) :
arrayItselfAddSuccessMessage("All good!")
Validating a JsonObject is very easy : you simply
use its "validationSet()" method to get a Validation Set specifically
made to validate it. For example :
JsonObject user = getUser();
JsonObjectValidationSet userValidationSet = user.validationSet();
ValidationSet lastResult = userValidationSet.validationEmail()
.jsonPath("email")
.validate();
Explanation :
Validation Set from a JsonObject, the type
of this set is JsonObjectValidationSet.
This type extends the ValidationSet base type
and adds some extra functionalities.
Validation Set
is bound to a specific JsonObject, a new
"jsonPath(...)" method is available! It allows you
to specify the JsonPath to the
element to validate on the current object, and will also be used as
the validation key.
By calling the "validationSet()" method on a JsonObject, you get a
JsonObjectValidationSet
instance. This type extends the ValidationSet base type
and adds some extra functionalities.
With a JsonObjectValidationSet, you don't need
to specify a "key(...)" to use or an "element(...)" to validate! You
simply specify the jsonPath(...) to the element to
validate. The resulting Validation Messages, if any,
will have that JsonPath as their validation keys. For example :
JsonObject user = getJsonManager().create();
user.put("email", "nope");
JsonObjectValidationSet userValidationSet = user.validationSet();
// The Validation Set is bound to the "user" object here,
// so we use a JsonPath starting from this object as the root
// to target the "email" element to validate
ValidationSet lastResult = userValidationSet.validationEmail()
.jsonPath("email")
.validate();
// The generated validation key is the JsonPath of
// the validated element!
List<:ValidationMessage> messages = userValidationSet.getMessages("email");
System.out.println(messages.size()); // prints "1"
ValidationMessage message = messages.get(0);
System.out.println(message.getValidationLevel()); // prints "ERROR"
System.out.println(message.getCode()); // prints "VALIDATION_TYPE_EMAIL"
System.out.println(message.getText()); // prints "Invalid email address"
Finally, note that there is also a "jsonPathAll(...)" method to validate
all the elements of a JsonArray.
You can merge a Validation Set into another one using the
mergeValidationSet()
method. This allows you to make some elements being validated by an external validator
and then merge the resulting Validation Messages in your local Validation Set.
Let's say you have a CompanyValidator object that
provides a validateCompany(...) method able to validate
a "company" JsonObject :
// The user object we're going to validate
JsonObject user = getUser();
// The local Validation Set bound to our "user" object
JsonObjectValidationSet userValidationSet = user.validationSet();
// We validate the email of the user directly
ValidationSet lastResult = userValidationSet.validationEmail()
.jsonPath("email")
.validate();
// We use an *external validator* to validate the company
// of the user
ValidationSet companyValidationSet =
getCompanyValidator().validateCompany(user.getJsonObject("company"));
// We merge the Validation Set of the company validation
// to our local set!
userValidationSet.mergeValidationSet("company.", companyValidationSet);
Explanation :
user object
containing an email and a company
field, and we want to validate it.
Validation Set
of the user : this set will contain all the Validation Messages at the end
of the validation process.
Validation Set.
Validation Set containing the Validation Messages
resulting from this company validation.
19 : We merge the
Validation Set for the company element into our user Validation Set,
and we scope its validation keys using the "company." prefix.
At this point, the user Validation Set contain both the Validation Messages
for the email field, and the Validation Messages for
the company field. If printed, the set
would look something like this, given that both the email and
the company were invalid :
messages =
{
email = [Invalid email address - VALIDATION_TYPE_EMAIL] java.util.ArrayList
company.name = [Can't be empty - VALIDATION_TYPE_NOT_BLANK] java.util.ArrayList
}
When you merge two Validation Sets, don't forget to scope the merged
validation keys (if required)... Learn more about this in the Validation Keys
section!
Being able to share and merge Validation Sets allows you to be creative and structure your
application as you wish. You can have standalone validators that are used in multiple places and situations.
When your validation is done, you will want to use the Validation Messages saved in
the Validation Set. In some cases, you need to serialize them to Json, for example to
send them as a response to an Ajax call.
To do that, you simply call the convertToJsonObject()
method on the Validation Set. This will convert the set to a JsonObject which, in turn,
can easily be serialized to a plain Json string.
When you convert a Validation Set to a JsonObject, an
extra root element is added (in addition to the Validation Messages) :
"_". This special "_" element summarizes the validation performed using the
Validation Set. It contains those fields :
isValid : Is the whole set valid? It is if it contains no Error Validation Messages.
hasErrors : Does the set contain Error Validation Messages?
hasWarnings : Does the set contain Warning Validation Messages?
hasSuccesses : Does the set contain Success Validation Messages?
Have a look at the Displaying validation messages section to
see the use of this "_" element in action!