Cannot use Map as a JSON @RequestParam in Spring REST controller
Asked Answered
D

2

2

This controller

@GetMapping("temp")
public String temp(@RequestParam(value = "foo") int foo,
                   @RequestParam(value = "bar") Map<String, String> bar) {
    return "Hello";
}

Produces the following error:

{
    "exception": "org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException",
    "message": "Failed to convert value of type 'java.lang.String' to required type 'java.util.Map'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Map': no matching editors or conversion strategy found"
}

What I want is to pass some JSON with bar parameter: http://localhost:8089/temp?foo=7&bar=%7B%22a%22%3A%22b%22%7D, where foo is 7 and bar is {"a":"b"} Why is Spring not able to do this simple conversion? Note that it works if the map is used as a @RequestBody of a POST request.

Drive answered 22/12, 2017 at 22:45 Comment(3)
And what is the input? My bet is that your query is not valid json.Riva
localhost:8089/temp?blah=%7B%22a%22%20%3A%20%22b%22%7D I want to pass {"a" : "b"}Drive
https://mcmap.net/q/1163720/-how-to-get-variable-html-form-values-post-in-spring-backendMiguelinamiguelita
D
6

Here is the solution that worked: Just define a custom converter from String to Map as a @Component. Then it will be registered automatically:

@Component
public class StringToMapConverter implements Converter<String, Map<String, String>> {

    @Override
    public Map<String, Object> convert(String source) {
        try {
            return new ObjectMapper().readValue(source, new TypeReference<Map<String, String>>() {});
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}
Drive answered 23/12, 2017 at 18:37 Comment(0)
B
3

If you want to use Map<String, String> you have to do the following:

@GetMapping("temp")
public String temp(@RequestParam Map<String, String> blah) {
    System.out.println(blah.get("a"));
    return "Hello";
}

And the URL for this is: http://localhost:8080/temp?a=b

With Map<String, String>you will have access to all your URL provided Request Params, so you can add ?c=d and access the value in your controller with blah.get("c");

For more information have a look at: http://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/spring-mvc-request-param/ at section Using Map with @RequestParam for multiple params

Update 1: If you want to pass a JSON as String you can try the following:

If you want to map the JSON you need to define a corresponding Java Object, so for your example try it with the entity:

public class YourObject {

   private String a;

   // getter, setter and NoArgsConstructor

}

Then make use of Jackson's ObjectMapper to map the JSON string to a Java entity:

@GetMapping("temp")
public String temp(@RequestParam Map<String, String> blah) {
     YourObject yourObject = 
          new ObjectMapper().readValue(blah.get("bar"), 
              YourObject.class);
     return "Hello";
}

For further information/different approaches have a look at: JSON parameter in spring MVC controller

Beetlebrowed answered 22/12, 2017 at 23:14 Comment(3)
Thanks for the answer. What I actually want is to pass JSON as a parameter. See my updated question.Drive
Thanks, I'll check it out. I just hoped there was a cleaner solution than to use ObjectMapper explicitly.Drive
could you map the JSON successfully?Beetlebrowed

© 2022 - 2024 — McMap. All rights reserved.