
templates.docs.validation.html Maven / Gradle / Ivy
Show all versions of spincast-website Show documentation
{#==========================================
Docs : "Validation"
==========================================#}
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.
In Spincast, you validate an object using three main steps :
-
You create a Validation Set instance. This is a
container where the results of the validation will be saved.
-
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 Error Validation Messages
resulting from failed validations
("This email is invalid", for example).
-
When the validation is all done, you use the resulting
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...
The Validation Set
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
:
-
An
Error Validation Message
: "The email is invalid."
-
A
Success Validation Message
: "This username is available!"
There are two ways of creating a Validation Set
instance :
-
By injecting and using the
ValidationFactory :
ValidationFactory validationFactory = getValidationFactory();
ValidationSet validationSet = validationFactory.createValidationSet();
-
By using the
validationSet(...)
method on a JsonObject
:
JsonObject responseModel = context.response().getModel();
JsonObjectValidationSet validationSet = responseModel.validationSet();
When you get a 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)
Adds a new Validation Message
to this set, using the
specified validation key.
-
ValidationSet addMessage(String validationKey, ValidationLevel messageLevel, String code, String text)
Creates and adds a new Validation Message
.
-
ValidationSet addError(String validationKey, String code, String text)
Creates and adds a new Error Validation Message
.
-
ValidationSet addWarning(String validationKey, String code, String text)
Creates and adds a new Warning Validation Message
.
-
ValidationSet addSuccess(String validationKey, String code, String text)
Creates and adds a new Success Validation Message
.
-
ValidationSet mergeValidationSet(ValidationSet set)
Merges an existing 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()
Does this Validation Set
contain any
Validation Messages
?
-
boolean hasMessages(String validationKey)
Are there some Validation Messages
associated with the
specified validation key?
-
boolean isWarning()
Returns true
if the Validation Set
contains at least one Warning Validation Message
, but no
Error Validation Messages
.
-
boolean isWarning(String validationKey)
Returns true
if there is
at least one Warning Validation Message
, but no
Error Validation Messages
associated with the
specified validation key.
-
boolean isSuccess()
Returns true
if the validation set
only contains Success Validation Messages
(or contains no messages at all).
-
boolean isSuccess(String validationKey)
Returns true
if there are
only Success Validation Messages
associated with the
specified validation key (or contains no messages at all).
-
boolean isError()
Returns true
if the validation set
contains at least one Error Validation Message
.
-
boolean isError(String validationKey)
Returns 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)
Quick way to get a formatted version of the Validation Messages
.
-
String getMessagesFormatted(String validationKey, ValidationMessageFormatType formatType)
Quick way to get a formatted version of the 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.
Validation Messages
A ValidationMessage
is composed of three things :
-
A
Validation Level
. This level can be :
-
Error
-
Warning
-
Success
-
A
text
, which is the description of the validation result. For
example : "This email is invalid".
-
A
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 :
-
2 : We create a
Validation Set
.
-
3 : The
user
(as a JsonObject
)
that we're going to validate.
-
5 : We get the title of the third book
of the
user
. We use a
JsonPath to target it!
-
6 : We perform a manual validation
on that title. We could use
a Predefined Validation too.
-
8 : We create a
Validation Message
to
represent the validation result.
-
9 : The
level
of this Validation Message.
Here, it's going to be a Warning Validation Message
. The two other possible levels are
Error
and Success
.
-
10 : The
code
(or "type") of the validation
the Validation Message
is associated with.
-
11 : The
text
for the Validation Message
.
-
13 : We add the
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");
Validation Keys
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": "[email protected]"
"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().set("validation", validationSet);
Predefined Validations
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 :
-
You call the associated
validateXXXXXX(...)
method
on your Validation Set
. For example : myValidatorSet.validationNotBlank()
.
This starts a builder to create the validation.
-
You specify a
validation key
using the "key(...)"
method on the builder. This key associate
the resulting Validation Messages
to the validated elements.
For example :
.key("username")
.
-
You specify the
element
to validate. For example :
.element(username)
.
-
You finally call
.validate()
to perform the actual validation.
When the validate()
method is called, the validation
is perform and :
-
The resulting
Validation Messages
are automatically added to the root Validation Set
.
-
A new
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()
Starts the creation of a "not blank" validation (null
, empty or
spaces only).
-
ValidationBuilderKey validationBlank()
Starts the creation of a "must be blank" validation.
-
ValidationBuilderKey validationEmail()
Starts the creation of an email validation.
-
ValidationBuilderKey validationNotNull()
Starts the creation of a "not null" validation.
-
ValidationBuilderKey validationNull()
Starts the creation of a "must be null" validation.
-
ValidationBuilderKey validationPattern(String pattern)
Starts the creation of a "pattern must match" validation.
-
ValidationBuilderKey validationNotPattern(String pattern)
Starts the creation of a "pattern must not match" validation.
-
ValidationBuilderKey validationSize(int size, boolean ignoreNullValues)
Starts the creation of a "size" validation.
-
ValidationBuilderKey validationMinSize(int minSize, boolean ignoreNullValues)
Starts the creation of a "minimum size" validation.
-
ValidationBuilderKey validationMaxSize(int maxSize, boolean ignoreNullValues)
Starts the creation of a "maximum size" validation.
-
ValidationBuilderKey validationLength(int length)
Starts the creation of a "length" validation.
-
ValidationBuilderKey validationMinLength(int minLength)
Starts the creation of a "minimum length" validation.
A null
value makes this validation fail, otherwise
toString()
is called on the object to
check its "length".
-
ValidationBuilderKey validationMaxLength(int maxLength)
Starts the creation of a "maximum length" validation.
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.
Predefine Validation options
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();
In this example, the resulting 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.
-
By default a
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();
In this example, the resulting 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]"
.
-
When using the
"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();
-
When a validation fails, an
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
-
You can specify the text to use for a
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!")
JsonObject validation
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 :
-
2 : When you get a
Validation Set
from a JsonObject
, the type
of this set is JsonObjectValidationSet.
This type extends the ValidationSet base type
and adds some extra functionalities.
-
4 : Because this
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.set("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
.
Sharing / Merging Validation Sets
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 :
-
2 : Let's say this is a
user
object
containing an email
and a company
field, and we want to validate it.
-
5 : We get the
Validation Set
of the user : this set will contain all the Validation Messages
at the end
of the validation process.
-
8-10 : We validate the email of the user
using a predefined validation on our local
Validation Set
.
-
14-15 : We use an external validator
to validate the "company" element of the user! This validation returns
a
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.
Converting to a JsonObject
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!