Any way to accept bot json and regular objects in Spring controller - spring

Is this possible to achive in any way?
#RequestMapping(value = "/test", method = RequestMethod.POST)
public String test(#RequestBody Person personJson , Person personRegular){
Person person = personJson != null ? personJson : personRegular;
}

Yes, you can if you send an json representation of Person as POST body it will get bound to personJson, and the request parameters will get bound to personRegular, another way could be to send a id as a request parameter, populate a personRegular module attribute by performing a database lookup, and annotating your personRegular with #ModelAttribute

Related

Spring throw Bad Request if the request param not available in Controller method

I want to restrict the list of allowed request parameters in my controller, so that if I get a request with an undefined parameter in the controller, it should return a bad request, but it returns 200 OK.
I think that this one should be fixed on the framework level, but not in the controller layer.
I am confused about it, and could not find anything on the internet
For e.g I have the following controller definition:
#GetMapping("/Client")
public ResponseEntity<List<Client>> getAllClients(HttpServletRequest httpServletRequest,
#RequestParam(value = McsConstants.PAGE_HEADER, required = false) Integer page,
#RequestParam(value = McsConstants.SIZE_HEADER, required = false) Integer size) {...}
And the valid request would be
GET .../Client
GET .../Client?page=1
GET .../Client?size=10
GET .../Client?page=1&size=10
How can I validate the case when I have an undefined request param like below?
GET .../Client?someUndefinedParam=1
Let me know please for any ideas or links
Thanks!
One way to handle this can be using #RequestParam annotation on a Map or MultiValueMap argument.
The map is populated with all the request parameters, therein you can write your logic to validate and reject unidentified query params.
EDIT: Following is an example for the same-
#RequestMapping(value = "/test", method = RequestMethod.GET)
public void testMethod(#RequestParam Map<String, String> allRequestParams) {
if (!isValidParams(allRequestParams)) {
// isValidParams() will validate the map with a reference map containing all the expected params
// throw BadRequestException here
}
}
Hope this helps!
let me share my knowledge it may helpful for some other scenarios
If the requestparam and variable is same name you no need to mention the value #RequestParam .
below i have mentioned with code example. Please share ur feedback
#GetMapping("/Client")
public ResponseEntity<List<Client>> getAllClients(HttpServletRequest httpServletRequest,
#RequestParam <Optional>Integer page,
#RequestParam <Optional>Integer size) {
//you can do ur logics
}

Issue with Spring Rest #RequestMapping when negating params

I have two spring controller methods :
#RequestMapping(value="/requestotp",method = RequestMethod.POST,params = "!applicationId") //new customer
public OTPResponseDTO requestOTP( #RequestBody CustomerDTO customerDTO){
return customerService.requestOTP(customerDTO);
}
#RequestMapping(value="/requestotp",method = RequestMethod.POST,params = {"idNumber","applicationId"}) //existing customer
public String requestOTP( #RequestParam(value="idNumber") String idNumber , #RequestParam(value="applicationId") String applicationId) {
return customerService.requestOTP(idNumber, applicationId);
}
using "!applicationId" , I am expecting that when I call the url with applicationId parameter there that the second method will be called , but actually when I pass a request like this :
{"idNumber":"345","applicationId":"64536"}
The first method gets called
This is the part of the params paremeters documentation that I rely on :
Finally, "!myParam" style expressions indicate that the specified
parameter is not supposed to be present in the request.
Can't you just simply delete first request params?
#RequestMapping(value="/requestotp",method = RequestMethod.POST) //new customer
public OTPResponseDTO requestOTP( #RequestBody CustomerDTO customerDTO){
return customerService.requestOTP(customerDTO);
}
The issue actually wasn't with negating the parameter, the issue was that I was sending {"idNumber":"345","applicationId":"64536"} in the POST body and I was expecting the variables to be mapped to the method parameters annotated with #RequestParam ... this is not correct ... #RequestParam only map URL parameters .... so the controller was trying to find the best match so it was using the first method as it contained #RequestBody

how to get both value #RequestBody and #RequestParam together

how to get both values #RequestBody and #RequestParam together??
below the code:
#RequestMapping(value = "/sign-up", method = RequestMethod.POST)
public ResponseEntity<?> addUser(#RequestBody User user,#RequestParam("location") String location,#RequestParam("deviceid") String deviceid) {
System.out.println(location);
System.out.println(deviceid);
it is possible?
for #RequestParam Content-Type application/x-www-form-urlencoded
and for #RequestBody Content-type application/json
i want both value location and deviceid if there is any other way?
#PathVariable is to obtain some placeholder from the uri (Spring
call it an URI Template) — see Spring Reference Chapter 16.3.2.2 URI
Template Patterns
#RequestParam is to obtain an parameter — see Spring Reference Chapter 16.3.3.3 Binding request parameters to method parameters with #RequestParam
If URL http://localhost:8080/MyApp/user/1234/invoices?date=12-05-2013 gets the invoices for user 1234 on December 5th, 2013, the controller method would look like:
#RequestMapping(value="/user/{userId}/invoices", method = RequestMethod.GET)
public List<Invoice> listUsersInvoices(
#PathVariable("userId") int user,
#RequestParam(value = "date", required = false) Date dateOrNull) {
...
}
Also, request parameters can be optional, but path variables cannot--if they were, it would change the URL path hierarchy and introduce request mapping conflicts. For example, would /user/invoices provide the invoices for user null or details about a user with ID "invoices"

how to apply post method to all request mappings in spring

How i can access to request POST data from different url-s to one controller method, for example I have /countries & /countries/{id} URL, It works very good with first one, because my code is
#RequestMapping(value = {"/{id}", "/{id}/"}, method = RequestMethod.GET)
public String getCountry(#PathVariable(value = "id", required = true) int id,ModelMap model) {
}
#RequestMapping(method = RequestMethod.POST)
public String deleteCountry(ModelMap model,HttpServletRequest request) {
}
And when I try to request POST data from second url I'm getting
HTTP Status 405 - Request method 'POST' not supported
Which is expectable because I haven't POST method with this mapping, but if I will be made one method for one mapping my code will be too ugly ant terrible, what solution I can use?
Hum why not add the "array" of value to your second method as well ?
#RequestMapping(value = {"", "/{id}"},method = RequestMethod.POST)
public String deleteCountry(ModelMap model,
HttpServletRequest request) {
Btw using POST verb to call an action that looks like it will delete the resource seems wrong, it should be a DELETE verb used
EDIT
But in reality, you should be creating 2 methods, as both those method are not supposed to do the same thing.
POST /countries should be creating country resources
POST /countries/{id} should be doing something else.
For an update prefer PUT /countries/{id}
And for a delete, prefer DELETE /countries/{id}
There is one way to have separate handler interceptors for different controllers.
Refer this link for details.
bind Spring HandlerInterceptor only to one controller
But I feel, it may be good you can create a common method to share business logic for this.
As Interceptor comes with proxy class for your controller which can be avoided unless you have complex logic.

Spring MVC + JSON in #ResponseBody + inheritance

I have a class hierarchy. On the top of it there is a an abstract AnswerUnit class. There are two inheriting classes: OpenQuestionAnswer and MultipleChoiceQuestionAnswer.
I have a .jsp form that sends data (object serialized to JSON) to server with AJAX request and a method in controller to handle it.
#RequestMapping(value = "/test", method = RequestMethod.POST)
public #ResponseBody
String testPostMethod(#RequestBody
OpenQuestionAnswer answer) {
return "home";
}
I would like to be able to take "AnswerUnit answer" as the argument (abstract type instead of concrete type, so I could handle request from different views with one method). When I try to do it there is a problem - server respose is
400 BAD REQUEST he request sent by the client was syntactically incorrect.
I think that the reason is that Spring (Jackson?) isn't able to find out which concrete class he should create and use.
On the client side I know what type of class I send to server.
What is the proper way to tell server which concrete class should be created and filled with my request?
I guess I'm late with response, but anyway:)
http://wiki.fasterxml.com/JacksonAnnotations
You can have this using Jackson Polymorphic type handling
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes(value = {
#JsonSubTypes.Type(name = "answer", value = OpenQuestionAnswer.class),
#JsonSubTypes.Type(name = "multiple", value = MultipleChoiceQuestionAnswer.class)
})
public class AnswerUnit
...
But you would need to add "type" field to your client JSON.

Resources