Reputation: 147
I want to validate my request body with @Valid
annotation, but it's not working in Spring Boot
I have a Request class within JAR file which I can't modify with two fields. One field is of type Object. My controller class accept this class object as a request body. When I pass my below JSON to the controller, validation is not working. Below are code samples.
Request Class:
public class Request {
Object data;
Map<String, Object> meta;
public <T> T getData() throws ClassCastException {
return (T) this.data;
}
}
Another Class:
public class StudentSignUpRequest {
@NotNull(message = "First Name should not be empty")
@Size(max = 64, message = "FirstName should not exceed 64 characters")
private String firstName;
@NotNull(message = "Last Name should not be empty")
@Size(max = 64, message = "LastName should not exceed 64 characters")
private String lastName;
@NotNull(message = "Email cannot be empty")
@Size(max = 50, message = "Email cannot exceed 50 characters")
@Pattern(regexp = EMAIL_REGEX_PATTERN, message = "Email should contain a valid email address.")
private String email;
// other fields
}
Controller Class:
@PostMapping(value = Constants.STUDENT_SIGN_UP)
public Response signUpStudent(@Valid @RequestBody Request request, HttpServletRequest servletRequest) {
// retrieving the actual resource from request payload
StudentSignUpRequest signUpRequest = request.getData(StudentSignUpRequest.class);
// call service to sign-up student
return loginRegistrationService.signUpStudent(signUpRequest);
}
Calling code sets request as below:
StudentSignUpRequest studentSignUpRequest = new StudentSignUpRequest();
//setter methods
Request payload = new Request();
payload.setData(studentSignUpRequest);
This is the request I am sending:
For more than 64 chars for firstName:
Sample JSON:
{
"data": {
"firstName": "student111111111111111111111111111111111111111111111111111111111111",
"lastName": "somesurname",
"email": "[email protected]"
}
}
Where first name not included:
{
"data": {
"lastName": "somesurname",
"email": "[email protected]"
}
}
Here both @Size
as well as @NotNull
annotation not working.
Any solution?
Upvotes: 9
Views: 33597
Reputation: 6689
Yet another reason why @Valid
annotation can be completely ignored is when actual validator library is missing. It may happen if your Spring project does not need database related starter and as a result misses a library like org.hibernate.validator:hibernate-validator
.
Spring even tries to tell you about missing validator in the log, but that message may be lost in a lot of other messages that Spring spits out.
Upvotes: 0
Reputation: 61
to enable validation support in a Spring Boot application.You need this dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Without this dependency, Spring Boot won't automatically process and apply validation rules on your request data, which is why you were not getting the expected validation behavior.So now you do not need to use @Validated annotation just @Valid one beside the @RequestBody
Upvotes: 2
Reputation: 672
did you add following dependency?
spring-boot-starter-validation
also check https://www.baeldung.com/spring-boot-bean-validation
Upvotes: 1
Reputation: 4317
A couple of things here:
The type Object
for data
in Request
class makes it impossible for the validator to know that it is of type StudentSignUpRequest
. So change the data type.
public class Request {
StudentSignUpRequest data;
Map<String, Object> meta;
}
Secondly, though you have added @Valid
in the controller method, in order to validate fields in StudentSignUpRequest
you have to add @Valid here as well. Now, data will be validated if passed in the API request. In case it is absent validation won't take place. If you want to make data to be mandatorily passed add @NotNull as well.
public class Request {
@Valid
@NotNull
StudentSignUpRequest data;
Map<String, Object> meta;
}
Upvotes: 0
Reputation: 342
So you can use below code for validating the same.
public <T> T getData() throws ClassCastException, SomeCustomValidationException {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
Set s = validator.validate(this.data);
//throw SomeCustomValidationException if set is not empty else return this.data
}
Upvotes: 1
Reputation: 14698
Validation would've worked if the Request
class was like;
public class Request {
@Valid
StudentSignUpRequest data;
// other stuff
}
The fact that you have no class type for data
makes it impossible for validation to be applied on it, ignoring the fact that there isn't even a @Valid
annotation on the field. The @Valid
annotation is used to propagate the validation cascade.
But since you cannot modify Request
object, let's continue with another way to handle validation without doing it manually.
Another way is to trigger validation after you get the StudentSignUpRequest
from request
object;
StudentSignUpRequest signUpRequest = request.getData(StudentSignUpRequest.class);
loginRegistrationService.signUpStudent(signUpRequest) // validation will trigger with this call
What you can do is as follows;
@Service
@Validated
public class LoginRegistrationService {
public void signUpStudent(@Valid StudentSignUpRequest signUpRequest) {
// some logic
}
}
with @Validated
annotation, you will activate the validation check for any @Valid
annotated args in public
methods within that class.
Can be used with method level validation, indicating that a specific class is supposed to be validated at the method level (acting as a pointcut for the corresponding validation interceptor)
This can be costly since you'd want to get any constraint violation as soon as possible without doing any costly jobs for an already doomed request.
Upvotes: 12
Reputation: 4446
First use @NotEmpty
, @Notblank
for Strings. Then ensure you import javax.validation.constraints
not that of hibernate. If you are using a custom validator, you will need (final BindingResult bindingResult)
as part of your controller method variable.
Upvotes: 1
Reputation: 125
No validation will work the way you are using it, you need to put @valid on the object inside your request object, but since you dont have control on that class the other way around is extend Request object and override getData method and apply @valid on that method, it should work that way.
Upvotes: 1