Parameter Validation in Spring Boot: @Valid, @Validated, and Custom Annotations

Spring Boot offers several ways to validate request parameters—including the @Valid and @Validated annotations and custom validation annotations—each with its own strengths, allowing developers to enforce data integrity, improve code quality, and enhance user experience across different scenarios.

Java Captain
Java Captain
Java Captain
Parameter Validation in Spring Boot: @Valid, @Validated, and Custom Annotations

In a Spring Boot application, parameter validation is crucial for ensuring logical correctness and preventing invalid data input. Effective validation improves code quality and user experience. This article introduces several approaches to implement parameter validation in Spring Boot and discusses their advantages and disadvantages to help developers choose the most suitable method.

1. Using Spring MVC's @Valid Annotation

Spring MVC provides the @Valid annotation for parameter validation at the controller layer. By adding @Valid to request parameters or request bodies together with JSR‑303/JSR‑380 constraints such as @NotNull and @Size, developers can easily perform validation.

Example code:

<span style="color: #61aeee; line-height: 26px">@RestController</span><br/><span style="color: #c678dd; line-height: 26px">public</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">UserController</span> </span>{<br/><br/>    <span style="color: #61aeee; line-height: 26px">@PostMapping</span>(<span style="color: #98c379; line-height: 26px">"/users"</span>)<br/>    <span style="color: #c678dd; line-height: 26px">public</span> ResponseEntity<?> createUser(<span style="color: #61aeee; line-height: 26px">@Valid</span> <span style="color: #61aeee; line-height: 26px">@RequestBody</span> UserDTO userDTO) {<br/>        <span style="color: #5c6370; font-style: italic; line-height: 26px">// 业务逻辑处理</span><br/>        <span style="color: #c678dd; line-height: 26px">return</span> ResponseEntity.ok().build();<br/>    }<br/>}<br/><br/><span style="color: #c678dd; line-height: 26px">public</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">UserDTO</span> </span>{<br/>    <span style="color: #61aeee; line-height: 26px">@NotNull</span><br/>    <span style="color: #c678dd; line-height: 26px">private</span> Long id;<br/><br/>    <span style="color: #61aeee; line-height: 26px">@Size</span>(min = <span style="color: #d19a66; line-height: 26px">1</span>, max = <span style="color: #d19a66; line-height: 26px">50</span>)<br/>    <span style="color: #c678dd; line-height: 26px">private</span> String name;<br/><br/>    <span style="color: #5c6370; font-style: italic; line-height: 26px">// getters and setters</span><br/>}<br/>

When a client sends a POST request to /users, Spring MVC automatically validates the UserDTO object. If validation fails, a MethodArgumentNotValidException is thrown, which can be handled with custom exception logic.

2. Using Spring Boot's @Validated Annotation

The @Validated annotation, provided by Spring Boot, works similarly to @Valid but offers more power and flexibility, supporting validation groups, nested validation, and other advanced features.

Example code:

<span style="color: #61aeee; line-height: 26px">@RestController</span><br/><span style="color: #61aeee; line-height: 26px">@Validated</span><br/><span style="color: #c678dd; line-height: 26px">public</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">UserController</span> </span>{<br/><br/>    <span style="color: #61aeee; line-height: 26px">@PostMapping</span>(<span style="color: #98c379; line-height: 26px">"/users"</span>)<br/>    <span style="color: #c678dd; line-height: 26px">public</span> ResponseEntity<?> createUser(<span style="color: #61aeee; line-height: 26px">@RequestBody</span> <span style="color: #61aeee; line-height: 26px">@Validated</span> UserDTO userDTO) {<br/>        <span style="color: #5c6370; font-style: italic; line-height: 26px">// 业务逻辑处理</span><br/>        <span style="color: #c678dd; line-height: 26px">return</span> ResponseEntity.ok().build();<br/>    }<br/>}<br/><br/><span style="color: #c678dd; line-height: 26px">public</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">UserDTO</span> </span>{<br/>    <span style="color: #61aeee; line-height: 26px">@NotNull</span>(groups = Create<span style="line-height: 26px">.<span style="color: #c678dd; line-height: 26px">class</span>)<br/>    <span style="color: #e6c07b; line-height: 26px">private</span> <span style="color: #e6c07b; line-height: 26px">Long</span> <span style="color: #e6c07b; line-height: 26px">id</span></span>;<br/><br/>    <span style="color: #61aeee; line-height: 26px">@Size</span>(min = <span style="color: #d19a66; line-height: 26px">1</span>, max = <span style="color: #d19a66; line-height: 26px">50</span>, groups = {Create<span style="line-height: 26px">.<span style="color: #c678dd; line-height: 26px">class</span>, <span style="color: #e6c07b; line-height: 26px">Update</span>.<span style="color: #e6c07b; line-height: 26px">class</span>})<br/>    <span style="color: #e6c07b; line-height: 26px">private</span> <span style="color: #e6c07b; line-height: 26px">String</span> <span style="color: #e6c07b; line-height: 26px">name</span></span>;<br/><br/>    <span style="color: #5c6370; font-style: italic; line-height: 26px">// getters and setters</span><br/><br/>    <span style="color: #c678dd; line-height: 26px">public</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">interface</span> <span style="color: #e6c07b; line-height: 26px">Create</span> </span>{}<br/>    <span style="color: #c678dd; line-height: 26px">public</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">interface</span> <span style="color: #e6c07b; line-height: 26px">Update</span> </span>{}<br/>}<br/>

By defining interfaces as validation groups, different validation rules can be applied in different scenarios—for example, validating only the id field when creating a user and both id and name when updating.

3. Custom Validation Annotations

Beyond the standard JSR‑303/JSR‑380 constraints, Spring Boot also supports custom validation annotations. Developers can define their own validation rules and implement them via custom annotations.

Example code:

<span style="color: #61aeee; line-height: 26px">@Target</span>({ElementType.FIELD, ElementType.PARAMETER})<br/><span style="color: #61aeee; line-height: 26px">@Retention</span>(RetentionPolicy.RUNTIME)<br/><span style="color: #61aeee; line-height: 26px">@Constraint</span>(validatedBy = UniqueUserNameValidator<span style="line-height: 26px">.<span style="color: #c678dd; line-height: 26px">class</span>)<br/><span style="color: #e6c07b; line-height: 26px">public</span> @<span style="color: #e6c07b; line-height: 26px">interface</span> <span style="color: #e6c07b; line-height: 26px">UniqueUserName</span> </span>{<br/>    <span style="line-height: 26px">String <span style="color: #61aeee; line-height: 26px">message</span><span style="line-height: 26px">()</span> <span style="color: #c678dd; line-height: 26px">default</span> "用户名必须唯一"</span>;<br/><br/>    Class<?>[] groups() <span style="color: #c678dd; line-height: 26px">default</span> {};<br/><br/>    Class<? extends Payload>[] payload() <span style="color: #c678dd; line-height: 26px">default</span> {};<br/>}<br/><br/><span style="color: #c678dd; line-height: 26px">public</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">UniqueUserNameValidator</span> <span style="color: #c678dd; line-height: 26px">implements</span> <span style="color: #e6c07b; line-height: 26px">ConstraintValidator</span><<span style="color: #e6c07b; line-height: 26px">UniqueUserName</span>, <span style="color: #e6c07b; line-height: 26px">String</span>> </span>{<br/>    <span style="color: #61aeee; line-height: 26px">@Autowired</span><br/>    <span style="color: #c678dd; line-height: 26px">private</span> UserService userService;<br/><br/>    <span style="color: #61aeee; line-height: 26px">@Override</span><br/>    <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">public</span> <span style="color: #c678dd; line-height: 26px">void</span> <span style="color: #61aeee; line-height: 26px">initialize</span><span style="line-height: 26px">(UniqueUserName constraintAnnotation)</span> </span>{<br/>    }<br/><br/>    <span style="color: #61aeee; line-height: 26px">@Override</span><br/>    <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">public</span> <span style="color: #c678dd; line-height: 26px">boolean</span> <span style="color: #61aeee; line-height: 26px">isValid</span><span style="line-height: 26px">(String value, ConstraintValidatorContext context)</span> </span>{<br/>        <span style="color: #c678dd; line-height: 26px">return</span> userService.checkUserNameUnique(value);<br/>    }<br/>}<br/><br/><span style="color: #c678dd; line-height: 26px">public</span> <span style="line-height: 26px"><span style="color: #c678dd; line-height: 26px">class</span> <span style="color: #e6c07b; line-height: 26px">UserDTO</span> </span>{<br/>    <span style="color: #61aeee; line-height: 26px">@UniqueUserName</span><br/>    <span style="color: #c678dd; line-height: 26px">private</span> String userName;<br/><br/>    <span style="color: #5c6370; font-style: italic; line-height: 26px">// getters and setters</span><br/>}<br/>

The example defines a @UniqueUserName annotation to ensure usernames are unique. By implementing ConstraintValidator, custom validation logic is provided, and the annotation can be applied to fields in DTO classes for automatic validation by Spring Boot.

Conclusion

Spring Boot provides multiple parameter‑validation solutions. Developers can use @Valid or @Validated for straightforward validation, employ validation groups for flexible scenario‑based rules, or create custom annotations for project‑specific requirements. Whichever approach is chosen, emphasis should be placed on code quality, user experience, and accurate validation.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootCustom AnnotationParameter Validation@Validated@Valid
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.