Spring #PathVariable integration test - spring

I'm trying ot write an integration test for one of my methods, that handles a form submission.
The problem is that i use #PathVariable int id in the #RequestMapping of my controller.
I get the following error message when my test method reaches the .handle() part.
nested exception is java.lang.IllegalStateException: Could not find #PathVariable [id] in #RequestMapping
So the controller cant reach the id. I'm using request.setRequestURI("/url-" + s.getId()); But appareantly its not helping with setting up #PathVariable.
Is there any way to set up the #PathVariable of my Mock object?
Update:
Yeah, im useing MockHttpServletRequest and annotationMethodHandlerAdapter.handle in my test class.
The Controller:
#RequestMapping(method = RequestMethod.POST, params = {"edit" })
public String onSubmit(#ModelAttribute("sceneryEditForm") SceneryEditForm s,
#PathVariable int id, Model model) {
// some code that useing id
}
The test method:
#Test
public void testEditButton() throws Exception {
MyObject s = new MyObject();
request.setMethod("POST");
request.setRequestURI("/edit-" + s.getId());
request.setParameter("edit", "set");
final ModelAndView mav = new AnnotationMethodHandlerAdapter()
.handle(request, response, controller);
assertViewName(mav, "redirect:/view-" + s.getId());
}

The error is correct: there is no path variable id
You need to add the path expression with an placeholder id
#RequestMapping(value = "/something/{id}",
method = RequestMethod.POST,
params = {"edit" })
public String onSubmit(#ModelAttribute("sceneryEditForm") SceneryEditForm s,
#PathVariable int id, Model model) {
// some code that useing id
}

Related

Spring Controller Test - mockMvc parameter null

I try to test a controller and have a problem because of a parameter.
I recieve an error:
"cannot invoke "java.lang.Integer.intValue()" because "voivodeship" is
null"
It shouldn't be null. because it is an id of last selected voivodeship(option from dropdown list). I think the problem is here .requestAttr("voivodeship", 10). How can i pass this parameter using mockMvc?
#Test
public void selectVoivodeshipTest() throws Exception { //post
Integer voivodeship = 10;
List<Voivodeship> voivodeships = voivodeshipService.findAll();
List<City> cities = cityService.getAllCitiesByVoivodeship(voivodeship);
mockMvc.perform(MockMvcRequestBuilders.post("/select_voivodeship")
.contentType(MediaType.APPLICATION_JSON)
.requestAttr("voivodeship", 10)
.content(new Gson().toJson(voivodeships)))
.andExpect(model().attribute("voivodeships", voivodeships))
.andExpect(model().attribute("voivodeship_selected", voivodeship))
.andExpect(model().attribute("cities", cities))
.andExpect(model().hasNoErrors())
.andExpect(view().name("/taxoffice"))
.andExpect(status().isOk());
}
Controller.java
#RequestMapping(value="/select_voivodeship", method = RequestMethod.POST)
public String selectVoivodeship (int voivodeship, Model model) {
List<Voivodeship> voivodeships = voivodeshipService.findAll();
model.addAttribute("voivodeships", voivodeships);
model.addAttribute("voivodeship_selected", voivodeship);
List<City> cities = cityService.getAllCitiesByVoivodeship(voivodeship);
model.addAttribute("cities", cities);
return "taxoffice";
}
I think that the issue is that in your controller you still have int type for voivodeship, which cannot be null. Change it to Integer to match what you have in your test.
public String selectVoivodeship (Integer voivodeship, Model model) {
Objects can be null, primitive types cannot.

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!

Access absolute path of resource when using #RequestMapping in spring boot controller

I am using #RquestMapping for mapping url to controller method.
#RestController
#RequestMapping(path = "/api/tasks")
public class TaskController { ....
and methods inside controller have /{id} with request mapping annotations.
#RequestMapping(
path = "/{taskId},
method = RequestMethod.GET
)
public Map<String, Object> methodOne(...
I want to access http method and absolute path (configured path) for that method inside.
i.e. I want to get /api/tasks/{taskId} as value (not the /api/tasks/1 if api is called for task id 1) and GET as method inside of the methodOne.
I checked the HandlerMapping but it returns actual path of resource called by client. Not the configured path for the method / resource.
Any help or guidance would be highly appreciated. Thank you.
String[] pathReqMappingAnnotationOnControllerClass = this.getClass().getAnnotation(RequestMapping.class).path();
Method method = TaskApiController.class.getMethod("getListOfTasks", HttpServletRequest.class, HttpServletResponse.class);
String[] pathReqMappingAnnotationOnControllerMethod = method.getAnnotation(RequestMapping.class).path();
String wholePath = pathReqMappingAnnotationOnControllerClass[0] + pathReqMappingAnnotationOnControllerMethod[0];
//pathReqMappingAnnotationOnControllerMethod will be empty array if method is not annotated for path
#RequestMapping(path = "/{id}", method = [RequestMethod.DELETE])
public void test(#PathVariable("id") String id, HttpServletRequest request) {
\\ Code Here
}
In the method parameter, id is the pathVariable. And request method is accessible in the request variable (Although I do not know what is the point as you are limiting it to only accept GET requests)
As suggested by #codedetector, best option is if you have request object or you can add one if you dont have it.
#RequestMapping(path = "/{taskId}, method = RequestMethod.GET)
public String methodOne(HttpServletRequest request){
String test = request.getRequestURI();
return test;
}
If you dont have request object in your method, with below code you can get any URL on your system.
import org.springframework.hateoas.mvc.ControllerLinkBuilder
...
ControllerLinkBuilder linkBuilder = ControllerLinkBuilder.linkTo(methodOn(YourController.class).getSomeEntityMethod(parameterId, parameterTwoId))
URI methodUri = linkBuilder.Uri()
String methodUrl = methodUri.getPath()
--------Edit
I am not sure why you need in this format "/api/tasks/{taskId}" as value (not the /api/tasks/1 )but i can think of using a constant use it for your #RequestMapping path parameter and then easily after getting absolute path , replace/append it with that constant.
String pathParam ="/{taskId}"
#RequestMapping(path = "/{id}", method = [RequestMethod.DELETE])
public void test(#PathVariable("id") String id, HttpServletRequest request) {
switch(id){
case 1:
method1();
break;
case 2:
method2();
break
....
....
}
}
private void method1(){};
private void method2(){};
private void method3(){};

request and session attribute value returns null in #ModelAttribute method

Am using spring mvc i want to access an request attribute inside #ModelAttribute method but its giving only null
#RequestMapping(value = "/abc", method = RequestMethod.GET, params = "data")
public ModelAndView aaaa()
{
String courseId = httpServletRequest.getParameter("courseValue");
System.out.println("course value data :" + courseId); // here am getting value
httpServletRequest.setAttribute("courseId", courseId); // setting in request
attribute
WebUtils.setSessionAttribute(httpServletRequest, "courseId", courseId);
// setting in session attribute
ModelAndView modelAndView = new ModelAndView("abc");
return modelAndView;
}
#ModelAttribute("termList")
public Map<String, String> def(HttpServletRequest httpServletRequest)
{
String courseId = (String) WebUtils
.getSessionAttribute(httpServletRequest, "courseId");
System.out.println("course value in term :" + courseId); // here its giving null
Map<String, String>map = courseSubLinkService.getTermDetailsBasedOnCourseId
(courseId);
httpServletRequest.setAttribute("termList", map);
return map;
}
I dont know where i did wrong please help me to get this value
From Spring docs:
#ModelAttribute methods in a controller are invoked before
#RequestMapping methods, within the same controller
This means that in moment when def is invoked HttpServletRequest hasn't attribute that you need because you set this attribute in aaaa method that will be invoked after def.

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.

Resources