18

I have the following method in my Spring MVC @Controller :

@RequestMapping(method = RequestMethod.GET)
public String testUrl(@RequestParam(value="test") Map<String, String> test) {   
    (...)
}

I call it like this :

http://myUrl?test[A]=ABC&test[B]=DEF

However the "test" RequestParam variable is always null

What do I have to do in order to populate "test" variable ?

2
  • Did you resolve this? If so can you post your answer? Commented Jul 26, 2018 at 15:10
  • Sorry for this late answer, but I can't help anyway. It's been over a year I worked in the project, and from what I remember I couldn't find a viable solution, so I just dropped this part and found an alternative way to do what I was supposed to do. Steel waiting for a solution Commented Dec 19, 2018 at 21:26

6 Answers 6

14

As detailed here https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestParam.html

If the method parameter is Map or MultiValueMap and a parameter name is not specified, then the map parameter is populated with all request parameter names and values.

So you would change your definition like this.

@RequestMapping(method = RequestMethod.GET)
public String testUrl(@RequestParam Map<String, String> parameters) 
{   
  (...)
}

And in your parameters if you called the url http://myUrl?A=ABC&B=DEF

You would have in your method

parameters.get("A");
parameters.get("B");
Sign up to request clarification or add additional context in comments.

2 Comments

I don't need to retrieve all the request parameters, that's why I added (value="test"). And even when retrieving them like that, the url "test[A]=ABC&test[B]=DEF" gives me "test[A]" as key and not just "A"
saved my times.
5

I faced a similar situation where the client sends two groups of variable parameters. Let's call these groups foo and bar. A request could look like:

GET /search?page=2&size=10&foo[x]=aaa&foo[y]=bbb&bar[z]=ccc

I wanted to map these parameters to two distinct maps. Something like:

@GetMapping("/search")
public Page<...> search(Pageable pageable,
        @RequestParam(...) Map<String, String> foo,
        @RequestParam(...) Map<String, String> bar) {
    ...
}

@RequestParam didn't work for me, too. Instead I created a Model class with two fields of type Map<> matching the query parameter names foo and bar (@Data is lombok.Data).

@Data
public static class FooBar {
    Map<String, String> foo;
    Map<String, String> bar;
}

My controller code has changed to:

@GetMapping("/search")
public Page<...> search(Pageable pageable, FooBar fooBar) {
    ...
}

When requesting GET /search?page=2&size=10&foo[x]=aaa&foo[y]=bbb&bar[z]=ccc Spring instantiated the Maps and filled fooBar.getFoo() with keys/values x/aaa and y/bbb and fooBar.getBar() with z/ccc.

Comments

4

You can create a new class that contains the map that should be populated by Spring and then use that class as a parameter of your @RequestMapping annotated method.

In your example create a new class

public static class Form {
   private Map<String, String> test;
   // getters and setters
}

Then you can use Form as a parameter in your method.

@RequestMapping(method = RequestMethod.GET)
public String testUrl(Form form) {
  // use values from form.getTest()
}

2 Comments

This should be selected as the correct answer. I faced a similar problem. See my answer for additional information.
This will force a request body contained of json. GET is the wrong mapping here.
2

Spring doesn't have default conversion strategy from multiple parameters with the same name to HashMap. It can, however, convert them easily to List, array or Set.

@RequestMapping(value = "/testset", method = RequestMethod.GET)
    public String testSet(@RequestParam(value = "test") Set<String> test) {

        return "success";
    }

I tested with postman like http://localhost:8080/mappings/testset?test=ABC&test=DEF

You will see set having data, [ABC, DEF]

1 Comment

I don't need a List but a Map. So in other words I have to create a custom editor ?
2

Your question needs to be considered from different points of view.

  1. first part:

as is mentioned in the title of the question, is how to have Map<String, String> as @RequestParam.

Consider this endpoint:

@GetMapping(value = "/map")
public ResponseEntity getData(@RequestParam Map<String, String> allParams) {
    String str = Optional.ofNullable(allParams.get("first")).orElse(null);
    return ResponseEntity.ok(str);
}

you can call that via:

http://<ip>:<port>/child/map?first=data1&second=data2

then when you debug your code, you will get these values:

> allParams (size = 2)
    > first = data1
    > second = data2

and the response of the requested url will be data1.


  1. second part:

as your requested url shows (you have also said that in other answers' comments) ,you need an array to be passed by url.

consider this endpoint:

public ResponseEntity<?> getData (@RequestParam("test") Long[] testId,
                                  @RequestParam("notTest") Long notTestId)

to call this API and pass proper values, you need to pass parameters in this way:

?test=1&test=2&notTest=3

all test values are reachable via test[0] or test[1] in your code.


  1. third part:

have another look on requested url parameters, like: test[B]

putting brackets (or [ ]) into url is not usually possible. you have to put equivalent ASCII code with % sign.

for example [ is equal to %5B and ] is equal to %5D.

as an example, test[0] would be test%5B0%5D.

more ASCII codes on: https://ascii.cl/

Comments

1

you can use MultiValueMap

MultiValueMap<String, String>

@RequestMapping(method = RequestMethod.GET)
public String testUrl(@RequestParam(value="test") MultiValueMap<String, String> test) {   
    (...)
}

and while testing don't use test[A],test[B]. just use it as stated below.

http://myUrl?test=ABC&test=DEF

test result will be in below format when you print it.

test = {[ABC, DEF]}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.