Skip to content

devon4j validations

devonfw-core edited this page Dec 16, 2021 · 14 revisions

devon4j Validations

For validations, devon4j includes the Hibernate Validator as one of the available libraries in the pom.xml file.

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>

Hibernate Validator allow us to check received values, by adding annotations to our Java classes.

MyThaiStar Validations

In the MyThaiStar app, we can find validations for some fields that we receive from the client.

The main part of client inputs is related to the booking process. The client needs to provide: name, comment, bookingDate, email and assistants.

@NotNull
private String name;

...

private String comment;

@NotNull
@Future
private Timestamp bookingDate;

...

@NotNull
@EmailExtended
private String email;

...

@Min(value = 1, message = "Assistants must be greater than 0")
@Digits(integer = 2, fraction = 0)
private Integer assistants;
  • @NotNull: Checks that the field is not null before saving in the database.

  • @Future: Checks that a provided date is not in the past.

  • @Min: Declares a minimum value for an integer.

  • @Digits: Checks the format of an integer.

  • @Email: Is the standard validator for email addresses. In this case the standard validator is not checking the domain of the email, so for MyThaiStar we added a custom validator called @EmailExtended that is defined in a new general/common/api/validation/EmailExtended.java class. We will see it in more detail in the next section.

Add your own Validations

In the JumpTheQueue app, we receive some inputs from the client. So let’s add some validations for that data, to avoid errors and ensure the consistency of the information, before saving it to the database.

When registering a visitor, the client provides the following information:

  • username: Must be not null and must match the format <name>@<domain.toplevel>.

  • name: Must be not null.

  • phoneNumber: Must be not null and must match a sequence of numbers and spaces.

  • password: Must be not null.

  • acceptedCommercial: Must be not null.

  • acceptedTerms: Must be not null.

  • userType: Must be not null.

Name Validation

As we have just mentioned, the name of the visitor must be not null. To do so, Hibernate Validator provides us with the already mentioned @NotNull annotation (javax.validation.constraints.NotNull).

We are going to add the annotation in the jtqj-core to visitormanagement/dataaccess/api/VisitorEntity.java, just before the field name:

...

  @NotNull
  private String name;

...

Run the app with Eclipse and — using Postman — call the register resource via POST:
http://localhost:8081/jumpthequeue/services/rest/visitormanagement/v1/visitor

In the body, provide a visitor object without a name, like so:

{
	"username" : "mary@mail.com",
	"phoneNumber" : "1234567",
	"password" : "12345",
	"acceptedCommercial" : "true",
	"acceptedTerms" : "true",
	"userType" : "false"
}

You will get a ValidationError message regarding the name field:

JumpTheQueue Name Validation

Email Validation

In the case of the email — as already explained in the MyThaiStar section — using the @Email annotation for validation, will allow users to enter emails such as something@something. This does not fit our app requirements, so we need to add a custom email validator.

In jtqj-core, add a class for our annotation, called EmailExtended.java, in a new general.common.api.validation package:

EmailExtended.java
...

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.Email;
import javax.validation.constraints.Pattern;

@Email
@Pattern(regexp = ".+@.+\\..+", message = "Email must specify a domain")
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface EmailExtended {
  String message() default "Please provide a valid email address";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};
}

This validator extends the @Email validation with an extra @Pattern, that defines a regular expression, which the fields annotated with @EmailExtended must match.

Now we can annotate the username field in our VisitorEntity.java with @NotNull and @EmailExtended, to fit the app requirements.

...

  @NotNull
  @EmailExtended
  private String username;

...

Then, if we restart the app and try to register a user without an email, we get a ValidationError with the message: "{username=[must not be null]}":

JumpTheQueue Null E-Mail Validation

And if we provide an email, that does not match the expected format, we get the related ValidationError with the message: "{username=[Email must specify a domain, …​]}":

JumpTheQueue Wrong E-Mail Validation

Finally, if we provide a valid email, the registration process ends successfully.

Phone Validation

For validating the phone, apart from the @NotNull annotation, we need to use another custom validation, based on the @Pattern annotation and a regular expression.

We are going to follow the same approach used for the EmailExtended validation.

In jtqj-core, add a class for our annotation, called Phone.java to the general.common.api.validation package. With the @Pattern annotation we can define a regular expression to filter for phone numbers ("consists of sequence of numbers or spaces"):

Phone.java
...

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.Pattern;

@Pattern(regexp = "[ 0-9]{0,14}$", message = "Phone must be valid")
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface Phone {
  String message() default "Phone must be well formed";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};
}

Then we only need to apply the new validation to our phone field in visitormanagement/dataaccess/api/VisitorEntity.java:

...

  @NotNull
  @Phone
  private String phoneNumber;

...

As a last step, we can now test our new validation. Call the previous service again, defining a wrong phone number. The response should be a ValidationError with the message: "{phoneNumber=[Phone must be valid]}":

JumpTheQueue Wrong Phone Number Validation

If we provide a valid phone number, the process should complete successfully.

In this chapter, we have seen how easy is to add validations to the server side of our devon4j applications. In the next chapter, we will show you how to test our components using Spring Test and devon4j's test module.


Next Chapter: Testing in devon4j