Spring mvc validate a primitive with #RequestBody doesn't work - java

I'm trying to validate an email that I receive from the post request body but it's doesn't work !
#RequestMapping(value = "myservice/emails", method = RequestMethod.POST)
public String requestFoo(#RequestBody #Email String email) {
return email;
}
When I send a request with a string that doesn't respect the email regex the function is executed and I receive a 200 status code.
Even do I add the #Valid annotation the result is always the same.
#RequestMapping(value = "myservice/emails", method = RequestMethod.POST)
public String testValidation(#Valid #RequestBody #Email String email) {
return email;
}

Start with Spring 3.2 #RequestBody method argument may be followed by Errors object, hence allowing handling of validation errors in the same #RequestMapping :
#RequestMapping(value = "myservice/emails", method = RequestMethod.POST)
public ResponseEntity<String> testValidation(#Valid #RequestBody #Email String email, Errors errors) {
if (errors.hasErrors()) {
return ResponseEntity.badRequest().body(ValidationErrorBuilder.fromBindingErrors(errors));
}
return email;
}
And create a custom validator :
public class ValidationErrorBuilder {
public static ValidationError fromBindingErrors(Errors errors) {
ValidationError error = new ValidationError("Validation failed. " + errors.getErrorCount() + " error(s)");
for (ObjectError objectError : errors.getAllErrors()) {
error.addValidationError(objectError.getDefaultMessage());
}
return error;
}
}

Related

Spring doesn't validate JSON request

When I send the request:
"Person": {
"name": 5
}
The request should fail (bad request) because 5 isn't a String. It prints: Person{name='5'}.
Similarly, there's no error when I send null.
I have these annotations:
#JsonProperty("name")
#Valid
#NotBlank
private String name;
Controller:
public void register(#Valid #RequestBody Person p) {
...
}
How can I make it validate the name so only strings are accepted?
Add a BindingResult parameter.
public void register(#Valid #RequestBody Person p, BindingResult result) {
if (result.hasErrors()) {
// show error message
}
}
How can I make it validate the name so only strings are accepted?
Use the #Pattern annotation.
#JsonProperty("name")
#Valid
#NotBlank
#Pattern(regexp="^[A-Za-z]*$", message = "Name should contains alphabetic values only")
private String name;
For more details check this link and this one for the regex.

Hystrix: how to perform #Requestparam and bean validation?

I am trying to perform some parameters validations on my rest controller, by using the JSR-303 bean validation. However, all validations are ignored when I annotate my method with the #HystrixCommand annotation.
For example :
#RestController
#Validated
public class TestController {
//This method ignore all validations :(, even if age < 10
#HystrixCommand(fallbackMethod = "fallback")
#RequestMapping(value = "/notok", method = RequestMethod.GET)
ResponseEntity<String> methodNotOk(
HttpServletRequest request,
#Min(10) #RequestParam(name = "age") final int age
) {
return ResponseEntity.ok("Age is " + age);
}
//This method will raised an error if age < 10, because of the age validation.
//This is the expected behavior
#RequestMapping(value = "/ok", method = RequestMethod.GET)
ResponseEntity<String> methodOk(
HttpServletRequest request,
#Min(10) #RequestParam(name = "age") final int age
) {
return ResponseEntity.ok("Age is " + age);
}
//Hystrix fallback
private ResponseEntity<String> fallback(HttpServletRequest request, #RequestParam("age") final int age, Throwable e) {
return ResponseEntity.badRequest().body("error");
}
}
For the methodNotOk, the #Min annotation is totally ignored, so the server can respond Age is 5, which is incorrect for this test case.
But, if I remove the #HystrixCommand, all go like clockwork.
So the question is how can I validate some method parameters when using #HystrixCommand ?
Thanks for the help
I have the same problem and I have not found anything on the internet.
I think the cause is the order that the Aspects are loaded (HystrixCommandAspect create a proxy of your Bean before that Validator is loaded), but I can not find a way to change it using the Java configuration of Spring
My last resort has been to move the logic to another Bean with #HystrixCommand, and then use the delegate pattern in the Controller
#RestController
#Validated
public class TestController {
#Autowired
private TestHystrixController delegate;
#RequestMapping(value = "/notok", method = RequestMethod.GET)
ResponseEntity<String> methodNotOk(HttpServletRequest request,
#Min(10) #RequestParam(name = "age") final int age) {
return delegate.methodNotOk(request, age);
}
}
#Controller
class TestHystrixController {
#HystrixCommand(fallbackMethod = "fallback")
ResponseEntity<String> methodNotOk(HttpServletRequest request,
final int age) {
return ResponseEntity.ok("Age is " + age);
}
}

Spring REST Integration tests, entity is not deleted

I have a UserControllerTest which is testing my UserConstroller. There is a test:
#Test
public void shouldRemoveUser() throws Exception {
mockMvc.perform(put("/user/register?email=test5#gmail.com&password=aaa"))
.andExpect(status().isOk());
mockMvc.perform(get("/user?email=test5#gmail.com"))
.andExpect(status().isOk());
mockMvc.perform(delete("/user?email=test5#gmail.com"))
.andExpect(status().isOk());
mockMvc.perform(get("/user?email=test5#gmail.com"))
.andExpect(status().isNotFound());
}
And the implementation which I want to test:
#RequestMapping(value = "register")
public ResponseEntity<?> createUser(
#RequestParam(value = "email") String email,
#RequestParam(value = "password", defaultValue = "") String password) {
MyUser myUser = new [...]
userRepository.save(myUser );
return ResponseEntity.ok(myUser);
}
#RequestMapping(method = RequestMethod.DELETE)
public ResponseEntity<?> delete(#RequestParam(value = "email") String email) {
MyUser userByEmail = userRepository.findMyUserByEmail(email);
if (userByEmail == null) {
LOG.debug("Cannot delete user with id: {}", email);
throw new UserNotFoundException("Cannot find user with email: " + email);
}
userRepository.delete(userByEmail);
return ResponseEntity.ok().build();
}
Turns out that the method delete works perfectly fine when fired via Postman or any other Rest Client. However, in tests the result is as follows:
java.lang.AssertionError: Status
Expected :404
Actual :200
It seams like the user is somehow not deleted when the code runs in tests.
In test I used H2, but when I tried to test it manually via Postman I used PostgreSQL.

javax bean validation not working on method parameters

javax validation not working on method parameters.. This is a test code and none of javax validation works on method parameter...
#RequestMapping(value = "/{id}", method = RequestMethod.PUT, params = "action=testAction")
public Test update(
#Size(min = 1) #RequestBody List<String> ids,
#Min(3) #PathVariable String name) {
return doSomething(ids, name);
}
But i have class level validations which works perfectly...
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public RoleType create (#RequestBody #Validated(FieldType.class) User user) {
...
}
And
#Size(min = 2, max = 10, groups = { FieldType.class }, message = "Invalid user code")
public String getId() {
return _id ;
}
-- Solution --
all steps followed as per the accepted answer.
And another addition is annoation on class level
#Validated
class UserController
{
#RequestMapping(value = "/{id}", method = RequestMethod.PUT, params ="action=testAction")
public Test update(#Size(min = 1) #RequestBody List<String> ids,#Min(3) #PathVariable String name) {
return doSomething(ids, name);
}
}
you need to register MethodValidationPostProcessor bean to kick method level validation annotation
delegates to a JSR-303 provider for performing method-level
validation on annotated methods.
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
then,
#RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public Test update(
#Size(min = 1) #RequestBody List<String> ids,
#Min(3) #PathVariable("id") String name) {
return doSomething(ids, name);
}
if you want to handle validation exception
#ExceptionHandler(value = { ConstraintViolationException.class })
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleResourceNotFoundException(ConstraintViolationException e) {
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
StringBuilder strBuilder = new StringBuilder();
for (ConstraintViolation<?> violation : violations ) {
strBuilder.append(violation.getMessage() + "\n");
}
return strBuilder.toString();
}

How to validate Controller method argument in Spring with JSR validations?

I am validating my form field with given piece of code.
//controller method
public String addBusiness(#Valid #ModelAttribute("myForm") MyForm myForm, ...)
{
//logic will go here.
}
//form
#Component
public class MyForm{
#Pattern(regexp = "[0-9]{3,10}", message = "should be valid number")
public String getZip_code()
{
return this.zip_code;
}
}
Now I want same validation on zip_code in another method of controller like,
#RequestMapping(value = "${validation.url}", method = RequestMethod.GET)
#ResponseBody
public List<String> getCityList(#RequestParam(value = "zip_code", required = true) final String zip_code)
{
//logic goes here
}
How is it possible?
It's not. #Valid doesn't apply to #RequestParam annotated parameters. You can create a custom HandlerMethodArgumentResolver to do this or do the validation yourself in the method.

Categories