How to stop after first constraint in springboot for validation - java

i have conrtoller advice:
#ExceptionHandler(ConstraintViolationException.class)
ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException constraintViolationException) {
return new ResponseEntity<>(constraintViolationException.getMessage(), HttpStatus.BAD_REQUEST);
}
i have a controller:
#PostMapping(value="linkSellerBuyer")
#Validated
public String createSellerBuyer(Seller seller, Buyer buyer) {
// some code
return "some response";
}
each model are like:
public class Seller {
#NotEmpty String Email;
// and more and more
}
public class Buyer {
#NotEmpty String Email;
// and more and more
}
the error i get is i always get both seller and buyer errors
eg:
seller: must not be empty, buyer: must not be empty,
i want is
seller: must not be empty
?how can i create code for this?

If you check this out you will see that it validate all parameters at once.
But if you really want only one and first message you can extract it in your handleConstraintViolationException:
#ExceptionHandler(ConstraintViolationException.class)
ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException constraintViolationException) {
return new ResponseEntity<>(constraintViolationException.getConstraintViolations()
.iterator().next().getMessage(),
HttpStatus.BAD_REQUEST);
}

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.

How to perform different Validations for POST , PUT , DELETE in Spring Boot

I am trying to validate Employee Request and the validations should be different for post method,put method and delete method
public class Employee {
#NotNull(message = "Employee Id can not be null")
private Integer id;
#Min(value = 2000, message = "Salary can not be less than 2000")
#Max(value = 50000, message = "Salary can not be greater than 50000")
private Integer salary;
#NotNull(message = "designation can not be null")
private String designation;
}
For post method want to validate all the fields present in the request
#PostMapping("/employees")
public ResponseEntity<Void> addEmployee(#Valid #RequestBody Employee newEmployee) {
Employee emp= service.addEmployee(newEmployee);
if (emp== null) {
return ResponseEntity.noContent().build();
}
return new ResponseEntity<Void>(HttpStatus.CREATED);
}
For my put method I want to validate only Salary field and the remaining fields won't be validated
#PutMapping("/employees/{id}")
public ResponseEntity<Vehicle> updateEmployee(#Valid #RequestBody Employee updateEmployee) {
Employee emp= service.EmployeeById(updateEmployee.getId());
if (null == emp) {
return new ResponseEntity<Employee>(HttpStatus.NOT_FOUND);
}
emp.setSalary(updateEmployee.getSalary());
emp.setDesignation(updateEmployee.getDesignation());
service.updateEmployee(emp);
return new ResponseEntity<Employee>(emp, HttpStatus.OK);
}
For delete I don't want to perform any validation
#DeleteMapping("/employees/{id}")
public ResponseEntity<Employee> deleteEmployee(#Valid #PathVariable int id) {
Employee emp = service.getEmployeeById(id);
if (null == employee) {
return new ResponseEntity<Employee>(HttpStatus.FOUND);
}
service.deleteEmployee(id);
return new ResponseEntity<Employee>(HttpStatus.NO_CONTENT);
}
But if I use #Valid all the methods are getting validated with all the fields.
One way to achieve this, is to use #Validated from org.springframework.validation library instead of using #Valid annotation in the method parameters.
By this, you can group your constraints according to your requirements in the model (first group for POST method, second group for PUT method etc.) In the model, you need to use groups property and specify the name of the group that you want to bind with.
There is a detailed explanation, and giving sample codes about the use of it: here.

How can I detect if the JSON object within Request body is empty in Spring Boot?

I want to return an error when the body of a REST request is empty (e.g contains only {}) but there is no way to detect if the request body contains an empty JSON or not.
I tried to change #RequestBody(required = true) but it's not working.
#PatchMapping("{id}")
public ResponseEntity<Book> updateAdvisor(#PathVariable("id") Integer id,
#Valid #RequestBody BookDto newBook) {
Book addedBook = bookService.updateBook(newBook);
return new ResponseEntity<>(addedBook,HttpStatus.OK);
}
If the body sent contains an empty JSON I should return an exception.
If the body is not empty and at least one element is provided I won't return an error.
Try #RequestBody(required = false)
This should cause the newBook parameter to be null when there is no request body.
The above still stands and is the answer to the original question.
To solve the newly edited question:
Change the #RequestBody BookDto newBook parameter to a String parameter
(for example, #RequestBody String newBookJson).
Perform pre-conversion validation (such as, "is the body an empty JSON string value").
If the body contains valid JSON,
parse the JSON into to an object (example below).
#Autowired
private ObjectMapper objectMapper; // A Jackson ObjectMapper.
#PatchMapping("{id}")
public ResponseEntity<Book> updateAdvisor(
#PathVariable("id") Integer id,
#Valid #RequestBody String newBookJson)
{
if (isGoodStuff(newBookJson)) // You must write this method.
{
final BookDto newBook = ObjectMapper.readValue(newBookJson, BookDto.class);
... do stuff.
}
else // newBookJson is not good
{
.. do error handling stuff.
}
}
Let's suppose you have a Class BookDto :
public class BookDto {
private String bookName;
private String authorName;
}
We can use #ScriptAssert Annotation on Class BookDto:
#ScriptAssert(lang = "javascript", script = "_this.bookName != null || _this.authorName != null")
public class BookDto {
private String bookName;
private String authorName;
}
then in the resource/controller Class:
#PatchMapping("{id}")
public ResponseEntity<Book> updateAdvisor(#PathVariable("id") Integer id,
#Valid #RequestBody BookDto newBook) {
Book addedBook = bookService.updateBook(newBook);
return new ResponseEntity<>(addedBook,HttpStatus.OK);
}
Now #Valid annotation will validate whatever we have asserted in the #ScriptAssert annotation's script attribute. i.e it now checks if the body of a REST request is empty (e.g contains only {}).

#JsonIgnore field is not consuming data from Postman

I have used the #JsonIgnore annotation to prevent exposing the password to the user while sending user details to the user:
public class UserDto {
private String username;
#JsonIgnore
private String password;
}
Below is the response of user API:
{
"username": "test12"
}
But while saving the new user when I am hitting the save API and send
below data, my controller method is consuming null password because of
#JsonIgnore and getting null pointer exception;
{
"username": "test1225",
"password": "admin"
}
Controller method:
#RequestMapping(value = "/addAccount", method = RequestMethod.POST)
public ResponseEntity<Void> addAccount(#RequestBody UserDto userDto) {
User user = new User();
user.setUsername(userDto.getUsername());
user.setPassword(userDto.getPassword());
userService.saveUser(user);
return new ResponseEntity<Void>(HttpStatus.CREATED);
}
Is there any way to ignore the Password parameter when returning
response to the user and not to ignore the password field value when
getting password parameter in request body in controller method?
You can use JsonViews to specify which fields should be included during serialization/deserialization. Take a look at this blog post to learn about JsonViews - http://www.baeldung.com/jackson-json-view-annotation.
For your issue, you can create a view called UserResponse.
public class UserResponse {
}
And annotate the fields of UserDto which you want to return with #JsonView(UserResponse.class)
public class UserDto {
#JsonView(UserResponse.class)
private String username;
private String password;
}
And in your controller, add JsonView annotation on the return type.
public #JsonView(UserResponse.class) ResponseEntity<Void> addAccount(#RequestBody UserDto userDto) {

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

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

Categories