Ralf Wehner's Blog

Just another WordPress.com weblog

Create JSON response for AJAX request in spring 3.0

with 8 comments

Within a project pause i was playing with the google chart tools embedded within a spring 3 web project which impressed me well.
After playing with some charts i reached a point were it was usedful to fill the TableData Java script object with data provided by an AJAX request. What i needed was to implent a simple own Data Source.
Using the actual spring 3.0 version i found out two simple solutions to generate a JSON response for AJAX requests.

Use Jackson JSON processor in combination with spring’s StringHttpMessageConverter

I used the Jackson JSON processor to generate a JSON string that can be written via the spring’s StringHttpMessageConverter into the HttpServletResponse response object. To use this functionality we have to add the jackson-mapper-asl.jar into our project. For maven projects we have to add following stuff into the pom.xml dependencies:

		<!-- Jackson JSON Mapper -->
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-mapper-asl</artifactId>
			<version>1.5.3</version>
		</dependency>

The Jackson processor provides two ways to generate a JSON object stream:

Simple Data Binding

You can use Map objects to build the JSON object graph and generate the JSON stream. In a spring web controller this could look like this:

@Controller
public class RestController {

    @RequestMapping(value = "rest/playground/json-user", method = RequestMethod.GET)
    protected void getJsonDataExampleSimpleDataBinding(HttpServletResponse response) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        Map<String, String> nameStruct = new HashMap<String, String>();
        nameStruct.put("first", "Joe");
        nameStruct.put("last", "Sixpack");
        Map<String, Object> userData = new HashMap<String, Object>();
        userData.put("name", nameStruct);
        userData.put("gender", "MALE");
        userData.put("verified", Boolean.FALSE);
        userData.put("userImage", "Rm9vYmFyIQ==");
        String jsonString = mapper.writeValueAsString(userData);

        AbstractHttpMessageConverter<String> stringHttpMessageConverter = new StringHttpMessageConverter();
        MediaType jsonMimeType = MediaType.APPLICATION_JSON;
        if (stringHttpMessageConverter.canWrite(String.class, jsonMimeType)) {
            try {
                stringHttpMessageConverter.write(jsonString, jsonMimeType, new ServletServerHttpResponse(response));
            } catch (IOException m_Ioe) {
            } catch (HttpMessageNotWritableException p_Nwe) {
            }
        }
    }
    ...
}

Full Data Binding

In opposite to use Map objects often it makes sense to represent the JSON objects in simple bean classes (POJOs) on the server side and to marshall the POJO back to a JSON string stream. Here is an example:

    @RequestMapping(value = "rest/playground/json-user", method = RequestMethod.GET)
    protected void getJsonDataExampleFullDataBinding(HttpServletResponse response) throws JsonGenerationException, JsonMappingException, IOException {
        ObjectMapper mapper = new ObjectMapper();
        Object userData = new String("mock for the json object which have to be replaced with real one");
        String jsonString = mapper.writeValueAsString(userData);

        AbstractHttpMessageConverter<String> stringHttpMessageConverter = new StringHttpMessageConverter();
        MediaType jsonMimeType = MediaType.APPLICATION_JSON;
        if (stringHttpMessageConverter.canWrite(String.class, jsonMimeType)) {
            try {
                stringHttpMessageConverter.write(jsonString, jsonMimeType, new ServletServerHttpResponse(response));
            } catch (IOException m_Ioe) {
            } catch (HttpMessageNotWritableException p_Nwe) {
            }
        }
    }

Beside the simple data binding and full data binding there exists two other JSON processing variantes named as Streaming and Tree model. Please have a look at the documentation if you need more information on how to use Jackson.

Use the spring’s MappingJacksonHttpMessageConverter

Another solution to provide JSON response is to use the MappingJacksonHttpMessageConverter which is an implementation of HttpMessageConverter that can read and write JSON using the Jackson’s ObjectMapper. (Underneath the cover the MappingJacksonHttpMessageConverter uses Jackson as the name implied.) For propper use of this Implementation we have to add the depending artifact jason-mapper-asl.jar into our project as shown in the pom.xml example above.

Use the MappingJacksonHttpMessageConverter directly in controller’s request method

Use the MappingJacksonHttpMessageConverter class directly in the controler’s request method to build the HttpServeletResponse. This will be show in the example below:

    @RequestMapping(value = "rest/playground/json-example", method = RequestMethod.GET)
    protected void getJsonDataExample(HttpServletResponse response) {
        MappingJacksonHttpMessageConverter jsonConverter = new MappingJacksonHttpMessageConverter();
        MediaType jsonMimeType = MediaType.APPLICATION_JSON;
        Object jsonBean = new String("mock for the json object which have to be replaced with real one");
        if (jsonConverter.canWrite(jsonBean.getClass(), jsonMimeType)) {
            try {
                jsonConverter.write(jsonBean, jsonMimeType, new ServletServerHttpResponse(response));
            } catch (IOException m_Ioe) {
            } catch (HttpMessageNotWritableException p_Nwe) {
            }
        }
    }

In this code the JSON object is represented in a POJO on the server side and will be serialized and processed into ‘application/json’ response by the MappingJacksonHttpMessageConverter. When it becomes necessary to have more control about the serialization/deserialization process a custom-configured ObjectMapper can be set using the method MappingJacksonHttpMessageConverter.setObjectMapper().

Use the @ResponseBody Annotation

A very simple solution is to use the spring’s @RequestBody Annotation on the return value of a controller method. When using the @RequestBody the return value is indicated to be bound to a web response body which will be automatically done by the spring MVC. In this case, Spring MVC invokes a MappingJacksonHttpMessageConverter built on the Jackson JSON processor. This implementation is enabled automatically when you use the mvc:annotation-driven configuration element with Jackson present in your classpath.
So, an approch in code can look like this:

    @RequestMapping(value = "/rest/playground/google-barchart", method = RequestMethod.GET)
    public @ResponseBody
    GoogleJsonResponse getJsonDataForBarChart(HttpServletResponse response, HttpServletRequest request) {
        response.setStatus(HttpServletResponse.SC_OK);
        GoogleJsonResponse ret = new GoogleJsonResponse();
        ret.addColl("string", "Year");
        ret.addColl("number", "Austria");
        ret.addColl("number", "Bulgaria");
        ret.addColl("number", "Denmark");
        ret.addColl("number", "Greece");
        ret.addRow(new GoogleJsonResponse.Cell("2003"), new GoogleJsonResponse.Cell(1336060), new GoogleJsonResponse.Cell(400361), new GoogleJsonResponse.Cell(1001582), new GoogleJsonResponse.Cell(
                997974));
        ret.addRow(new GoogleJsonResponse.Cell("2004"), new GoogleJsonResponse.Cell(1538156), new GoogleJsonResponse.Cell(366849), new GoogleJsonResponse.Cell(1119450), new GoogleJsonResponse.Cell(
                941795));
        ret.addRow(new GoogleJsonResponse.Cell("2005"), new GoogleJsonResponse.Cell(1576579), new GoogleJsonResponse.Cell(440514), new GoogleJsonResponse.Cell(993360), new GoogleJsonResponse.Cell(
                930593));
        ret.addRow(new GoogleJsonResponse.Cell("2006"), new GoogleJsonResponse.Cell(1600652), new GoogleJsonResponse.Cell(434552), new GoogleJsonResponse.Cell(1004163), new GoogleJsonResponse.Cell(
                897127));
        ret.addRow(new GoogleJsonResponse.Cell("2007"), new GoogleJsonResponse.Cell(1968113), new GoogleJsonResponse.Cell(393032), new GoogleJsonResponse.Cell(979198), new GoogleJsonResponse.Cell(
                1080887));
        ret.addRow(new GoogleJsonResponse.Cell("2008"), new GoogleJsonResponse.Cell(1901067), new GoogleJsonResponse.Cell(517206), new GoogleJsonResponse.Cell(916965), new GoogleJsonResponse.Cell(
                1056036));
        return ret;
    }

(I’ve modified a google tool chart example and created the GoogleJsonResponse class which is a simple Java bean with some attributes and setter and getter. This class represents the JSON data that will be wrapped into a google TableData objects in the java script of the jsp.)

public class GoogleJsonResponse {

    class Col {
        String id;
        final String _type;
        final String _label;

        public Col(String type, String label) {
            _type = type;
            _label = label;
        }

        public String getId() {
            return id;
        }

        public String getType() {
            return _type;
        }

        public String getLabel() {
            return _label;
        }
    };

    public static class Cell {
        private final Object _v;

        public Cell(Object v) {
            _v = v;
        }

        public Object getV() {
            return _v;
        }
    }

    class Row {
        List<Cell> _c = new ArrayList<Cell>();

        public void addCells(Cell... cells) {
            _c.addAll(Arrays.asList(cells));
        }

        public List<Cell> getC() {
            return _c;
        }
    };

    /* GoogleResonResponse attributes starts here */
    private List<Col> _cols = new ArrayList<Col>();
    
    private List<Row> _rows = new ArrayList<Row>();

    public void addColl(String type, String label) {
        Col col = new Col(type, label);
        _cols.add(col);
    }

    public void addRow(Cell... cells) {
        Row row = new Row();
        row.addCells(cells);
        _rows.add(row);
    }

    public List<Col> getCols() {
        return _cols;
    }

    public List<Row> getRows() {
        return _rows;
    }
}

Conclusion

The simplest and most straightforward solution to generate an ‘application/json’ response seemed to me to use the @ResponseBody annotation as shown above. If you need more control about the serialization of the JSON bean objects on the server side, e.g. if you need a special representation of java.util.Date attributes, you have to use Annotations as described in Jackson Core documenation.

About these ads

Written by rwehner

June 9, 2010 at 11:35 am

Posted in java, spring 3.0

8 Responses

Subscribe to comments with RSS.

  1. […] also Ralf’s post about Json and Spring MVC. AKPC_IDS += "595,"; Tags: ajax, jquery, mvc, spring […]

  2. Its it possible to post the source?

    thx

    ooDeveloper

    February 5, 2011 at 7:55 am

  3. is it possible to share GoogleJsonResponse.java
    with related sources files

    Shankar

    December 2, 2011 at 8:33 am

    • I’ve added the source code of GoogleJsonResponse class to the posting just above the ‘Conclusion’ section.

      rwehner

      December 2, 2011 at 8:57 pm

  4. Create JSON response for AJAX request in spring 3.0 « Ralf Wehner’s Blog…

    Thank you for submitting this cool story – Trackback from JavaPins…

    JavaPins

    January 14, 2012 at 2:09 pm

  5. […] Create JSON response from Spring MVC 3 :  ”Spring MVC invokes a MappingJacksonHttpMessageConverter built on the Jackson JSON processor. This implementation is enabled automatically when you use the mvc:annotation-driven configuration element with Jackson present in your classpath” […]

  6. If you are going for finest contents like myself,
    only go to see this website every day because it presents quality contents, thanks


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: