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

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.

Related

Error 400 when receiving data from URL parameters en Spring MVC

I am trying to receive data from an URL with two parameters like this one:
http://localhost:80000/xxx/xxx/tickets/search?codprovincia=28&municipio=110000
No matter the approach, I am always getting a 400 error, but if I access the URL without the two parameters, the controller returns the view correctly (without the parameters, naturally)
This is the code of my controller:
#Controller
#RequestMapping(value = "/xxx" )
public class BuscadorIncidenciasController extends BaseControllerWeb {
#RequestMapping("tickets")
public String tickets(Model model, #RequestParam ("codprovincia") String codprovincia, #RequestParam ("municipio") String municipio, HttpServletRequest request) throws NoAjaxException {
//...
return CONST.JSP_VIEW;
}
...}
Extra info: if I use this URL:
http://localhost:9081/xxx/xxx/tickets/search/28/790000
And this code:
#Controller
#RequestMapping(value = "/xxx" )
public class BuscadorIncidenciasController extends BaseControllerWeb {
#RequestMapping(value = "buscar/{codprovincia}/{municipio}", method = RequestMethod.GET)
public String buscar(#PathVariable Integer codprovincia, #PathVariable Integer municipio ,Model model, HttpServletRequest request) throws NoAjaxException {
//...
return CONST.JSP_VIEW;
}
...}
It gets the parameters correctly. The problem is that I have to use the first URL. I have reviewed similar questions about similar issues, and I have implemented the solutions to those issues, but I get the 400 error regardless what I try (add value="xxx=, required=false, and other suggestions.)
For RequestParam, you need to explicitly add 'name' attribute
#RequestParam(name = "codprovincia"), #RequestParam (name = "municipio")
No need to for HttpServletRequest, unless you have reason
Also, in your 'tickets' method, RequestMapping is not conforming to your URL path.
I think it should be
#RequestMapping("/xxx/tickets/search")
Cheers!

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

Junit passing multiple parameters to rest service

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.

redirect from get method to post method in spring controller

I have a link retailerId after clicking the link control will go to the below controller:
#Controller
#RequestMapping(value = "/auth/adminsearchowner")
public class AdminSearchOwnerController {
#RequestMapping(value = "/retailerId/{retailerId}",method = RequestMethod.GET)
public ModelAndView viewRetailerInfo(
#PathVariable("retailerId") String retailerId,
#ModelAttribute EditRetailerLifeCycleBean editLicenseBean) {
editLicenseBean.setSelectedIDsString(retailerId);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("editLicenseBean",editLicenseBean);
modelAndView.setViewName("redirect:/auth/adminlicense/viewlicense");
return modelAndView;
}
}
where /auth/adminlicense/viewlicense is in another controller and we have both GET and POST method for this /auth/adminlicense/viewlicense request mapping. I want to call the post method from the earlier controller.
#Controller
#RequestMapping("/auth/adminlicense")
public class AdminViewLicenseController {
#RequestMapping(value = "/viewlicense", method = RequestMethod.GET)
public ModelAndView searchRetailerLicense(
#ModelAttribute("editLicenseBean") EditRetailerLifeCycleBean editLicenseBean,
HttpSession session) {
}
#RequestMapping(value = "/viewlicense", method = RequestMethod.POST)
public ModelAndView getLicenseDetails(
#ModelAttribute EditRetailerLifeCycleBean lifeCycleBean,
HttpSession session) {
}
}
but it is going to GET method. Could you tell me the solution?
There is no solution. A redirect cannot cause a POST to be sent by the browser.
Rethink your design.
Try:
modelAndView.setViewName("forward:/auth/adminlicense/viewlicense");
instead of
modelAndView.setViewName("redirect:/auth/adminlicense/viewlicense");
A design in which you are trying to send some data from one controller(server-side) to another(server-side) via user's browser(client-side) is probably not the best idea, anyway.
Hope it helps!

Spring MVC to Spring REST tutorials misunderstanding

I have developed a Spring MVC - Hibernate application as told here.
Now I am trying to modify this code to create a REST application as told here.
I have added Jackson library to the classpath and added #XmlRootElement.
#XmlRootElement(name = "persons")
public class Person implements Serializable {
But if I do a application/json request then I still get the html code back.
What I am doing wrong / forgot to do?
My controller:
#RequestMapping(value = "/persons", method = RequestMethod.GET)
#ResponseBody
public String getPersons(Model model) {
logger.info("Received request to show all persons");
// Retrieve all persons by delegating the call to PersonService
List<Person> persons = personService.getAll();
model.addAttribute("persons", persons);
return "personspage";
}
Changed the Controller, but get an error:
t
ype Status report
message /Buddies/WEB-INF/jsp/main/persons/1.jsp
description The requested resource (/Buddies/WEB-INF/jsp/main/persons/1.jsp) is not available.
Your controller should look like this:
#RequestMapping(value = "/persons/{id}", method = RequestMethod.GET)
#ResponseBody
public Person getPerson(#PathVariable int id) {
Person person = personService.getPersonById(id);
return person;
}
If you want to return a list of Person objects, you need an extra wrapper object, see: Using JAXB to unmarshal/marshal a List<String>.
You are probably missing AnnotationMethodHandlerAdapter and messageConverter in your spring configuration.

Resources