I'm doing a rest webservice with spring boot and I would like to know if is possible do different validations with bean validation annotations by method with a POJO as param in the controller layer.
example:
POJO:
Public class Person{
#NotNull(forMethod="methodOne")
private String firstName;
#NotNull(forMehotd="methodTwo")
private String lastName;
private String age;
//getter and setter
}
Controller
#RestController
public class controller{
#RequestMapping(....)
public ResponseEntity methodOne(#Valid #RequestBody Person person){
.....
}
#RequestMapping(....)
public ResponseEntity methodTwo(#Valid #RequestBody Person person){
......
}
}
I know that is possible do it with separate parameters in the methods, but I have a POJO with so many attributes. is it possible do something like that?
I think you should use validation groups in your bean validation annotations and use #Validated annotation instead of #Valid annotation. because #Validated annotation has a value properties that specifies a group for validation.
for example:
Public class Person{
#NotNull(groups={MethodOne.class})
private String firstName;
#NotNull(groups={MethodTwo.class})
private String lastName;
private String age;
//getter and setter
}
and
#RestController
public class controller{
#RequestMapping(....)
public ResponseEntity methodOne(#Validated(MethodOne.class) #RequestBody Person person){
.....
}
#RequestMapping(....)
public ResponseEntity methodTwo(#Validated(MethodTwo.class) #RequestBody Person person){
......
}
}
by the way, don't forget that you should create MethodOne and MethodTwo interfaces to use them as your validation groups.
Related
I have a Spring Boot Controller with POST and PUT method's and a custom validator.
#Autowired
PersonValidator validator;
#InitBinder
protected void initBinder(final WebDataBinder binder) {
binder.addValidators(validator);
}
#PostMapping
public ResponseEntity<String> save(#Valid #RequestBody Person person) {}
#PutMapping
public ResponseEntity<String> update(#Valid #RequestBody Person person) {}
Currently both POST and PUT methods are using the same validation rules. QUESTION: I would need to have different validation rules for PUT and POST. Any ideas on how to proceed, how can I use different custom validators within the same RestController?
You can integrate Hibernate Validator in your application if you are using Spring boot. It seems that you need to implement Grouping constraints (https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#chapter-groups)
e.g.
Entity
#NotEmpty(groups = PutValidation.class)
private String field1;
#Size(min = 3, groups = PutValidation.class)
#Size(min = 5, groups = PostValidation.class)
private String field2;
#Min(value = 18, groups = {PostValidation.class,PutValidation.class,Default.class})
private int age;
//Getters/setters
Groups (these are nothing but empty interfaces)
public interface PostValidation {
}
public interface PutValidation {
}
How to use group of constraints in Controller
#PostMapping
public ResponseEntity<String> save(#Validated(PostValidation.class) #RequestBody Person person) {}
#PutMapping
public ResponseEntity<String> update(#Validated(PutValidation.class) #RequestBody Person person) {}
I hope this can help to solve your problem.
Cheers!
You could create your own annotations for each Validator and replace #Valid at each endpoint.
Have a look at #InRange: https://lmonkiewicz.com/programming/get-noticed-2017/spring-boot-rest-request-validation/
How can I inject #RequestBody object(value object) to Spring Service layer?
I want to Inject(Autowired)objects what come from request body values.
HelloController
#Autowired
UserService userService;
(….)
#GetMapping("/hello")
public String hello(
#RequestBody UserRequestBodyDto userDto,
HttpServletResponse response){
return null;
}
UserRequestBodyDto
#Data
public class UserRequestBodyDto{
private String name;
private String address;
}
UserServiceImpl
#Service
public class UserServiceImpl implements UserService{
#AutoWired
public UserServiceImpl(UserRequestBodyDto userDto){
(….)
}
}
In that case, how can I inject UserRequestBodyDto objects into service layer?
Add 'setUserDto' method to UserService is the best way?
or If
convert dto to entity is the best way to inject objets,
how can I manage many of same classes between dto class and entity class?
+a) In my opinion, make a RequestScopedBean is bad way.
ref: Spring: injecting #RequestBody into #Bean
Why you need to #AutoWired a request object? I seems completely unnecessary while doing operation with a request object cause, it will change on every new request.
So you can do operation with request object in the service layer method.
public UserServiceImpl(UserRequestBodyDto userDto){
(….)//do operation with userDto here.
}
Or, I you really need to #AutoWire the request object then declare UserRequestBodyDto userDto in service layer with #AutoWired annotation. And when the service layer method executes just set the values to this.userDto.
#Service
public class UserServiceImpl implements UserService{
#AutoWired
private UserRequestBodyDto userDto;
#AutoWired
public UserServiceImpl(UserRequestBodyDto userDto){
this.userDto = userDto;//Here, setting value of userDto to this.userDto
}
}
I have complex model request class and I am using valid annotation. But it doesnt work in subclasses.
cause=java.lang.NullPointerException detailMessage=HV000028:
Unexpected exception during isValid call.
public class ChangeBlackListStatusRequest {
#Valid
List<CategoryChangeRequest> categoryChangeRequestList;
}
public class CategoryChangeRequest {
#Valid
List<Category> categoryList;
#Valid
List<Service> serviceList;
#Valid
List<Merchant> merchantList;
#Valid
List<Aggregator> aggregatorList;
}
Usually we write
#RestController
public class TestController {
#RequestMapping(value = "/test")
public String test2(#RequestBody #Valid TestClass req) {
return "test2";
}
}
But since it is a REST controller is it possible to configure Spring to use #RequestBody #Valid by default, so these annotations could be omitted?
I have SpringBoot application with that dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
I have a method at my controller as follows:
#RequestMapping(value = "/liamo", method = RequestMethod.POST)
#ResponseBody
public XResponse liamo(XRequest xRequest) {
...
return something;
}
I send a JSON object from my HTML via AJAX with some fields of XRequest type object (it is a plain POJO without any annotations). However my JSON is not constructed into object at my controller method and its fields are null.
What I miss for an automatic deserialisation at my controller?
Spring boot comes with Jackson out-of-the-box which will take care of un-marshaling JSON request body to Java objects
You can use #RequestBody Spring MVC annotation to deserialize/un-marshall JSON string to Java object... For example.
Example
#RestController
public class CustomerController {
//#Autowired CustomerService customerService;
#RequestMapping(path="/customers", method= RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public Customer postCustomer(#RequestBody Customer customer){
//return customerService.createCustomer(customer);
}
}
Annotate your entities member elements with #JsonProperty with corresponding json field names.
public class Customer {
#JsonProperty("customer_id")
private long customerId;
#JsonProperty("first_name")
private String firstName;
#JsonProperty("last_name")
private String lastName;
#JsonProperty("town")
private String town;
}
SpringBoot by default comes with this functionality. You just have to use #RequestBody annotation in parameter declaration of your controller method but in contrast to #so-random-dude's answer you don't have to annotate fields with #JsonProperty, that is not required.
You just have to provide getters and setters for your custom XML object class. I am posting an example below for simplicity.
Example:
Controller method declaration:-
#PostMapping("/create")
public ResponseEntity<ApplicationResponse> createNewPost(#RequestBody CreatePostRequestDto createPostRequest){
//do stuff
return response;
}
Your custom XML object class:-
public class CreatePostRequestDto {
String postPath;
String postTitle;
public String getPostPath() {
return postPath;
}
public void setPostPath(String postPath) {
this.postPath = postPath;
}
public String getPostTitle() {
return postTitle;
}
public void setPostTitle(String postTitle) {
this.postTitle = postTitle;
}
}