CodeGym /Courses /Module 5. Spring /Bean Validation API: annotations @NotNull, @Min, @Max, et...

Bean Validation API: annotations @NotNull, @Min, @Max, etc.

Module 5. Spring
Level 8 , Lesson 1
Available

"In a perfect world, every user would only send correct data..." — sounds like the start of a fairy tale. In reality we deal with typos in forms, required fields forgotten, and even attempts at SQL injections in the name field. That's where data validation comes in — the first line of defense for any web app.

In the previous lecture we briefly mentioned Bean Validation API — a set of annotations that turns data checking from a headache into a simple, understandable process. Let's dig into it a bit more.


What is Bean Validation API?

Bean Validation API is a Java specification (JSR 380) that provides a set of annotations for defining validation rules. It usually works together with Hibernate Validator, which is commonly used as the implementation of this spec in Spring apps.

Bean Validation lets you validate:

  • Object fields (e.g., database entities or DTOs).
  • Method input parameters.
  • Class configurations.

Classic validation example: you need to make sure the user didn't leave the "email" field empty and that it's in a correct format. Instead of writing manual checks (the old good if/else), you can just add the @NotNull annotation to the field.

How does it work?

When Spring processes requests or data, it automatically validates objects annotated with Bean Validation rules. If the data doesn't meet the rules, Spring throws an exception, which we can handle (for example, return the user a message like "Hey, your email is invalid!").


Core Bean Validation API annotations

@NotNull

This annotation guarantees that the field value is not null. Note: it does not check for empty strings. For example:


import jakarta.validation.constraints.NotNull;

public class UserDTO {
    @NotNull(message = "Username cannot be null!")
    private String name;

    // Getters and setters
}

If the name field ends up being null, Spring will throw a validation error with the message "Username cannot be null!".


@Size

@Size is used to check the size of strings, collections, arrays, and other objects. For example, to ensure the username is at least 3 characters and at most 50:


import jakarta.validation.constraints.Size;

public class UserDTO {
    @Size(min = 3, max = 50, message = "Username must be between 3 and 50 characters.")
    private String username;

    // Getters and setters
}

Note: if you only want to check string length, use @Size. If you also need to check for blank strings, add @NotBlank as well.


@Min and @Max

These annotations are used for numeric fields to set minimum and maximum allowed values.

Example: a user's age should be between 18 and 65:


import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Max;

public class UserDTO {
    @Min(value = 18, message = "Age cannot be less than 18.")
    @Max(value = 65, message = "Age cannot be greater than 65.")
    private int age;

    // Getters and setters
}

@Pattern

If you like regular expressions, @Pattern will be handy. This annotation checks strings against a given regex.

Example: phone number format validation


import jakarta.validation.constraints.Pattern;

public class UserDTO {
    @Pattern(regexp = "\\+\\d{1,3}-\\d{9,15}", message = "Phone must be in the format +XXX-XXXXXXXXXXXXX.")
    private String phoneNumber;

    // Getters and setters
}

Here \\+\\d{1,3}-\\d{9,15} means the phone should start with +, followed by 1 to 3 digits, then a dash, and then 9 to 15 digits.


@Email

Can't forget about email addresses! The @Email annotation checks whether the entered string matches an email format:


import jakarta.validation.constraints.Email;

public class UserDTO {
    @Email(message = "Please enter a valid email address.")
    private String email;

    // Getters and setters
}

@NotBlank and @NotEmpty

These annotations specialize in string validation:

  • @NotEmpty ensures the string is not null and its length is greater than 0.
  • @NotBlank additionally ensures the string is not only whitespace.

Example:


import jakarta.validation.constraints.NotBlank;

public class UserDTO {
    @NotBlank(message = "Name cannot be empty or consist only of spaces.")
    private String name;

    // Getters and setters
}

Example: creating an annotated DTO class

Let's put it all together. Imagine we have a user registration form. The user must provide:

  • Name (3 to 50 characters, must not be blank).
  • Age (18 to 65).
  • Email.
  • Password (at least 8 characters).

The code might look like this:


import jakarta.validation.constraints.*;

public class UserRegistrationDTO {

    @NotBlank(message = "Name cannot be blank.")
    @Size(min = 3, max = 50, message = "Username must be between 3 and 50 characters.")
    private String username;

    @Min(value = 18, message = "Age cannot be less than 18.")
    @Max(value = 65, message = "Age cannot be greater than 65.")
    private int age;

    @NotBlank(message = "Email is required.")
    @Email(message = "Please enter a valid email address.")
    private String email;

    @NotBlank(message = "Password is required.")
    @Size(min = 8, message = "Password must be at least 8 characters long.")
    private String password;

    // Getters and setters
}

Now this object can be used for validating incoming data.


Example usage in Spring MVC

It's useful not only to declare validation rules but to see them in action. Let's say we're creating a controller to handle a registration POST request:


import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;

@RestController
@RequestMapping("/users")
@Validated
public class UserController {

    @PostMapping("/register")
    public ResponseEntity<String> registerUser(@Valid @RequestBody UserRegistrationDTO userDTO) {
        // User processing logic (e.g., saving to the database)
        return ResponseEntity.ok("User successfully registered!");
    }
}

Here:

  • The @Valid annotation automatically triggers validation of the incoming UserRegistrationDTO object.
  • If the data doesn't comply with the rules, Spring automatically returns an error (usually a 400 status and an error description).

Common mistakes

Many people make mistakes when using Bean Validation API. Here are a few common issues:

  • Forgetting to include Hibernate Validator in project dependencies. If you're on Spring Boot this is unlikely, since Hibernate Validator is included by default.
  • Incorrect regular expressions. Test your @Pattern or the annotation will reject all values.
  • Missing @Valid annotation. This is especially common in controllers — without it validation won't run.
  • Mixing annotations. For example, using @NotNull where you actually need @NotBlank.

Conclusions

Data validation is not just a checkbox on a developer's to-do list. It's protection of data integrity and the security of both users and the application. Bean Validation API turns that protection into a convenient and powerful tool, making code cleaner and more reliable.

Want to dig deeper? Check out the official Hibernate Validator documentation. You'll find even more interesting features there.

And finally: trust, but verify! User input can sometimes be a Pandora's box — you never know what you'll find in there. From an innocent typo to a sneaky DROP TABLE. So validation isn't a luxury, it's a necessity!

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION