قيود Bean Validation ومجموعات القيود
تطبيق تعليقات Jakarta Bean Validation التوضيحية مع التجميع لفرض قواعد خاصة بالسياق.
قيود Bean Validation ومجموعات القيود درس مجاني في Spring Boot 4 Complete Guide على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Spring Boot 4 Complete Guide، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Spring Boot 4 Complete Guide 4 دروس في المجموع.
بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.
Why Bean Validation?
In a Spring Boot 4 application you constantly receive untrusted data: request bodies, query params, form submissions. Jakarta Bean Validation (the jakarta.validation API) lets you declare rules as annotations directly on your model fields instead of writing manual if checks everywhere.
- Declarative — the rule lives next to the field it protects.
- Centralized — Spring triggers validation automatically at the controller boundary.
- Consistent — the same annotated class can be validated in the web layer, service layer, or persistence layer.
The reference implementation behind the API is Hibernate Validator, pulled in by the spring-boot-starter-validation dependency.
Adding the Starter
Validation is not bundled with the web starter anymore, so you must add it explicitly. Once present, Hibernate Validator is auto-configured and Spring wires a Validator bean for you.
Add the dependency to your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>Annotating a DTO
You attach constraints to the fields of a Data Transfer Object. Each annotation carries an optional message and validation parameters.
@NotBlank— the string must contain at least one non-whitespace character.@Email— must look like a valid email address.@Size(min, max)— length must fall within range.@Min/@Max— numeric bounds.
public class UserRegistrationRequest {
@NotBlank(message = "Username is required")
@Size(min = 3, max = 20)
private String username;
@NotBlank
@Email(message = "Provide a valid email")
private String email;
@Min(value = 18, message = "Must be at least 18")
private int age;
// getters and setters
}Triggering Validation with @Valid
Annotating the DTO alone does nothing. You must tell Spring to validate the argument by placing @Valid on the controller method parameter. If validation fails, Spring throws a MethodArgumentNotValidException before your method body ever runs, and returns a 400 Bad Request.
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ResponseEntity<String> register(
@Valid @RequestBody UserRegistrationRequest request) {
// reaches here only if all constraints pass
return ResponseEntity.ok("Registered " + request.getUsername());
}
}The Problem: One DTO, Many Contexts
Imagine the same UserRegistrationRequest is reused for two operations:
- Create — the client must NOT send an
id(the server generates it). - Update — the client MUST send an existing
idto know what to modify.
A field that should be @Null on create but @NotNull on update cannot be expressed with plain annotations, because they always fire. This is exactly the problem constraint groups solve.
Defining Constraint Groups
A constraint group is just a marker interface — an empty interface used purely as a tag. You create one per validation context.
Every constraint annotation accepts a groups attribute. When you assign a constraint to a group, that constraint only runs when validation is requested for that group.
public interface OnCreate {}
public interface OnUpdate {}Assigning Constraints to Groups
Now tag each constraint with the group(s) it belongs to. A constraint with no groups attribute implicitly belongs to the built-in Default group and runs unless you switch groups.
Here the id field obeys opposite rules depending on context:
public class ProductRequest {
@Null(groups = OnCreate.class,
message = "id must be empty when creating")
@NotNull(groups = OnUpdate.class,
message = "id is required when updating")
private Long id;
@NotBlank(groups = {OnCreate.class, OnUpdate.class})
private String name;
@Positive(groups = {OnCreate.class, OnUpdate.class})
private BigDecimal price;
// getters and setters
}Selecting a Group with @Validated
Here is the crucial distinction: @Valid always validates the Default group only and cannot select a group. To activate a specific group you must use Spring's @Validated annotation, which accepts the target group class.
Each endpoint picks the group that matches its operation:
@RestController
@RequestMapping("/api/products")
public class ProductController {
@PostMapping
public ResponseEntity<Void> create(
@Validated(OnCreate.class) @RequestBody ProductRequest req) {
// @Null id, @NotBlank name, @Positive price enforced
return ResponseEntity.status(HttpStatus.CREATED).build();
}
@PutMapping
public ResponseEntity<Void> update(
@Validated(OnUpdate.class) @RequestBody ProductRequest req) {
// @NotNull id enforced instead
return ResponseEntity.ok().build();
}
}@Valid vs @Validated
This pair trips up many developers, so commit it to memory:
@Valid— comes fromjakarta.validation. Works on fields for nested/cascading validation, but cannot specify a group (usesDefault).@Validated— comes fromorg.springframework.validation.annotation. Accepts group classes, and also enables method-level validation on Spring beans. Cannot be placed on a field for cascading.
Rule of thumb: use @Validated(Group.class) at the controller parameter to pick a group; use @Valid on inner object fields to cascade into them.
Cascading and Group Sequences
Two advanced needs come up often:
- Cascading — to validate a nested object, mark its field with
@Valid. Without it, the nested object's constraints are skipped. - Ordering — a
@GroupSequenceruns groups in order and stops at the first group that fails, so you can enforce cheap checks before expensive ones.
@GroupSequence({First.class, Second.class})
public interface OrderedChecks {}
public class OrderRequest {
@NotEmpty(groups = First.class)
private List<@Valid LineItem> items; // @Valid cascades into each item
@AssertTrue(groups = Second.class,
message = "Total must match line items")
public boolean isTotalConsistent() {
return /* expensive cross-field check */ true;
}
}Reading the Errors
When a grouped validation fails, the resulting MethodArgumentNotValidException still carries the standard BindingResult. You can translate it into a clean JSON response with a @RestControllerAdvice handler, mapping each field to its message.
@RestControllerAdvice
public class ValidationExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> handle(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(err ->
errors.put(err.getField(), err.getDefaultMessage()));
return errors;
}
}Quick Check
Test your understanding of how Spring selects a constraint group.
Recap
You learned how to enforce context-specific validation rules with Jakarta Bean Validation in Spring Boot 4:
- Add
spring-boot-starter-validation, then annotate DTO fields with constraints like@NotBlank,@Email,@Size,@Min. - Trigger validation at the controller boundary; a failure yields a 400 via
MethodArgumentNotValidException. - Constraint groups are marker interfaces assigned via each annotation's
groupsattribute, letting one DTO carry different rules per operation (e.g.@Nullon create vs@NotNullon update). - Use
@Validated(Group.class)to select a group —@Validonly runs theDefaultgroup and is for cascading into nested objects. @GroupSequenceorders groups and short-circuits on the first failure;@Validon a collection cascades into each element.
الأسئلة الشائعة
هل درس «قيود Bean Validation ومجموعات القيود» مجاني؟
نعم — نص درس «قيود Bean Validation ومجموعات القيود» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Spring Boot 4 Complete Guide، انتقل إلى CoddyKit PRO. تتضمن دورة Spring Boot 4 Complete Guide 4 دروس في المجموع.
ماذا ستتعلم في «قيود Bean Validation ومجموعات القيود»؟
تطبيق تعليقات Jakarta Bean Validation التوضيحية مع التجميع لفرض قواعد خاصة بالسياق. تتمرن على Spring Boot 4 Complete Guide مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Spring Boot 4 Complete Guide؟
لا تُشترط خبرة سابقة. Spring Boot 4 Complete Guide على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «قيود Bean Validation ومجموعات القيود»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Spring Boot 4 Complete Guide هذا؟
نعم. كل درس في Spring Boot 4 Complete Guide يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- قيود Bean Validation ومجموعات القيود
- إنشاء تعليقات القيود المخصصة
- معالجة الاستثناءات العامة باستخدام @ControllerAdvice
- استجابات تفاصيل المشكلة وفق RFC 7807