Home > Articles > Programming > Java

Java Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

Rendering JSON Responses with Spring 3 Web Services

Last updated Mar 14, 2003.

XML, as used with web services, has made integrating disparate systems, potentially written in different programming languages and running on different operating systems, an elegant reality. But one of the downfalls of XML is its verbosity: every node in an XML document requires at a minimum a single tag, and if that node contains values then it requires an end tag. For example:

<MyObject>
  <id>1</id>
  <name>Name of this object</name>
</MyObject>

This is pretty verbose to simply state that there is an object with the id of “1” and the name “Name of this object.”

Asynchronous JavaScript over XML (AJAX) provides two means for retrieving information from a web server:

  • XML
  • JSON

JSON, or JavaScript Object Notation, provides a leaner, albeit not as robust, representation of objects that JavaScript developers prefer to work with. For example, the aforementioned object would be represented as follows in JSON:

{"name":"Name of this object","id":"myid"}

And a JavaScript method could create a variable named MyObject as follows:

var myObject = eval( ‘{"name":"Name of this object","id":"myid"}’ );

And then its fields can be accessed through their property names:

var name = myObject.name;
var id = myObject.id;

When I say that it is not as robust, you can still represent all of the data, but you would be hard pressed to validate the contents against something like an XML Schema Definition (XSD file.) But this lack of robustness comes with a clean and easy to understand format.

If you are building a web service with Spring 3, you can easily configure it to return objects in a JSON format instead of an XML format. The key is in the message converters that we reviewed in the previous section.

When you create an AnnotationMethodHandlerAdapter bean in your Spring configuration file and you annotate your service methods with the @ResponseBody annotation then Spring will iterate over all configured message converters until it finds one that matches the object you are returning. It is important to configure Spring to iterate over the list sequentially if you are returning multiple media types because the converter that converts an object to JSON converts all objects (and you may not want it to convert certain object types.) The converter in question is the followings:

org.springframework.http.converter.json.MappingJacksonHttpMessageConverter

Simply put, if you return an object from your service method, it will convert it to JSON and return it to the caller. Listing 1 shows the contents of my Spring configuration file, named jsonexample-servlet.xml in this example.

Listing 1. jsonexample-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:oxm="http://www.springframework.org/schema/oxm"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-2.5.xsd
       http://www.springframework.org/schema/oxm
        http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

    <!-- Component scan to find all Spring components -->
    <context:component-scan base-package="com.geekcap.jsonexample" />

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="order" value="1" />
        <property name="messageConverters">
            <list>
                <!-- Default converters -->
                <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
                <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
            </list>
        </property>
    </bean>
</beans>

The instruction to tell the AnnotationMethodHandlerAdapter to review converters sequentially is the “order” set to “1.” The MappingJacksonHttpMessageConverter is configured last so that other converters have a chance to review the object first. The final step is to configure a controller with a method annotated with the @ResponseBody annotation that returns an object to convert to JSON. Listing 2 shows the JsonExampleController.

Listing 2. JsonExampleController.java

package com.geekcap.jsonexample;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Sample controller whose response it rendered to the browser as JSON
 * @author shaines
 */
@Controller
public class JSonExampleController
{
    @RequestMapping( value = "/object/{id}", method = RequestMethod.GET )
    @ResponseBody
    public MyObject getMyObject( @PathVariable String id )
    {
        return new MyObject( id, "Object " + id );
    }
}

This example is purposely simple: it defines a single method that responds to GET requests to URIs of the format /object/id and returns a new instance of a simple bean called MyObject (shown in listing 3.) Because the MyObject class is not handled by another converter it falls through the converter stack to the MappingJacksonHttpMessageConverter and is returned as JSON.

Listing 3. MyObject.java

package com.geekcap.jsonexample;

/**
 * Sample Object
 * @author shaines
 */
public class MyObject 
{
    private String id;
    private String name;

    public MyObject()
    {
    }

    public MyObject(String id, String name)
    {
        this.id = id;
        this.name = name;
    }

    public String getId()
    {
        return id;
    }

    public void setId(String id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }
}

MyObject is a simple bean, but with the MappingJacksonHttpMessageConvter you can pass more complex objects, with nested objects, and it will handle it seamlessly for you.

The final two pieces to this example are the web.xml file and the pom.xml file, shown in listings 4 and 5, respectively.

Listing 4. web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

    <display-name>JSON Example Web Services</display-name>

    <servlet>
        <servlet-name>jsonexample</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>jsonexample</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Listing 5. pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.geekcap.spring3</groupId>
    <artifactId>jsonexample</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>JSON Example RESTful Web Service</name>
    <url>http://maven.apache.org</url>
    <properties>
        <spring.version>3.0.4.RELEASE</spring.version>
        <java.version>1.6</java.version>
        <servlet-api.version>2.5</servlet-api.version>
    </properties>

    <dependencies>
        <!-- Spring Dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>${servlet-api.version}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-jaxrs</artifactId>
            <version>1.6.1</version>
        </dependency>


        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.6</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            
        </plugins>

        <finalName>jsonexample</finalName>
    </build>
</project>

These two files are standard to any Spring MVC application.

Build this project and copy jsonexample.war to your Tomcat’s webapps directory (or deploy it however your web container dictates) and you can access it through the following URL:

http://localhost:8080/jsonexample/object/myid

The only challenge that you may face is that JSON is returned with the content type application/json and the browser does not want to natively show it. You can either save the file and review it (your browser will prompt you) or you can use a tool like curl or the FireFox Poster plug-in. I personally find the Poster plug-in to be my tool of choice when testing RESTful web services during development because it allows you to execute GET, POST, PUT, and DELETE HTTP commands, including the ability to submit data contained in files.

JSON is a simple way of representing data that can be consumed by any platform, but most commonly web browsers via JavaScript. By using the correct converter you can easily render JSON responses using Spring 3.