0

I'm trying to pass a Map< String, String> to Spring via Ajax using @ModelAttribute notation. With IntelliJ's REST client, I just have to add the "infos[KEY]" param with value "VALUE" to get the corresponding key/value couple populated in the hashmap.

I'm trying to reproduce the same behaviour with JQuery

function update()
{
     $.ajax(
          {
            type: "PATCH",
            url: "url",
            dataType: "json",
            data: {"infos[TheAnswer]": "42"},
            success: function(data)
              {
                alert("OK");
              }
          });
}

But Spring controller can't get to populate my model. Here it is (but i shouldn't be the problem because as I said IntelliJ's REST client works fine)

public class ExtraInfos implements Serializable
{
    protected HashMap<String, String> infos = new HashMap<String, String>();

    public HashMap<String, String> getInfos()
    {
        return infos;
    }

    public void setInfos(HashMap<String, String> infos)
    {
        this.infos = infos;
    }
}

Here's my controller's method:

@RequestMapping(value = "/{id}", method = RequestMethod.PATCH)
public
@ResponseBody
Contact updateContact(@PathVariable("id") Long id,
                      @ModelAttribute ExtraInfos infos)
{
    return this.service.update(id, infos);
 }

2 Answers2

2

String modelAttribute doesn't receive the data the way you sent it (json object).

EDIT

The easiest way for you should be to the following:

AJAX:

$.ajax(
          {
            type: "PATCH",
            url: "url",
            dataType: "json",
            data: {TheAnswer: "42"},
            success: function(data)
              {
                alert("OK");
              }
          });

CONTROLLER:

public @ResponseBody Contact updateContact(@PathVariable("id") Long id,
                          @RequestBody ExtraInfos infos){
        }
Shay Elkayam
  • 4,128
  • 1
  • 22
  • 19
  • Unfortunately neither the first nor the second solution works. The second one looked attractive though. –  Mar 17 '14 at 20:48
  • Sorry. lose the type: patch also. I didn't notice it. I updated it in my answer too. – Shay Elkayam Mar 17 '14 at 20:49
  • Also, in order to use the first option, you should send all the fields of ExtraInfos object on the ajax json structure. – Shay Elkayam Mar 17 '14 at 20:51
  • If I drop the type, then the request becomes a GET (by default) request and then the server throws a "405 Method not allowed" –  Mar 17 '14 at 20:53
  • so use type: 'post' both on the controller and the ajax. – Shay Elkayam Mar 17 '14 at 20:54
  • Yes, but I want the method to be PATCH since I'm updating something. –  Mar 17 '14 at 20:57
  • So use the first method, and add all the fields to the ajax structure on the javascript side. It didn't work for you because you sent only "TheAnswer" and not all the fields in the ExtraInfos class – Shay Elkayam Mar 17 '14 at 20:58
  • ExtraInfos only contains one field. I'll try the first one again maybe I did it wrong –  Mar 17 '14 at 21:00
  • send it as {theAnswer: 42} and use @RequestBody – Shay Elkayam Mar 17 '14 at 21:01
  • I've edited my answer to the simplest solution. copy and paste it, I believe it should work. – Shay Elkayam Mar 17 '14 at 21:04
  • Have you managed to get it working with the update I've posted? – Shay Elkayam Mar 17 '14 at 21:11
  • 1
    I didn't tried it because Eduardo's answer worked. Anyway I think you meant contantType instead of dataType no? Anyway thank you! –  Mar 18 '14 at 17:19
-1

Well using this controller

//Just an example

   @RequestMapping(value = "/test/{id}", method = RequestMethod.POST)
    public @ResponseBody Integer extra(@PathVariable("id") Long id, @RequestBody ExtraInfos extraInfos){
            System.out.println(id);
            System.out.println(extraInfos.getInfos());

            return 1;
        } 

The thing here is as the other previously mentioned you need to send the object for ExtraInfos.

If we suppose that this is an example value for ExtraInfos

ExtraInfos = {infos:{"key":"value"}}

Our mapper will create the ExtraInfos object with it.

Doing this ajax call (in this case for this mapper).

$.ajax({
    url:"test/23123",
    type:"post",
    contentType: "application/json; charset=utf-8",
    data:JSON.stringify(ExtraInfos)
})

Output on the console:

23123
{key=value}
Eduardo Quintana
  • 2,368
  • 1
  • 15
  • 20
  • Why the downvotes is the answer wrong? If it is it will be a pleasure to erase it. – Eduardo Quintana Mar 17 '14 at 21:08
  • Wasn't me. Anyway, it works great now, event with "PUT" method. I am pretty sure I tried it when Shay Elkayam answered me, but I probably messed it up. Thanks! –  Mar 18 '14 at 17:18
  • Yw i tried also with PATCH and it worked for me. If you want to still use PATCH. – Eduardo Quintana Mar 18 '14 at 17:21
  • I am now facing a problem. Let's say I have a controller with both "@RequestBody ExtraInfos extraInfos" and "@RequestParam("something") Long something". What query should I make with JQuery to specify that only a part of the data is json-encoded? –  Mar 24 '14 at 18:55
  • http://stackoverflow.com/questions/19468572/spring-mvc-why-not-able-to-use-requestbody-and-requestparam-together – Eduardo Quintana Mar 24 '14 at 20:25
  • 1
    It Seems that when we use the requestParam spring binds the full request body to that variable, that's why the requestParam fails because @requestBody consumes all the body you can add it to the POJO of extraInfos or send it as PathVariable – Eduardo Quintana Mar 24 '14 at 20:39