- Регистрация
- 1 Мар 2015
- Сообщения
- 5,599
- Баллы
- 155
Validation is a critical aspect of API development to ensure data integrity and early invalid requests detection. In this post, we’ll learn how to implement field-level validation and custom validation logic in Spring REST Framework (SRF) using Dto objects during deserialization.
1. Field-Level Validation with Annotations
The SRF provides the @FieldValidation annotation for quick and declarative validation on DTO fields. You can enforce rules such as minimum/maximum length, numeric ranges, and more.
Example: Basic Field Validation
import io.github.nikanique.springrestframework.annotation.FieldValidation;
import io.github.nikanique.springrestframework.annotation.ReadOnly;
import io.github.nikanique.springrestframework.dto.Dto;
import lombok.Data;
@Data
public class StudentDto extends Dto {
@ReadOnly
private Long id;
@FieldValidation(minLength = 2, maxLength = 50)
private String name;
@FieldValidation(allowNull = false)
private String nationality;
@FieldValidation(minValue = 1, maxValue = 12)
private Integer grade;
}
This declarative validation automatically applies during deserialization. If the incoming request fails these validations, an error response will be generated.
The complete list of supported attributes and their functionality:
1. maxLength and minLength
These attributes validate the length of a string field.
@FieldValidation(minLength = 3, maxLength = 50)
private String name;
This attribute validates whether the field can be blank.
@FieldValidation(blank = false)
private String description;
These attributes validate the numeric range of a field.
@FieldValidation(minValue = 1, maxValue = 12)
private Integer grade;
This attribute specifies whether the field can accept null values.
@FieldValidation(nullable = false)
private String nationality;
These attributes validate whether a date field falls within a specific range. It should be provided in yyyy-MM-dd or yyyy-MM-dd HH:mm:ss formats.
@FieldValidation(minDate = "2000-01-01", maxDate = "2024-12-31")
private String dateOfBirth;
Here’s an example DTO that uses various @FieldValidation attributes to validate input fields:
import io.github.nikanique.springrestframework.annotation.FieldValidation;
import io.github.nikanique.springrestframework.dto.Dto;
import lombok.Data;
@Data
public class StudentDto extends Dto {
@FieldValidation(nullable = false, minLength = 2, maxLength = 50)
private String name; // Must be between 2 and 50 characters, and cannot be null.
@FieldValidation(blank = false)
private String nationality; // Cannot be blank (empty or whitespace).
@FieldValidation(minValue = 1, maxValue = 12)
private Integer grade; // Must be between 1 and 12.
@FieldValidation(minDate = "2000-01-01", maxDate = "2024-12-31")
private String dateOfBirth; // Must be within the specified date range.
}
If a request contains invalid data, SRF will return a structured response with detailed error messages. For example, if the name is too short and grade is out of range, the response will look like this:
Request (Invalid Data)
{
"name": "A",
"nationality": "",
"grade": 13,
"dateOfBirth": "1990-12-31"
}
Response (Validation Errors)
{
"errors": {
"name": "Length must be between 2 and 50 characters.",
"nationality": "Cannot be blank.",
"grade": "Value must be between 1 and 12.",
"dateOfBirth": "Date must be between 2000-01-01 and 2024-12-31."
}
}
For more complex scenarios, you can combine these annotations with custom validation logic by overriding the validate method in your DTO. Here’s an example of overriding the validate method of a Dto:
import io.github.nikanique.springrestframework.annotation.FieldValidation;
import io.github.nikanique.springrestframework.dto.Dto;
import lombok.Data;
import java.util.Map;
@Data
public class ProductDTO extends Dto {
@ReadOnly
private Integer id;
private String model;
@FieldValidation(minLength = 3)
private String company;
@Override
public Map<String, String> validate(Boolean raiseValidationError) throws Throwable {
Map<String, String> validationErrors = super.validate(false);
if (company != null && company.equalsIgnoreCase("BMW")) {
validationErrors.put("company", "Company cannot be BMW.");
}
// Raise validation error if specified
if (!validationErrors.isEmpty() && raiseValidationError) {
throw new ValidationException(validationErrors);
}
return validationErrors;
}
}
The super.validate(false) calls the default validation logic for @FieldValidation annotations to apply base validation logic for standard validations. Here I passed false to called validate method to let the overridden method to send complete validation error in the exception message.
Conclusion
The @FieldValidation annotation in Spring REST Framework (SRF) provides a powerful way to enforce input validation. It simplifies validation for common rules like length, range, nullability, and date constraints. For more complex scenarios, you can combine these annotations with custom validation logic by overriding the validate method in your DTO.
Also Read:
1. Field-Level Validation with Annotations
The SRF provides the @FieldValidation annotation for quick and declarative validation on DTO fields. You can enforce rules such as minimum/maximum length, numeric ranges, and more.
Example: Basic Field Validation
import io.github.nikanique.springrestframework.annotation.FieldValidation;
import io.github.nikanique.springrestframework.annotation.ReadOnly;
import io.github.nikanique.springrestframework.dto.Dto;
import lombok.Data;
@Data
public class StudentDto extends Dto {
@ReadOnly
private Long id;
@FieldValidation(minLength = 2, maxLength = 50)
private String name;
@FieldValidation(allowNull = false)
private String nationality;
@FieldValidation(minValue = 1, maxValue = 12)
private Integer grade;
}
This declarative validation automatically applies during deserialization. If the incoming request fails these validations, an error response will be generated.
The complete list of supported attributes and their functionality:
1. maxLength and minLength
These attributes validate the length of a string field.
- maxLength: The maximum allowed length of the string (default: Integer.MAX_VALUE, meaning no limit).
- minLength: The minimum required length of the string (default: -1, meaning no restriction).
@FieldValidation(minLength = 3, maxLength = 50)
private String name;
- Ensures the name field has a length between 3 and 50 characters.
- If name is shorter than 3 or longer than 50, an error is returned.
This attribute validates whether the field can be blank.
- blank = true: Allows blank values.
- blank = false: Disallows blank values (default).
@FieldValidation(blank = false)
private String description;
- Ensures the description field cannot be blank.
These attributes validate the numeric range of a field.
- minValue: The minimum allowable numeric value (default: Integer.MIN_VALUE).
- maxValue: The maximum allowable numeric value (default: Integer.MAX_VALUE).
@FieldValidation(minValue = 1, maxValue = 12)
private Integer grade;
- Ensures the grade field contains a value between 1 and 12 (inclusive).
This attribute specifies whether the field can accept null values.
- nullable = true: Allows null values (default).
- nullable = false: Disallows null values.
@FieldValidation(nullable = false)
private String nationality;
- Ensures the nationality field cannot be null.
These attributes validate whether a date field falls within a specific range. It should be provided in yyyy-MM-dd or yyyy-MM-dd HH:mm:ss formats.
- minDate: The earliest allowable date (default: "").
- maxDate: The latest allowable date (default: "").
@FieldValidation(minDate = "2000-01-01", maxDate = "2024-12-31")
private String dateOfBirth;
- Ensures the dateOfBirth is between January 1, 2000 and December 31, 2024.
Here’s an example DTO that uses various @FieldValidation attributes to validate input fields:
import io.github.nikanique.springrestframework.annotation.FieldValidation;
import io.github.nikanique.springrestframework.dto.Dto;
import lombok.Data;
@Data
public class StudentDto extends Dto {
@FieldValidation(nullable = false, minLength = 2, maxLength = 50)
private String name; // Must be between 2 and 50 characters, and cannot be null.
@FieldValidation(blank = false)
private String nationality; // Cannot be blank (empty or whitespace).
@FieldValidation(minValue = 1, maxValue = 12)
private Integer grade; // Must be between 1 and 12.
@FieldValidation(minDate = "2000-01-01", maxDate = "2024-12-31")
private String dateOfBirth; // Must be within the specified date range.
}
If a request contains invalid data, SRF will return a structured response with detailed error messages. For example, if the name is too short and grade is out of range, the response will look like this:
Request (Invalid Data)
{
"name": "A",
"nationality": "",
"grade": 13,
"dateOfBirth": "1990-12-31"
}
Response (Validation Errors)
{
"errors": {
"name": "Length must be between 2 and 50 characters.",
"nationality": "Cannot be blank.",
"grade": "Value must be between 1 and 12.",
"dateOfBirth": "Date must be between 2000-01-01 and 2024-12-31."
}
}
2. Overriding the validate Method for Custom LogicNotice that fields marked as @ReadOnly will not be validated because they are excluded from input.
For more complex scenarios, you can combine these annotations with custom validation logic by overriding the validate method in your DTO. Here’s an example of overriding the validate method of a Dto:
import io.github.nikanique.springrestframework.annotation.FieldValidation;
import io.github.nikanique.springrestframework.dto.Dto;
import lombok.Data;
import java.util.Map;
@Data
public class ProductDTO extends Dto {
@ReadOnly
private Integer id;
private String model;
@FieldValidation(minLength = 3)
private String company;
@Override
public Map<String, String> validate(Boolean raiseValidationError) throws Throwable {
Map<String, String> validationErrors = super.validate(false);
if (company != null && company.equalsIgnoreCase("BMW")) {
validationErrors.put("company", "Company cannot be BMW.");
}
// Raise validation error if specified
if (!validationErrors.isEmpty() && raiseValidationError) {
throw new ValidationException(validationErrors);
}
return validationErrors;
}
}
The super.validate(false) calls the default validation logic for @FieldValidation annotations to apply base validation logic for standard validations. Here I passed false to called validate method to let the overridden method to send complete validation error in the exception message.
Conclusion
The @FieldValidation annotation in Spring REST Framework (SRF) provides a powerful way to enforce input validation. It simplifies validation for common rules like length, range, nullability, and date constraints. For more complex scenarios, you can combine these annotations with custom validation logic by overriding the validate method in your DTO.
Also Read: