This Tech Bite was brought to you by Tarik Bašić, Junior Test Engineer at Atlantbh.

Tech Bites are tips, tricks, snippets or explanations about various programming technologies and paradigms, which can help engineers with their everyday job.

Introduction

Data validation is the basic requirement for any application, especially web applications that ask for data inputs. E-mail address, age and credit card numbers are examples of input fields that could be validated since they need to have a specific format or be within some expected boundaries.

This Tech Bite shows a brief example of how to leverage out of the box bean validation with spring as well as how to write custom constraint validators. So let’s get started.

Simple bean validation

A common practice would be to annotate our domain (entity) class. This is practical and avoids code duplication because this class is usually accessible from all application layers. Let’s take a look at an example User.class which will serve as an entity. The example makes use of spring validation libraries, but the concept remains the same, which will be demonstrated in the second part of this Tech Bite.

@Entity
public class User {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
 
  @NotNull(message = ”Name must not be null.”)
  private String name;
 
  @Size(min = 10, max = 500, message = ”Some violation message.”)
  private String aboutMe;
 
  @Min(value = 18, message = “Age must be higher than 18”)
  @Max(value = 130, message = “Age must be lower than 130”)
  private int age;
 
  @Email(message = “Invalid e-mail address format”)
  private String email;
 
}

Out of the box validation is achieved via annotations. For the most part these are pretty self-explanatory, though it should be taken into account that some could have different meanings for different data types (@Size for example, validates the length of a List if such element is annotated).

@Entity, @Id, @GeneratedValue – are annotations from  javax.persistence package and are used if we persist our data in a database.

@NotNull, @Size, @Max, @Min, @Email – are bean validation annotations used in our example. It should be mentioned that these are only some of the available validators, but they are the most common. Some other annotations are: @NotEmpty, @NotBlank, @Positive, @Past and so on.

Custom constraint annotations

It is also possible to write custom validators. This can be done through annotations as well. First we write a custom annotation like this WithoutA.java (we dislike the letter “a” for some reason

).

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = WithoutAValidator.class)
public @interface WithoutA {
    String message() default "Hey, there is the letter a there";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Now we write the actual validator WithoutAValidator.class:

// imports
public class WithoutAValidator implements ConstraintValidator<WithoutA, String> {
  
  @Override
  public boolean isValid(String value, ConstraintValidatorContext context)
{
        return !value.contains(“a”);
}
}

By adding our annotation, to the aboutMe field, we would then need to write an about that does not have the letter “a” in it:

@Size(min = 10, max = 500, message = ”Some violation message.”)
@WithoutA
private String aboutMe;

This is all there is to it. Validators do not require additional configuration, the only thing that needs to be done for them to take effect is adding @Valid annotation in our Controllers and Services.

Leave a Reply