Junit passing multiple parameters to rest service - spring

I have a rest controller like bellow :
#RequestMapping(value = "/create", method = RequestMethod.POST)
public
#ResponseBody
GlobalResponse createDeal(#RequestBody Deal deal,#RequestBody Owner owner) {
// code here
}
I use Junit and Mockito for my test :
#Test
public void createDeal() throws Exception{
this.mockMvc.perform(post("/v1/Deal/create").content("\"deal\":{\"dealNumber\":\"DA001\"},\"owner\":{\"id\":1}").contentType(MediaType.APPLICATION_JSON)).andDo(print());
}
I cant past multiple parameters to the controller service , how can I avoid this ?

You won't be able to pass multiple arguments annotated with #RequestBody annotation. The argument annotated with this annotation holds the whole request body and it can't be split into multiple.
What you can do is to have a wrapper to hold your Deal and Owner objects and you can pass that wrapper as a single request body argument.
For e.g.:
public class Wrapper {
private Deal deal;
private Owner owner;
//Getters and setters
}
And your controller's method:
#RequestMapping(value = "/create", method = RequestMethod.POST)
public
#ResponseBody
GlobalResponse createDeal(#RequestBody Wrapper wrapper) {
// code here
}
Hope this makes sense.

Related

Spring MVC RestController allow params with different names in methods

I am writing an API using Spring MVC and I am coming up with a problem allowing apps written in different languages to consume my API.
It turns out that the "Ruby users" like to have their params named in snake_case and our "Java users" like to have their param names in camel_case.
Is it possible to create my methods that allow param names to be named multiple ways, but mapped to the same method variable?
For instance... If I have a method that accepts a number of variables, of them there is mapped to a postal code. Could I write my method with a #RequestParam that accepts BOTH "postal_code" and "postalCode" and maps it to the same variable?
Neither JAX-RS #QueryParam nor Spring #RequestParam support your requirement i.e., mapping multiple request parameter names to the same variable.
I recommend not to do this as it will be very hard to support because of the confusion like which parameter is coming from which client.
But if you really wanted to handle this ((because you can't change the URL coming from 3rd parties, agreed long back), then the alternative is to make use of HandlerMethodArgumentResolver which helps in passing our own request argument (like #MyRequestParam) to the controller method like as shown in the below code:
Controller class:
#Controller
public class MyController {
#RequestMapping(value="/xyz")
public void train1(#MyRequestParam String postcode) {//custom method argument injected
//Add your code here
}
}
MyRequestParam :
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
public #interface MyRequestParam {
}
HandlerMethodArgumentResolver Impl class:
public class MyRequestParamWebArgumentResolver implements HandlerMethodArgumentResolver {
#Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
MyRequestParam myRequestParam =
parameter.getParameterAnnotation(MyRequestParam.class);
if(myRequestParam != null) {
HttpServletRequest request =
(HttpServletRequest) webRequest.getNativeRequest();
String myParamValueToBeSentToController = "";
//set the value from request.getParameter("postal_code")
//or request.getParameter("postalCode")
return myParamValueToBeSentToController;
}
return null;
}
#Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.getParameterAnnotation(MyRequestParam.class) != null);
}
}
WebMvcConfigurerAdapter class:
#Configuration
class WebMvcContext extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new MyRequestParamWebArgumentResolver());
}
}
I think what you want to do is not allowed by Spring framework with the annotation RequestParam.
But if you can change the code or say to your third party to modify the calls i would suggest you 2 options
Option 1:
Use the #PathVariable property
#RequestMapping(value = "/postalcode/{postalCode}", method = RequestMethod.GET)
public ModelAndView yourMethod(#PathVariable("postalCode") String postalCode) {
//...your code
Here does not matter if the are calling your URL as:
http://domain/app/postalcode/E1-2ES
http://domain/app/postalcode/23580
Option 2:
Create 2 methods in your controller and use the same service
#RequestMapping(value = "/postalcode", method = RequestMethod.GET, params={"postalCode"})
public ModelAndView yourMethod(#RequestParam("postalCode") String postalCode) {
//...call the service
#RequestMapping(value = "/postalcode", method = RequestMethod.GET, params={"postal_code"})
public ModelAndView yourMethodClient2(#RequestParam("postal_code") String postalCode) {
//...call the service
If is possible, I would suggest you option 1 is much more scalable

How to specify multiple parameters in POST method

I have Model called Loan:
public class Loan {
private int loan_id;
private String clientName;
private String clientSurname;
private Double amount;
private int days;
//getters and setters
}
And Controller
#RestController
public class MyController {
#Autowired
MyService myService;
#RequestMapping(value = "/makeAction",method = RequestMethod.POST)
public String makeLoan(){
return myService.makeAction(...);
}
}
The question is: how to bypass multiple variables via adressbar like:
localhost:8080/makeAction?loanId=1#clientName=Stive#clientSurname=Wassabi
and so on.
UPD: Another attempt failed:
#RequestMapping(value="/makeLoan",method = RequestMethod.GET)
public String makeLoan(#PathVariable("loan_id")int loan_id,
#PathVariable("name") String clientName,
#PathVariable("surname") String clientSurname,
#PathVariable("amount") double amount,
#PathVariable("days") int days ) throws Exception {
return myService.makeLoan(loan_id,clientName,clientSurname,amount,days);
P.S tried #PathVariables - failed to use
Thanks you all for helping me with this
The final code looks like that:
#RequestMapping(value = "/makeAction")
public String makeLoan(#RequestParam("loan_id")int loan_id,
#RequestParam("clientName")String clientName,
#RequestParam("clientSurname")String clientSurname,
#RequestParam("amount")double amount,
#RequestParam("days")int days ) throws Exception {
return loanService.makeAction(loan_id,clientName,clientSurname,amount,days);
}
I had to remove GET/POST method and switch #PathVariable to #RequestParam
Well, first of all, you shouldn't put parameters for POST in the URL.
URL parameters are used for GET, and they are separated with & so in your case:
localhost:8080/makeAction?loanId=1&clientName=Stive&clientSurname=Wassabi
For POST you should submit parameters as request body parameters. Parameters are bound with #RequestParam annotation like #SMA suggested.
In your method define them with RequestParam annotation like:
public String makeLoan(#RequestParam(value="clientName", required=false) String clientName) {//and others, and hope you meant & to seperate request parameters.
}
Well, assuming you're using spring MVC, this could be helpful:
How to explictely obtain post data in Spring MVC?
Be aware that if you're using a POST method, your parameters should be read in the request body...

How to call one controller to another controller URL in Spring MVC?

Hi I am new to Spring MVC ,I want to call method from one controller to another controller ,how can I do that .please check my code below
#Controller
#RequestMapping(value="/getUser")
#ResponseBody
public User getUser()
{
User u = new User();
//Here my dao method is activated and I wil get some userobject
return u;
}
#Controller
#RequestMapping(value="/updatePSWD")
#ResponseBody
public String updatePswd()
{
here I want to call above controller method and
I want to update that user password here.
how can I do that
return "";
}
any one help me .
Can do like this:
#Autowired
private MyOtherController otherController;
#RequestMapping(value = "/...", method = ...)
#ResponseBody
public String post(#PathVariable String userId, HttpServletRequest request) {
return otherController.post(userId, request);
}
You never have to put business logic into the controller, and less business logic related with database, the transactionals class/methods should be in the service layer. But if you need to redirect to another controller method use redirect
#RequestMapping(value="/updatePSWD")
#ResponseBody
public String updatePswd()
{
return "redirect:/getUser.do";
}
A controller class is a Java class like any other. Although Spring does clever magic for you, using reflection to examine the annotations, your code can call methods just as normal Java code:
public String updatePasswd()
{
User u = getUser();
// manipulate u here
return u;
}
You should place method getUser in a service (example UserService class) .
In the getUser controller, you call method getUser in the Service to get the User
Similarly, in the updatePswd controller, you call method getUser in the Service ,too
Here no need to add #reponseBody annotation as your redirecting to another controller
Your code will look like
#Controller
class ControlloerClass{
#RequestMapping(value="/getUser",method = RequestMethod.GET)
#ResponseBody
public User getUser(){
User u = new User();
//Here my dao method is activated and I wil get some userobject
return u;
}
#RequestMapping(value="/updatePSWD",method = RequestMethod.GET)
public String updatePswd(){
//update your user password
return "redirect:/getUser";
}
}

Request parameters in spring

I need to take two parameters in my spring controller.
http://mydomain.com/myapp/getDetails?Id=13&subId=431
I have controller which will return Json for this request.
#RequestMapping(value = "/getDetails", method = RequestMethod.GET,params = "id,subId", produces="application/json")
#ResponseBody
public MyBean getsubIds(#RequestParam String id, #RequestParam String subId) {
return MyBean
}
I am getting 400 for when i tried to invoke the URL. Any thoughts on this?
I was able to get it with one parameter.
Try specifying which parameter in the query string should match the parameter in the method like so:
public MyBean getsubIds(#RequestParam("id") String id, #RequestParam("subId") String subId) {
If the code is being compiled without the parameter names, Spring can have trouble figuring out which is which.
As for me it works (by calling: http://www.example.com/getDetails?id=10&subId=15):
#RequestMapping(value = "/getDetails", method = RequestMethod.GET, produces="application/json")
#ResponseBody
public MyBean getsubIds(#RequestParam("id") String id, #RequestParam("subId") String subId) {
return new MyBean();
}
P.S. Assuming you have class MyBean.

Why Spring REST do not analyze "get","post" methods with same url

I am using spring rest , I have two methods
#RequestMapping(value="/",method = RequestMethod.POST)
public #ResponseBody
Object test1(HttpServletRequest request) {}
#RequestMapping(value="/",method = RequestMethod.GET)
public #ResponseBody
Object test2(HttpServletRequest request) {}
But it is not able to detect the two methods. Is it necessary that the URL should be different for each http method in spring.
Spring can support GET and POST for the same url. I've done it many times. For example (this is POST and PUT, but it's the same difference):
#Controller
#RequestMapping(value="player")
public class PlayerController {
#Autowired
private PlayerService playerService;
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public Player createNewPlayer(#RequestBody Player player) {
return playerService.createNewPlayer(player);
}
#RequestMapping(method = RequestMethod.PUT)
#ResponseBody
public Player updatePlayer(#RequestBody Player player) {
return playerService.updatePlayer(player);
}
}
If you can post the error message you're getting, maybe we can help you figure out what's wrong.
I am bit late but i might be useful for someone who still wants to know this concept. In below code we will be getting the error: java.lang.IllegalStateException: Ambiguous mapping.Cannot map 'XXX' method.
#RequestMapping(value="/",method = RequestMethod.POST)
public #ResponseBody
Object test1(HttpServletRequest request) {}
#RequestMapping(value="/",method = RequestMethod.GET)
public #ResponseBody
Object test2(HttpServletRequest request) {}
this error occurs because RequestHandlerMapper delegates the request on the basis of pattern of URL only and not on the method type.Hence if we have the same URL pattern, handlermapping will fail to distinguish that to which method it should map because of ambiguity.

Resources