Overview
Bean Validation is a Java standard (JSR 380) that provides a consistent way to perform validation on Java bean objects.
- primarily uses annotations to define constraints and supports validation at the field, method parameter, constructor parameter, and class levels
- Spring fully integrates
Bean Validationand offers the following features:- Automatic validation of controller method parameters
- Declarative validation support via
@Validand@Validatedannotations - Exception handling mechanisms for validation failures
- Support for custom validator registration and extension
- Bean VS Bean validation
- Tips
- Validation annotations can be applied to fields, parameters, return values, and more.
- The
@Validatedannotation is more flexible than@Valid, allowing the use of validation groups. - You can create custom annotations to abstract complex business rules into reusable validators.
- In production, separate validation failure messages between logging and user feedback for better management.
- Input validation locations (service, controller)
- Custom Validator
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-validation'- transitively includes these dependencies (or compatible versions):
org.hibernate.validator:hibernate-validatororg.glassfish:jakarta.el
Why
- User may make mistake/intentionally submit bad data
- If unchecked this can led to these problems
- Compromised Database Integrity: Storing incorrect or inconsistent data.
- System Exceptions: Causing the application to crash or behave unpredictably.
- Business Logic Errors: Leading to incorrect calculations or process flows.
- Security Threats: Opening vulnerabilities like SQL Injection, Cross-Site Scripting (XSS), etc.
- 4 Potential problems in a Spring application - Invalid User Input
Main annotations
NEED TO KNOW EVERYTHING LOL
| Category | Annotations | Description |
|---|---|---|
| String | @NotNull, @NotEmpty, @NotBlank | Validate null, empty, or blank strings |
| String | @Size, @Length | Validate string length |
| String | @Email, @Pattern | Format validation (email, regex) |
| Number | @Min, @Max, @Range | Numeric range constraints |
| Number | @Positive, @Negative | Sign validation (positive/negative) |
| Number | @Digits, @DecimalMin, @DecimalMax | Precision and decimal validation |
| Date | @Past, @Future, etc. | Time-based validation |
| Collection | @Size, @Valid, element-level annotations | Validate lists/maps and their elements |
@Pattern- Regex is still widely used
- even tho GPT is good at it, it will still be beneficial (and wonโt hurt you) if you get used to it
@NotNull, @NotEmpty, @NotBlank
| Annotation | null | "" (empty) | " " (whitespace) | Best For |
|---|---|---|---|---|
@NotNull | โ | โ | โ | Any object type |
@NotEmpty | โ | โ | โ | Collections, Strings |
@NotBlank | โ | โ | โ | Strings only |
Before and after bean validation
Before (Not using)
public class User {
private String username;
private String email;
private int age;
public User(String username, String email, int age) {
this.username = username;
this.email = email;
this.age = age;
}
// ๊ฒํฐ ์๋ต
}public class Validator {
public static void validateUser(User user) {
if (user.getUsername() == null || user.getUsername().isBlank()) {
throw new IllegalArgumentException("์ฌ์ฉ์ ์ด๋ฆ์ ํ์์
๋๋ค.");
}
if (!user.getEmail().contains("@")) {
throw new IllegalArgumentException("์ด๋ฉ์ผ ํ์์ด ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค.");
}
if (user.getAge() < 18) {
throw new IllegalArgumentException("๋์ด๋ 18์ธ ์ด์์ด์ด์ผ ํฉ๋๋ค.");
}
}
}After (Using)
import jakarta.validation.constraints.*;
public class User {
@NotBlank(message = "์ฌ์ฉ์ ์ด๋ฆ์ ํ์์
๋๋ค.")
private String username;
@Email(message = "์ด๋ฉ์ผ ํ์์ด ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค.")
private String email;
@Min(value = 18, message = "๋์ด๋ 18์ธ ์ด์์ด์ด์ผ ํฉ๋๋ค.")
private int age;
public User(String username, String email, int age) {
this.username = username;
this.email = email;
this.age = age;
}
// ๊ฒํฐ ์๋ต
public String getUsername() { return username; }
public String getEmail() { return email; }
public int getAge() { return age; }
}Validation in Client & Server side
Validation should happen in two key places, with each having a distinct role.
| Location | Primary Role | Examples |
|---|---|---|
| Client-Side (The Browser) | Improve User Experience (UX) by providing instant feedback. | Using HTML5 attributes like required or type="email", and performing checks with JavaScript before submitting a form |
| Server-Side (The Application) | Act as the final authority to guarantee data integrity and enforce security. Client-side validation can be bypassed, so server-side validation is mandatory. | โข @Valid and @Validated annotations โข Flexibly handling validation errors using the BindingResult objectโข Validating complex business rules separately within the service layer |
Some other resources
- ์ ๊ท ํํ์์ ๋ํด์ ๋ ์์๋ณด๊ณ ์ถ๋ค๋ฉด ์๋ ๋งํฌ๋ฅผ ํ์ธํ์ธ์.
์ ๊ท ํํ์์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ์ข
์๋์ง ์์ ํํ์์
๋๋ค. ๋ฐ๋ผ์ ์๋ ๊ด๋ จ ์๋ฃ์์ Java์ ๊ด๋ จ๋ ์๋ฃ๊ฐ ์๋์ด๋ ์ ๊ท ํํ์์ ํ์ตํ๋๋ฐ ์ง์ฅ์ด ์์ผ๋ ์ด ์ ์ฐธ๊ณ ํด์ ๊ด๋ จ ์๋ฃ๋ฅผ ์ดํด๋ณด๊ธฐ ๋ฐ๋๋๋ค.
- ์ ๊ท ํํ์ ๊ด๋ จ ์๋ฃ
- ์ ๊ท ํํ์ ๋ชจ๋ฒ ์ฌ๋ก ์๋ฃ
- Jakarta Bean Validation์ ๋ํด์ ๋ ์์๋ณด๊ณ ์ถ๋ค๋ฉด ์๋ ๋งํฌ๋ฅผ ํ์ธํ์ธ์.
- Jakarta Bean Validation Specification
- Jakarta Bean Validation Built-in Constraint definitions
- Hibernate Validator
- Java Bean์ ๋ํด์ ๋ ์์๋ณด๊ณ ์ถ๋ค๋ฉด ์๋ ๋งํฌ๋ฅผ ํ์ธํ์ธ์.
- Java Bean ๊ด๋ จ ์๋ฃ
- ์ด๋ฉ์ผ ์ฃผ์์ ์คํ์ ๋ํด์ ๋ ์์๋ณด๊ณ ์ถ๋ค๋ฉด ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ์ธ์.