简体   繁体   中英

Not able to validate request body in Spring boot with @Valid

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": "developer@gmail.com"
    }
}

Where first name not included:

{
    "data": {
        "lastName": "somesurname",
        "email": "developer@gmail.com"
    }
}

Here both @Size as well as @NotNull annotation not working.

Any solution?

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.

没有验证将按照您使用它的方式工作,您需要将 @valid 放在请求对象内的对象上,但由于您无法控制该类,因此另一种方法是扩展 Request 对象并覆盖 getData 方法并应用 @valid在这种方法上,它应该以这种方式工作。

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
}

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.

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;
}

did you add following dependency?

spring-boot-starter-validation

also check https://www.baeldung.com/spring-boot-bean-validation

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM