Skip to main content

Validation in Spring Boot: Complete Guide (Built-in & Custom)

Validation is arguably one of the most critical aspects of enterprise application development. Imagine an Employee Management System exposing a REST API to register new staff. What happens if a client submits this payload?

{ "name": "", "email": "abc", "salary": -1000 }

Without strict validation boundaries, this corrupted data flows through your controller, into your service layer, and straight into your database—causing catastrophic business logic failures down the line.

Spring Boot elegantly solves this by seamlessly integrating with Bean Validation (Jakarta Validation), allowing you to enforce rules using simple annotations before the data ever reaches your business logic.


1. What is Bean Validation?

Standard Definition

Bean Validation is a Java specification that allows developers to define validation constraints directly on object models (DTOs) using annotations.

To enable it in Spring Boot, you include the following starter dependency. Internally, Spring Boot relies on Hibernate Validator as the default engine to execute these rules.

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>

Why Is Validation Required?

  • Prevents bad data from reaching the database.
  • Dramatically improves API security (mitigating injection attacks).
  • Reduces bugs by enforcing assumptions early.
  • Simplifies business logic (Service classes shouldn't contain basic formatting checks).

2. Core Validation Annotations

Let's look at a standard EmployeeRequest DTO and how we validate its fields.

@NotNull

Ensures that a field is not physically null.

@NotNull private Double salary;

Valid: {"salary": 50000}
Invalid: {"salary": null}"salary must not be null"

@NotBlank

Used strictly for Strings. It enforces three rules simultaneously: the string cannot be null, cannot be empty, and cannot consist entirely of whitespace.

@NotBlank private String name;

Valid: {"name": "Madhu"}
Invalid: {"name": ""} or {"name": " "}

@NotEmpty

Ensures the field is not null AND its size/length is greater than 0. It works with Strings, Lists, Sets, and Maps.

@NotEmpty private String department;

The @NotNull vs @NotEmpty vs @NotBlank Debate

This is a favorite interview question. Here is exactly how they differ:

Annotation Null Allowed? Empty "" Allowed? Spaces " " Allowed?
@NotNull No Yes Yes
@NotEmpty No No Yes
@NotBlank No No No

@Size & @Email & @Pattern

  • @Size(min=3, max=50): Enforces boundaries on Strings or Collections.
  • @Email: Validates standard email formatting natively.
  • @Pattern(regexp="^[0-9]{10}$"): Uses Regular Expressions to enforce strict formatting (like exactly 10 digits for a mobile number).

3. Triggering Validation Using @Valid

Important Interview Concept

Question: "I added @NotBlank to my DTO, but invalid data is still passing through. Why?"

Answer: Because validation does not run automatically. You must explicitly trigger the validation engine when the payload enters the controller.

Spring triggers validation using the @Valid annotation inside the controller method signature.

@PostMapping("/employees") public ResponseEntity<EmployeeRequest> saveEmployee( @Valid @RequestBody EmployeeRequest request) { return ResponseEntity.ok(request); }

Internal Working Flow of @Valid

Client JSON Body | DispatcherServlet | @RequestBody Jackson Conversion | Create EmployeeRequest Object | [ @Valid Trigger Detected ] | Invoke Hibernate Validator Engine | Check Rules (@NotBlank, @Email, etc.) | +--------- Is Valid? ---------+ | | YES NO | | Controller Method Execute Throw MethodArgumentNotValidException

If the data is invalid, Spring immediately intercepts it and returns a 400 Bad Request before your controller logic ever executes.


4. Creating Custom Validators

Built-in annotations are powerful, but enterprise business rules often require custom logic.

Business Rule: An Employee ID must strictly begin with the prefix "EMP" (e.g., EMP1001 is valid, ABC1001 is invalid).

Step 1: Create the Custom Annotation

@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = EmployeeCodeValidator.class) public @interface EmployeeCode { String message() default "Invalid Employee Code. Must start with EMP"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }

Step 2: Create the ConstraintValidator Engine

public class EmployeeCodeValidator implements ConstraintValidator<EmployeeCode, String> { @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null) { return false; } return value.startsWith("EMP"); } }

Step 3: Apply the Annotation

public class EmployeeRequest { @EmployeeCode private String employeeCode; }

Real World Use Cases for Custom Validators: PAN Numbers, Indian Aadhaar Validation, GST Numbers, Advanced Password Policies, Company-specific SKU formats.


5. Complete Backend Validation Flow

Client HTTP Request | DispatcherServlet | Jackson JSON Deserialization | @Valid Interceptor | Hibernate Validator Engine | Execute Standard Checks (@NotBlank, @Email) | Execute Custom Checks (EmployeeCodeValidator.isValid()) | [ Validation Success ] | Controller Business Logic | Service -> Database

6. Interview Summary Checklist

Top Interview Q&A

Q1: What is Bean Validation?
A: Bean Validation is a Jakarta specification allowing developers to declare validation rules directly on Java DTOs using annotations. Spring Boot uses Hibernate Validator as its default execution engine.

Q2: What happens internally when @Valid is used?
A: When a request arrives, Spring binds the JSON payload to the Java object. Spotting @Valid, it invokes the Hibernate Validator engine. The engine processes all constraints. If any fail, Spring aborts the controller execution and throws a MethodArgumentNotValidException, automatically returning a 400 Bad Request to the client.

Q3: What is a ConstraintValidator?
A: ConstraintValidator is the core interface used to implement the actual business logic behind a custom validation annotation. It contains the isValid() method which dictates whether the incoming data passes or fails.

Important Internal Classes to Memorize

  • Validator
  • LocalValidatorFactoryBean
  • SpringValidatorAdapter
  • ConstraintValidator
  • MethodArgumentNotValidException
  • BindingResult

Comments

Popular posts from this blog

How I Got Selected in MNC

Virtusa Sometimes success does not come from having the best coding skills or the perfect roadmap. Sometimes it comes from simply refusing to quit. This is the honest story of how I transitioned from a confused, rejected fresher to getting selected as an Associate Engineer at Virtusa. The Beginning: Confused About My Future After completing my graduation, I stared blankly at my career options. Like many freshers, I lacked a clear direction. Should I join a Java course? Should I prepare on my own? Should I just wait for campus placement opportunities? One day, I called my friend Chetan. He suggested I join Naresh i Technologies and start learning Java seriously. Still unsure of my path, I told him I needed time to think about it. A couple of days later, my phone buzzed with a WhatsApp message offering a job opportunity. They asked me to come for the next round of the recruitment process. Excitement completely took over. I packed my bags, traveled to th...

Spring Boot Introduction

Spring Boot Introduction: Architecture, Dependencies, and Embedded Servers Modern enterprise applications demand rapid development, frictionless deployment, and absolute minimal configuration. Before Spring Boot arrived, developers utilizing the Spring Framework wasted immense amounts of time configuring XML files, managing clashing dependencies, setting up clunky application servers, and stitching various Spring modules together manually. To eliminate these bottlenecks, Pivotal introduced Spring Boot . Built entirely on top of the traditional Spring Framework, Spring Boot is an "opinionated" framework. It aggressively simplifies application development by injecting auto-configuration, packaging starter dependencies, and embedding web servers directly into your application. This allows backend developers to focus entirely on building business logic rather than wrestling with infrastructure setup. What is Spring Boot? Spring Boot is a powerful extens...

Strings in C

C Programming: Working with Strings Unlike modern programming languages like Python or Java, C does not possess a dedicated "String" data type. Instead, C treats a string as a simple 1D array of characters. Real-life example: Think of a freight train. The train does not exist as one solid object; it consists of individual boxcars linked together. Similarly, a C string links individual characters side-by-side in memory. To let the computer know the train has ended, C attaches a special "caboose" called the Null Terminator ( \0 ). 1. Essential String Functions Handling strings manually requires complex loops. To save time, C provides a built-in library called <string.h> that contains powerful functions to manipulate text. strlen(): You use this to find the exact length of a string. The compiler counts the characters until it hits the \0 terminator. It does not count the terminator itself. strcpy(): You ...