20

I'm trying to send a JSON representation of a Map into my controller as a POST parameter.

@RequestMapping(value = "/search.do", method = RequestMethod.GET, consumes = { "application/json" })
public @ResponseBody Results search(@RequestParam("filters") HashMap<String,String> filters, HttpServletRequest request) {
       //do stuff
}

I found that @RequestParam would just throw a 500 error, so I tried using @ModelAttribute instead.

@RequestMapping(value = "/search.do", method = RequestMethod.GET, consumes = { "application/json" })
public @ResponseBody Results search(@ModelAttribute("filters") HashMap<String,String> filters, HttpServletRequest request) {
       //do stuff
}

This would correctly respond to requests, but I realized that the Map was empty. With later experimentation, I found that any object (not just HashMap) would be instantiated, but no fields would be filled in. I do have Jackson on my classpath, and my controllers will respond with JSON. However, it would appear that my current configuration is not allowing Spring to read JSON in via a GET/POST parameter.

How does one pass JSON representations of objects from a client-side AJAX request to a Spring controller as a request parameter and get a Java object out?

EDIT Adding my relevant Spring configuration

  <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="mediaTypes">
      <map>
        <entry key="html" value="text/html" />
        <entry key="json" value="application/json" />
      </map>
    </property>
    <property name="viewResolvers">
      <list>
        <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
          <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
          <property name="prefix" value="/WEB-INF/jsp/" />
          <property name="suffix" value=".jsp" />
        </bean>
      </list>
    </property>
    <property name="defaultViews">
      <list>
        <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
          <property name="prefixJson" value="true" />
        </bean>
      </list>
    </property>
  </bean>
  <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
      <list>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
      </list>
    </property>
  </bean>

On the suggestion of a commenter, I tried @RequestBody. This will work, so long as the JSON strings are quoted with double quotes.

@RequestMapping(value = "/search.do", method = RequestMethod.POST, consumes = { "application/json" })
public @ResponseBody Results<T> search(@RequestBody HashMap<String,String> filters, HttpServletRequest request) {
      //do stuff
}

This does solve my immediate issue, but I'm still curious as to how ou might pass in multiple JSON objects via an AJAX call.

monitorjbl
  • 4,280
  • 3
  • 36
  • 45

6 Answers6

7

This does solve my immediate issue, but I'm still curious as to how ou might pass in multiple JSON objects via an AJAX call.

The best way to do this is to have a wrapper object that contains the two (or multiple) objects you want to pass. You then construct your JSON object as an array of the two objects i.e.

[
  {
    "name" : "object1",
    "prop1" : "foo",
    "prop2" : "bar"
  },
  {
    "name" : "object2",
    "prop1" : "hello",
    "prop2" : "world"
  }
]

Then in your controller method you recieve the request body as a single object and extract the two contained objects. i.e:

@RequestMapping(value="/handlePost", method = RequestMethod.POST, 
                consumes = {      "application/json" })
public void doPost(@RequestBody WrapperObject wrapperObj) { 
     Object obj1 = wrapperObj.getObj1;
     Object obj2 = wrapperObj.getObj2;

     //Do what you want with the objects...


}

The wrapper object would look something like...

public class WrapperObject {    
private Object obj1;
private Object obj2;

public Object getObj1() {
    return obj1;
}
public void setObj1(Object obj1) {
    this.obj1 = obj1;
}
public Object getObj2() {
    return obj2;
}
public void setObj2(Object obj2) {
    this.obj2 = obj2;
}   

}
rogerdpack
  • 62,887
  • 36
  • 269
  • 388
LTJHeron
  • 91
  • 1
  • 6
  • Thanks for the RequestBody answer. I had a Map in my request, but it would always be empty, making the response empty too. Now RequestBody in front of the Map fixed it! – Aliya Jun 16 '16 at 17:53
2

You may use the Jackson library to convert from Json to Map.

@web-context.xml

<bean id="messageAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
        </list>
    </property>
</bean>

@maven dependencies:

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-core-lgpl</artifactId>
    <version>1.9.13</version>
</dependency>
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-lgpl</artifactId>
    <version>1.9.13</version>
</dependency>

@Controller

@RequestMapping(value = "/method", method = RequestMethod.DELETE)
public String method(
                @RequestBody Map<String, Object> obj){

@Request (e.g. jquery Ajax)

$.ajax({"type": "DELETE",
        "contentType": "application/json;",
        "url": "/method",
        "data": JSON.stringify({"key": "Ricardo"}),
        "dataType": "json";}
});

It's much easier with Python Frameworks or Play! ufff

dario nascimento
  • 587
  • 5
  • 11
1

I have passed the Map object to Java using below code :

Javascript Code :

var values = {
                    "object1" : JSON.stringify(object1),
                    "object2" : JSON.stringify(object2)
            };
 var response = $http.post(url,data);

Server Side Code :

@RequestMapping(value = "/deleteData",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public Result deleteData(@RequestBody HashMap<String, Object> dataHashMap) {
    Object1 object1=  (Object1) JsonConvertor.jsonToObject((String) dataHashMap.get("object1"), Object1.class);
        Object2 object2= (Object2) JsonConvertor.jsonToObject((String) dataHashMap.get("object2"), Object2.class);   
}

JsonConvertor Class :

public class JsonConvertor {
  public static <T> Object jsonToObject(String json, Class<T> clazz) {
    if (json == null)
      throw new IllegalArgumentException("null cannot be converted to Object");
    Gson gson = new GsonBuilder().disableHtmlEscaping().setDateFormat("dd-MMM-yyyy").create();
    return gson.fromJson(json, clazz);
  }
}
Sanchi Girotra
  • 1,232
  • 13
  • 13
0

You are not getting json correctly.

Do like that ....

/*
 * Mapping for Demographics And Profiling Question Filter
 */
@RequestMapping (value = "/generalFilter")
public void ageFilteration(@RequestParam Map <String,String> filterParams,HttpServletRequest request,HttpServletResponse response) throws IOException
{
    //  System.out.println("Geographies in Controller :"+ filterParams.get("geographies"));
    List<FeasibilityBean> feasibilityList = feasibilityDao.getGeneralFeasibilityList(filterParams,request);
    //  System.out.println(" General Filter List Size:"+feasibilityList.size());
    response.getWriter().print(new Gson().toJsonTree(feasibilityList,new TypeToken<List<FeasibilityBean>>(){}.getType()));
}

}

Js Code

var ages='',ageCond='',genders='',genderCond='';

    $.ajax({
        type: "POST",
        url : url,
        data : {ages:ages,ageCond:ageCond,genders:genders,genderCond:genderCond},
        beforeSend: function() { 
            $(thisVar).find('i').addClass('fa-spin');
        },
        success : function(feasibilityJson){ 

        },
        error : function(data) {
            alert(data + "error");
        },
        complete:function(){  
            $(thisVar).find('i').removeClass('fa-spin');
        }
    }); 

or you want to bind bean with json....

https://stackoverflow.com/a/21689084/5150781 https://stackoverflow.com/a/37958883/5150781

Community
  • 1
  • 1
Zigri2612
  • 2,279
  • 21
  • 33
0
    @RequestMapping(method = RequestMethod.POST)
    public HttpEntity<Resource<Customize>> customize(@RequestBody String customizeRequest) throws IOException {
       Map<String, String> map = mapper.readValue(customizeRequest, new TypeReference<Map<String,String>>(){});
       log.info("JSONX: " + customizeRequest);
       Long projectId_L = Long.parseLong(map.get("projectId"));
       [...]
R.A
  • 1,813
  • 21
  • 29
0

As @dario's answer, but for Jackson 2 version:

spring-web-context.xml

    <bean id="messageAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" >
            <property name="supportedMediaTypes">    
                <list>    
                    <value>application/json;charset=utf-8</value>    
               </list>    
            </property>  
            </bean>
        </list>
    </property>
</bean>

maven pom.xml:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.6</version>
    </dependency>

java controller

@RequestMapping(value = "/search.do", method = RequestMethod.GET, consumes = { "application/json" })
public @ResponseBody Results search(@RequestBody Map<String,Object> filters, HttpServletRequest request) {
Yu Jiaao
  • 4,444
  • 5
  • 44
  • 57