Spring REST: DTO as parameter - values are not urldecoded - spring

I have a REST controller with a RequestMapping that looks like this:
#RequestMapping(method = RequestMethod.GET)
public List<MyDTO> search(SearchParameters searchParameters) {
// ...
}
and call it like that: /data/search?name=some%20value&....
searchParameters is populated, but the values are not being urldecoded. So instead of setting searchParameter's attribute name to "some value" it is "some%20value". How can I instruct Spring to urldecode these values?

One possible solution is to use a Map and have their names stored statically in a class, like :
#RequestMapping(method = RequestMethod.GET)
public List<MyDTO> search(#RequestParam Map<String,String> parameters) {
String name = parameters.get(SearchParameters.NAME);
// ...
}
or use the Map to build the Object SearchParameters:
#RequestMapping(method = RequestMethod.GET)
public List<MyDTO> search(#RequestParam Map<String,String> parameters) {
SeachParameters searchParameters = new SearchParameters(parameters);
// ...
}

Okay, the problem was not actually the decoding, but the encoding. It was encoded in a test case, although it wouldn't have needed to be. So the URL looking like /data/search?name=some%20value should really have been /data/search?name=some value with actual spaces.

Related

DTO has only null with GET request params, but not POST #RequestBody

I'm trying to get my query params in a DTO like in this question but my DTO has always null value.
Is there anything wrong in my code ? I made it as simple as possible.
Queries:
GET http://localhost:8080/api/test?a=azaz => null
POST http://localhost:8080/api/test with {"a":"azaz"} => "azaz"
Controller with a GET and a POST:
#RestController
#RequestMapping(path = {"/api"}, produces = APPLICATION_JSON_VALUE)
public class MyController {
// GET: dto NOT populated from query params "?a=azaz"
#RequestMapping(method = GET, path = "test")
public #ResponseBody String test(TestDto testDto){
return testDto.toString(); // null
}
// POST: dto WELL populated from body json {"a"="azaz"}
#RequestMapping(method = POST, path = "test")
public #ResponseBody String postTest(#RequestBody TestDto testDto){
return testDto.toString(); // "azaz"
}
}
DTO:
public class TestDto {
public String a;
#Override
public String toString() {
return a;
}
}
Thanks !
Full Spring boot sample to illustrate it
The problem is that you are missing setter for the field.
public void setA(String a) {
this.a = a;
}
should fix it.
I'm assuming that you have done required configuration like having Jackson mapper in the class path, consume json attribute, getter and setter in DTO classes etc.
One thing missed here is, in RequestMapping use value attribute instead of path attribute as shown below
#RequestMapping(method = POST, value= "/test", consumes="application/json")
public #ResponseBody String postTest(#RequestBody TestDto testDto){
return testDto.toString();
}
And, make sure that you set content-type="application/json" while sending the request
I think what you are trying to do is not possible. To access the query Parameter you have to use #RequestParam("a"). Then you just get the String. To get your object this way you have to pass json as Parameter. a={"a":"azaz"}
Kind regards

How to pass List<String> in post method using Spring MVC?

I need to pass a list of values in the request body of POST method but I get 400: Bad Request error.
Below is my sample code:
#RequestMapping(value = "/saveFruits", method = RequestMethod.POST,
consumes = "application/json")
#ResponseBody
public ResultObject saveFruits(#RequestBody List<String> fruits) {
...
}
The JSON I am using is: {"fruits":["apple","orange"]}
You are using wrong JSON. In this case you should use JSON that looks like this:
["orange", "apple"]
If you have to accept JSON in that form :
{"fruits":["apple","orange"]}
You'll have to create wrapper object:
public class FruitWrapper{
List<String> fruits;
//getter
//setter
}
and then your controller method should look like this:
#RequestMapping(value = "/saveFruits", method = RequestMethod.POST,
consumes = "application/json")
#ResponseBody
public ResultObject saveFruits(#RequestBody FruitWrapper fruits){
...
}
I had the same use case,
You can change your method defination in the following way :
#RequestMapping(value = "/saveFruits", method = RequestMethod.POST,
consumes = "application/json")
#ResponseBody
public ResultObject saveFruits(#RequestBody Map<String,List<String>> fruits) {
..
}
The only problem is it accepts any key in place of "fruits" but You can easily get rid of a wrapper if it is not big functionality.
You can pass input as ["apple","orange"]if you want to leave the method as it is.
It worked for me with a similar method signature.

Spring MVC parse web url Object

I have a GET request in the format below
http://www.example.com/companies?filters=%7B%22q%22%3A%22aaa%22%7D
After decode it is
filters={"q":"aaa"}
I have created an Object named Filters as below
public class Filters {
private String q;
//getter setter....
}
and in my controller
#RequestMapping(method = RequestMethod.GET)
public List<CompanyDTO> getCompanies(Filters filters) {
filters.getQ();
//do things
}
However, the filters.getQ() is null.
Am I doing something incorrect here?
You need to associate the request parameter to the method argument. Add #RequestParam to your method i.e.
#RequestMapping(method = RequestMethod.GET)
public List<CompanyDTO> getCompanies(#RequestParam(value="filters") Filters filters) {
filters.getQ();
//do things
}
Instead of #RequestParam, use #RequestBody
Instead of String filters=%7B%22q%22%3A%22aaa%22%7D, pass JSON object as parameter http://www.example.com/companies?filters={"q":"aaa"}

how to capture multiple parameters using #RequestParam using spring mvc?

Suppose a hyperlink is clicked and an url is fired with the following parameter list myparam=myValue1&myparam=myValue2&myparam=myValue3 . Now how can I capture all the parameters using #RequestParam in spring mvc?
My requirement is I have to capture all the params and put them in a map.
Please help!
#RequestMapping(value = "users/newuser", method = RequestMethod.POST)
public String saveUser(#RequestParam Map<String,String> requestParams) throws Exception{
String userName=requestParams.get("email");
String password=requestParams.get("password");
//perform DB operations
return "profile";
}
You could use RequestParam in the above mentioned manner.
It seems you can't get
Map<String,String>
because all your params have same name "myparam"
Try this instead:
public ModelAndView method(#RequestParam("myparam") List<String> params) { }
To get all parameters at once try this:
public ModelAndView postResultPage(#RequestParam MultiValueMap<String, String> params)
This feature is described in the #RequestParam java doc (3. Paragraph):
Annotation which indicates that a method parameter should be bound to a web request parameter. Supported for annotated handler methods in Servlet and Portlet environments.
If the method parameter type is Map and a request parameter name is specified, then the request parameter value is converted to a Map assuming an appropriate conversion strategy is available.
If the method parameter is Map<String, String> or MultiValueMap<String, String> and a parameter name is not specified, then the map parameter is populated with all request parameter names and values.
As of Spring 3.0, you can also use MultiValueMap to achieve this:
A rudimentary example would be:
public String someMethod(#RequestParam MultiValueMap<String,String> params) {
final Iterator<Entry<String, List<String>>> it = params.entrySet().iterator();
while(it.hasNext()) {
final String k = it.next().getKey();
final List<String> values = it.next().getValue();
}
return "dummy_response";
}
If anyone is trying to do the same in Spring Boot, use RequestBody in place of RequestParam
Spring mvc can support List<Object>, Set<Object> and Map<Object> param, but without #RequestParam.
Take List<Object> as example, if your object is User.java, and it like this:
public class User {
private String name;
private int age;
// getter and setter
}
And you want pass a param of List<User>, you can use url like this
http://127.0.0.1:8080/list?users[0].name=Alice&users[0].age=26&users[1].name=Bob&users[1].age=16
Remember to encode the url, the url after encoded is like this:
http://127.0.0.1:8080/list?users%5B0%5D.name=Alice&users%5B0%5D.age=26&users%5B1%5D.name=Bob&users%5B1%5D.age=16
Example of List<Object>, Set<Object> and Map<Object> is displayed in my github.
You can use for multiple Params as such
public String saveUser(#RequestParam("email") String userName, #RequestParam("password") String password) throws Exception{
//your code
//perform DB operations
return "profile";
}
For params with same name, you can use MultiValueMap<String ,String>. Then all the values would be present as List
You can use multiple #RequestParam annotations as shown below.
#RequestParam(value="myparam1", required = true) <Datatype> myparam1,
#RequestParam(value = "myparam2", required = false) <Datatype> myparam2,

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