Chapter 9. Spring REST

In this chapter, you will learn how Spring addresses Representational State Transfer, usually referred to by its acronym REST. REST has had an important impact on web applications since the term was coined by Roy Fielding (http://en.wikipedia.org/wiki/Roy_Fielding) in the year 2000.

Based on the foundations of the web's protocol Hypertext Transfer Protocol (HTTP), the architecture set forth by REST has become increasingly popular in the implementation of web services.

Web services in and of themselves have become the cornerstone for much machine-to-machine communication taking place on the Web. It's the fragmented technology choices (e.g., Java, Python, Ruby, .NET) made by many organizations that have necessitated a solution capable of bridging the gaps between these disparate environments. How is information in an application backed by Java accessed by one written in Python? How can a Java application obtain information from an application written in .NET? Web services fill this void.

There are various approaches to implementing web services, but RESTful web services have become the most common choice in web applications. They are used by some of the largest Internet portals (e.g., Google and Yahoo) to provide access to their information, used to back access to Ajax calls made by browsers, in addition to providing the foundations for the distribution of information like news feeds (e.g., RSS).

In this chapter, you will learn how Spring applications can use REST, so you can both access and provide information using this popular approach.

Publishing a REST Service with Spring

Problem

You want to publish a REST service with Spring.

Solution

There are two possibilities when designing REST services in Spring. One involves publishing an application's data as a REST service, the other one involves accessing data from third-party REST services to be used in an application. This recipe describes how to publish an application's data as a REST service. Recipe 9-2 describes how to access data from third-party REST services.

Publishing an application's data as a REST service revolves around the use of the Spring MVC annotations @RequestMapping and @PathVariable. By using these annotations to decorate a Spring MVC handler method, a Spring application is capable of publishing an application's data as a REST service.

In addition, Spring supports a series of mechanisms to generate a REST service's payload. This recipe will explore the simplest mechanism, which involves the use of Spring's MarshallingView class. As the recipes in this chapter progress, you will learn about more advanced mechanisms supported by Spring to generate REST service payloads.

How It Works

Publishing a web application's data as a REST service, or as it's more technically known in web services parlance "creating an end point," is strongly tied to Spring MVC, which you explored in Chapter 8.

Since Spring MVC relies on the annotation @RequestMapping to decorate handler methods and define access points (i.e., URLs), it's the preferred way in which to define a REST service's end point. The following listing illustrates a Spring MVC controller class with a handler method that defines a REST service end point:

package com.apress.springrecipes.court.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.apress.springrecipes.court.domain.Member;

@Controller
public class RestMemberController {

    @RequestMapping("/members")
     public String getRestMembers(Model model) {
        // Return view membertemplate. Via resolver the view
        // will be mapped to a JAXB Marshler bound to the Member class
        Member member = new Member();
        member.setName("John Doe");
        member.setPhone("1-800-800-800");
        member.setEmail("[email protected]");
        model.addAttribute("member", member);
        return "membertemplate";
    }
}

By using @RequestMapping("/members") to decorate a controller's handler method, a REST service end point is made accessible at http://[host_name]/[app-name]/members. Before elaborating on the body of this last handler method, it's worth mentioning other variations you can use for declaring REST service end points.

It's also common for REST service requests to have parameters. This is done to limit or filter a service's payload. For example, a request in the form http://[host_name]/[app-name]/member/353/ can be used to retrieve information exclusively on member 353. Another variation can be a request like http://[host_name]/[app-name]/reservations/07-07-2010/ to retrieve reservations made on the date 07-07-2010.

In order to use parameters for constructing a REST service in Spring, you use the @PathVariable annotation. The @PathVariable annotation is added as an input parameter to the handler method, per Spring's MVC conventions, in order for it to be used inside the handler method body. The following snippet illustrates a handler method for a REST service using the @PathVariable annotation.

Import org.springframework.web.bind.annotation.PathVariable;

@RequestMapping("/member/{memberid}")
    public void getMember(@PathVariable("memberid") long memberID) {
}

Notice the @RequestMapping value contains {memberid}. Values surrounded by { } are used to indicate URL parameters are variables. Further note the handler method is defined with the input parameter @PathVariable("memberid") long memberID. This last declaration associates whatever memberid value forms part of the URL and assigns it to a variable named memberID that can be accessible inside the handler method.

Therefore, REST end points in the form /member/353/ and /member/777/ will be processed by this last handler method, with the memberID variable being assigned values of 353 and 777, respectively. Inside the handler method, the appropriate queries can be made for members 353 and 777—via the memberID variable—and returned as the REST service's payload. Even though void is the return value for the method, the REST service's payload is not void. Recall that per Spring MVC conventions, a method returning void is still mapped to a template that returns a payload.

In addition to supporting the { } notation, it's also possible to use a wildcard * notation for defining REST end points. This is often the case when a design team has opted to use expressive URLs (often called pretty URLs) or opts to use search engine optimization (SEO) techniques to make a REST URL search engine friendly. The following snippet illustrates a declaration for a REST service using the wildcard notation.

@RequestMapping("/member/*/{memberid}")
    public void getMember(@PathVariable("memberid") long memberID) {
}

In this case, the addition of a wildcard doesn't have any influence over the logic performed by the REST service. But it will match end point requests in the form /member/John+Smith/353/ and /member/Mary+Jones/353/, which can have an important impact on end user readability or SEO.

It's also worth mentioning that data binding can be used in the definition of handler methods for REST end points. The following snippet illustrates a declaration for a REST service using data binding:

@InitBinder
public void initBinder(WebDataBinder binder) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
@RequestMapping("/reservations/{date}")
    public void getReservation(@PathVariable("date") Date resDate) {
}

In this case, a request in the form http://[host_name]/[app-name]/reservations/07-07-2010/ is matched by this last handler method, with the value 07-07-2010 passed into the handler method—as the variable resDate– where it can be used to filter the REST web service payload.

Turning your attention back to the handler method decorated with the @RequestMapping("/members") annotation and its body, note that the handler method creates a Member object that is then assigned to the method's Model object. By associating data with a handler method's Model object, it becomes accessible to the view associated with the handler method—per Spring MVC conventions.

In this case, this single Member object is hard-coded to be the REST service's payload. More sophisticated REST service's can include querying a RDBMS or accessing class methods.

All handler methods in Spring MVC end up being delegated to logical views, which are used to render content passed in by handler methods, and that content is finally dispatched to requesting users.

In the case of RESTful services, the payload expected by requesting users is generally that of XML. Therefore, Spring MVC handler methods designed to attend REST end points are delegated to view technologies that generate XML-type payloads.

In the case of the handler method decorated with @RequestMapping("/members"), you can observe that control is relinquished to a logical view named membertemplate. Logical views, per Spring MVC conventions, are defined inside a Spring application's *-servlet.xml files. The following listing illustrates the declaration used to define the logical view named membertemplate:

<bean id="membertemplate" class="org.springframework.web.servlet.view.xml.MarshallingView">
       <constructor-arg>
          <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
              <property name="classesToBeBound">
                <list>
                  <value>com.apress.springrecipes.court.domain.Member</value>
                </list>
              </property>
          </bean>
       </constructor-arg>
  </bean>

The membertemplate view is defined as a MarshallingView type, which is a general-purpose class that allows a response to be rendered using a marshaller. Marshalling is the process of transforming an in-memory representation of an object into a data format. Therefore, for this particular case, a marshaller is charged with transforming a Member object into an XML data format.

The marshaller used by MarshallingView belongs to one of a series of XML marshallers provided by Spring—Jaxb2Marshaller. Other marshallers provided by Spring include CastorMarshaller, JibxMarshaller, XmlBeansMarshaller, and XStreamMarshaller.

Marshallers themselves also require configuration. We opted to use the Jaxb2Marshaller marshaller due to its simplicity and Java Architecture for XML Binding (JAXB) foundations. However, if you're more comfortable using the Castor XML framework, you might find it easier to use the CastorMarshaller, and you would likely find it easier to use the XStreamMarshaller if your more at ease using XStream, with the same case applying for the rest of the available marshallers.

The Jaxb2Marshaller marshaller requires to be configured with either a property named classesToBeBound or contextPath. In the case of classesToBeBound, the classes assigned to this property, indicate the class (i.e., object) structure that is to be transformed into XML. The following listing illustrates the Member class assigned to the Jaxb2Marshaller:

package com.apress.springrecipes.court.domain;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Member {
    private String name;
    private String phone;
    private String email;

    public String getEmail() {
        return email;
    }

    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }

    public void setEmail(String email) {
        this.email = email;
    }

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

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

Note the Member class is a POJO decorated with the @XmlRootElement annotation. This annotation allows the Jaxb2Marshaller marshaller to detect a class's (i.e., object's) fields and transform them into XML data (e.g., name=John into <name>john</name>, email= into <email>[email protected]</email>).

To recap what's been described, this means that when a request is made to a URL in the form http://[host_name]//app-name]/members.xml, the corresponding handler is charged with creating a Memeber object, which is then passed to a logical view named membertemplate. Based on this last view's definition, a marshaller is used to convert a Memeber object into an XML payload that is returned to the REST service's requesting party. The XML payload returned by the REST service is illustrated in the following listing:

<?xml version="1.0" encoding="UTF-8" standalone="yes">
<member>
<email>[email protected]</email>
<name>John Doe</name>
<phone>1-800-800-800</phone>
</member>

This last XML payload represents a very simple approach to generating a REST service's response. As the recipes in this chapter progress, you will learn more sophisticated approaches, such as the ability to create widely used REST service payloads like RSS, Atom, and JSON.

If you look closely at the REST service end point or URL described in the previous paragraph, you'll note that it has an .xml extension. If you try another extension—or even omit the extension—this particular REST service may not be triggered. This last behavior is directly tied to Spring MVC and how it handles view resolution. It has nothing do with REST services per se.

By default, since the view associated with this particular REST service handler method returns XML, it's triggered by an .xml extension. This allows the same handler method to support multiple views. For example, it can be convenient for a request like http://[host_name]/[app-name]/members.pdf to return the same information in a PDF document, as well as a request like http://[host_name]/[app-name]/members.html to return content in HTML or a request like http://[host_name]/[app-name]/members.xml to return XML for a REST request.

So what happens to a request with no URL extension, like http://[host_name]/[app-name]/members? This also depends heavily on Spring MVC view resolution. For this purpose, Spring MVC supports a process called content negotiation, by which a view is determined based on a request's extension or HTTP headers.

Since REST service requests typically have HTTP headers in the form Accept: application/xml, Spring MVC configured to use content negotiation can determine to serve XML (REST) payloads to such requests even if requests are made extensionless. This also allows extensionless requests to be made in formats like HTML, PDF and XLS, all simply based on HTTP headers. Recipe 8-7 in Chapter 8 discusses content negotiation.

Accessing a REST Service with Spring

Problem

You want to access a REST service from a third party (e.g., Google, Yahoo, another business partner) and use its payload inside a Spring application.

Solution

Accessing a third-party REST service inside a Spring application revolves around the use of the Spring RestTemplate class.

The RestTemplate class is designed on the same principles as the many other Spring *Template classes (e.g., JdbcTemplate, JmsTemplate ), providing a simplified approach with default behaviors for performing lengthy tasks.

This means the processes of invoking a REST service and using its returning payload are streamlined in Spring applications.

How It Works

Before describing the particularities of the RestTemplate class, it's worth exploring the life cycle of a REST service, so you're aware of the actual work the RestTemplate class performs. Exploring the life cycle of a REST service can best be done from a browser, so open your favorite browser on your workstation to get started.

The first thing that's needed is a REST service end point. The following URL represents a REST service end point provided by Yahoo that returns sports news results:

http://search.yahooapis.com/NewsSearchService/V1/newsSearch?appid=
How It Works
YahooDemo&query=sports&results=2&language=en

The structure of the REST service end point comprises an address, which starts with http:// and ends with ?, as well as a series of parameters that start with ? and are delimited by &, each represented by a key and value divided by =.

If you load this last REST service end point on your browser, the browser performs a GET request, which is one of the most popular HTTP requests supported by REST services. Upon loading the REST service, the browser displays a responding payload like the following:

<ResultSet xsi:schemaLocation="urn:yahoo:yn 
How It Works
http://api.search.yahoo.com/NewsSearchService/V1/
How It Works
NewsSearchResponse.xsd" totalResultsAvailable="55494"
How It Works
totalResultsReturned="2" firstResultPosition="1"> <Result> <Title>Toyota Recalls Will Slam Sports</Title> <Summary> All the big sports are likely to see their sponsorship revenue
How It Works
go down as a result of the Toytota de </Summary> <Url> http://blogs.forbes.com/sportsmoney/2010/02/toyota-recalls-will-slam-sports/ </Url> ...Remaining code omitted for brevity... </Result> </ResultSet>

This last payload represents a well-formed XML fragment, which is in line with most REST service's responses. The actual meaning of the payload is highly dependent on a REST service. In this case, the XML tags (e.g., <Result>, <Title> ) are definitions set forth by Yahoo, while the character data enclosed in each XML tag represents information related to a REST service's request.

It's the task of a REST service consumer (i.e., you) to know the payload structure—sometimes referred to as vocabulary—of a REST service to appropriately process its information. Though this last REST service relies on what can be considered a custom vocabulary, a series of REST services often rely on standardized vocabularies (e.g., RSS), which make the processing of REST service payloads uniform. In addition, it's also worth noting that some REST services provide Web Application Description Language (WADL) contracts to facilitate the discovery and consumption of payloads.

Now that your familiar with a REST service's life cycle using your browser, we can take a look at how to use the Spring RestTemplate class in order to incorporate a REST service's payload into a Spring application.

Given that the RestTemplate class is designed to call REST services, it should come as no surprise that its main methods are closely tied to REST's underpinnings, which are the HTTP protocol's methods: HEAD, GET, POST, PUT, DELETE, and OPTIONS. Table 9-1 contains the main methods supported by the RestTemplate class.

Table 9.1. RestTemplate class methods based on HTTP protocol's request methods

Method

Description

headForHeaders(String, Object...)

Performs an HTTP HEAD operation

getForObject(String, Class, Object...)

Performs an HTTP GET operation

postForLocation(String, Object, Object...)

Performs an HTTP POST operation using an object

postForObject(String, Object, Class, Object...)

Performs an HTTP POST operation using a class.

put(String, Object, Object...)

Performs an HTTP PUT operation

delete(String, Object...)

Performs an HTTP DELETE operation

optionsForAllow(String, Object...)

Performs an HTTP OPTIONS operation

execute(String, HttpMethod, RequestCallback, ResponseExtractor, Object...)

Can perform any HTTP operation with the exception of CONNECT

As you can observe in Table 9-1, the RestTemplate class methods are prefixed with a series of HTTP protocol methods that include HEAD, GET, POST, PUT, DELETE, and OPTIONS. In addition, the execute method serves as a general-purpose method that can perform any HTTP operation, including the more esoteric HTTP protocol TRACE method, albeit not the CONNECT method, the last of which is not supported by the underlying HttpMethod enum used by the execute method.

Note

By far the most common HTTP method used in REST services is GET, since it represents a safe operation to obtain information (i.e., it doesn't modify any data). On the other hand, HTTP methods such as POST and DELETE are designed to modify a provider's information, which makes them less likely to be supported by a REST service provider. For cases in which data modification needs to take place, many providers opt for the SOAP protocol, which is an alternative mechanism to using REST services.

Now that you're aware of the RestTemplate class methods, we can move onto invoking the same REST service you did with your browser previously, except this time using Java code from the Spring framework. The following listing illustrates a Spring MVC controller class with a handler method that accesses the REST service and returns its contents to a standard HTML page:

package com.apress.springrecipes.court.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.client.RestTemplate;


@Controller
public class RestNewsController {

    @Autowired
    protected RestTemplate restTemplate;

    @RequestMapping("/sportsnews")
    public String getYahooNews(Model model) {
        // Return view newstemplate. Via resolver the view
        // will be mapped to /WEB-INF/jsp/newstemplate.jsp
        String result = restTemplate.getForObject("
RestTemplate class methods based on HTTP protocol's request methods
http://search.yahooapis.com/
RestTemplate class methods based on HTTP protocol's request methods
NewsSearchService/V1/newsSearch?appid={appid}&
RestTemplate class methods based on HTTP protocol's request methods
query={query}&results={results}&language={language}",
RestTemplate class methods based on HTTP protocol's request methods
String.class, "YahooDemo","sports","2","en"); model.addAttribute("newsfeed", result); return "newstemplate"; } }

Warning

Some REST service providers restrict access to their data feeds depending on the requesting party. Access is generally denied by relying on data present in a request (e.g., HTTP headers or IP address). So depending on the circumstances, a provider can return an access denied response even when a data feed appears to be working in another medium (e.g., you might be able to access a REST service in a browser but get an accessed denied response when attempting to access the same feed from a Spring application). This depends on the terms of use set forth by a REST provider.

The first line marked in bold declares the import statement needed to access the RestTemplate class within a class's body. The second statement in bold represents this same class decorated with the @Autowired annotation, which allows the Spring framework to wire the class. The following listing illustrates the related configuration code needed inside a web application's Spring configuration file to wire the RestTemplate class:

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
</bean>

If you're unfamiliar with the process of Spring wiring a class, we recommend you read Chapters 1 through 3, which introduce this fundamental process of the framework. If you're unfamiliar with the @Autowired annotation, we recommend you read Chapter 8, which introduces you to Spring MVC, a part of the framework that relies on this annotation.

Next, you'll find a handler method decorated with the @RequestMapping("/sportsnews") annotation. This last method represents a basic Spring MVC declaration, indicating the method is triggered when a request is made on a URL in the form http://[host_name]/[app-name]/sportsnews.

In the first line of the handler method, you can find a call made to the getForObject method that belongs to the RestTemplate class, which as described in Table 9-1 is used to perform an HTTP GET operation—just like the one performed by a browser to obtain a REST service's payload. There are two important aspects related to this last method, its response and its parameters.

The response of calling the getForObject method is assigned to a String object. This means the same output you saw on your browser for this REST service (i.e., the XML structure) is assigned to a String. Even if you've never processed XML in Java, you're likely aware that extracting and manipulating data as a Java String is not an easy task. In other words, there are classes better suited for processing XML data, and with it a REST service's payload, than a String object. For the moment just keep this in mind; other recipes in the chapter illustrate how to better extract and manipulate the data obtained from a REST service.

The parameters passed to the getForObject method consist of the actual REST service end point. The first parameter corresponds to the URL (i.e., end point) declaration with a series of placeholders using { and }. Notice the URL is identical to the one used when you relied on a browser to call it, except now it doesn't have any hard-coded values and instead uses placeholders where these values were once declared.

In this case, each of the placeholder declarations (e.g., {appid} and {query}) are substituted by one of the remaining parameters passed to the getForObject method. With the first parameter representing the return type class—String.class—and the remaining parameters corresponding to the placeholder values mapped in the same order in which they're declared (e.g., the YahooDemo value assigned to {appid} or the sports value assigned to {query}).

Even though this process allows a REST service to be parameterized on a case-by-case basis (i.e., for each web application visitor), passing a series of String objects and keeping track of their order can be an error-prone process. The various RestTemplate class methods described in Table 9-1 also support a more compact parameter passing strategy using the Java collections framework. This process is illustrated in the following snippet:

Map<String, String> params = new HashMap<String, String>();
params.put("appid","YahooDemo");
params.put("query","sports");
params.put("results", "2");
params.put("language", "en");

String result = restTemplate.getForObject("http://search.yahooapis.com/
RestTemplate class methods based on HTTP protocol's request methods
NewsSearchService/V1/newsSearch?appid={appid}
RestTemplate class methods based on HTTP protocol's request methods
&query={query}&results={results}&language={language}",
RestTemplate class methods based on HTTP protocol's request methods
String.class, params);

This last snippet makes use of the HashMap class—part of the Java collections framework—creating an instance with the corresponding REST service parameters, which is later passed to the getForObject method of the RestTemplate class. The results obtained by passing either a series of String parameters or a single Map parameter to the various RestTemplate methods is identical.

Turning our attention back to the remaining part of the handler method, once the REST service's XML payload is assigned to a String object, it's then associated with the handler's Model object through the newsfeed keyword, so it can be accessed and displayed from the view linked to the handler method. In this case, the handler method relinquishes control to a logical view named newstemplate.

Since configuring logical views is a concept related Spring MVC, we advise you to read Chapter 8 if you're unfamiliar with the topic. The newstemplate logical view would finally be mapped to a JSP capable of displaying the contents of the REST service's XML payload, that in accordance with the Spring MVC mapping would be accessible at http://[host_name]/[app-name]/sportsnews.html. The following listing illustrates such a JSP:

<html>
  <head>
    <title>Sports news feed by Yahoo</title>
  </head>
<body>
   <h2>Sports news feed by Yahoo</h2>
     <table>
     <tr>
       <td>${newsfeed}</td>
     </tr>
     </table>
</body>
</html>

The REST service's XML payload is substituted into the ${newsfeed} placeholder, in accordance with the key value defined inside the handler method.

As we already mentioned, future recipes will address more elaborate ways to extract and manipulate data belonging to a REST service's XML payload than this approach, which simply dumps the entire feed's contents verbatim on an HTML page.

Publishing RSS and Atom feeds

Problem

You want to publish an RSS or Atom feed in a Spring application.

Solution

RSS and Atom feeds have become a popular means by which to publish information. Access to these types of feeds is provided by means of a REST service, which means building a REST service is a prerequisite to publishing RSS and Atom feeds.

In addition to relying on Spring's REST support, it's also convenient to rely on a third-party library especially designed to deal with the particularities of RSS and Atom feeds. This makes it easier for a REST service to publish this type of XML payload. For this last purpose, we will use Project Rome, an open source library available at https://rome.dev.java.net/.

Note

Project Rome depends on the JDOM library that can be downloaded at http://www.jdom.org/. If you are using Maven, you can add the following dependency to your pom.xml file:

<dependency>
  <groupId>org.jdom</groupId>
  <artifactId>jdom</artifactId>
  <version>1.1</version>
 </dependency>

Tip

Even though RSS and Atom feeds are often categorized as news feeds, they have surpassed this initial usage scenario of providing just news. Nowadays, RSS and Atom feeds are used to publish information related to blogs, weather, travel, and many other things in a cross-platform manner (i.e., using XML). Hence, if you require publishing information of any sort that's to be accessible in a cross-platform manner, doing so as RSS or Atom feeds can be an excellent choice given their wide adoption (e.g., many applications support them and many developers know their structure).

How It Works

The first thing you need to do is determine the information you wish to publish as an RSS or Atom news feed. This information can be located in an RDBMS or text file, accessed through JDBC or ORM, inclusively be part of a Spring bean or some other type of construct. Describing how to obtain this information would go beyond the scope of this recipe, so we will assume you'll use whatever means you deem appropriate to access it.

Once you've pinpointed the information you wish to publish, it's necessary to structure it as either an RSS or Atom feed, which is where Project Rome comes into the picture.

In case you're unfamiliar with an Atom feed's structure, the following snippet illustrates a fragment of this format:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>Example Feed</title>
  <link href="http://example.org/"/>
  <updated>2010-08-31T18:30:02Z</updated>
  <author>
    <name>John Doe</name>
  </author>
  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
<entry>
    <title>Atom-Powered Robots Run Amok</title>
    <link href="http://example.org/2010/08/31/atom03"/>
    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
    <updated>2010-08-31T18:30:02Z</updated>
    <summary>Some text.</summary>
  </entry>

</feed>

The following snippet illustrates a fragment of an RSS feed's structure:

<?xml version="1.0" encoding="UTF-8" ?>

<rss version="2.0">
<channel>
<title>RSS Example</title>
<description>This is an example of an RSS feed</description>
<link>http://www.example.org/link.htm</link>
<lastBuildDate>Mon, 28 Aug 2006 11:12:55 −0400 </lastBuildDate>
<pubDate>Tue, 31 Aug 2010 09:00:00 −0400</pubDate>

<item>
<title>Item Example</title>
<description>This is an example of an Item</description>
<link>http://www.example.org/link.htm</link>
<guid isPermaLink="false"> 1102345</guid>
<pubDate>Tue, 31 Aug 2010 09:00:00 −0400</pubDate>
</item>


</channel>


</rss>

As you can observe from these last two snippets, RSS and Atom feeds are just XML payloads that rely on a series of elements to publish information. Though going into the finer details of either an RSS or Atom feed structure would require a book in itself, both formats possess a series of common characteristics; chief among them are these:

  • They have a metadata section to describe the contents of a feed. (e.g., the <author> and <title> elements for the Atom format and the <description> and <pubDate> elements for the RSS format)

  • They have recurring elements to describe information (e.g., the <entry> element for the Atom feed format and the <item> element for the RSS feed format). In addition, each recurring element also has its own set of elements with which to further describe information.

  • They have multiple versions. RSS versions include 0.90, 0.91 Netscape, 0.91 Userland, 0.92, 0.93, 0.94, 1.0, and 2.0. Atom versions include 0.3 and 1.0.

Project Rome allows you to create a feed's metadata section, recurring elements, as well as any of the previously mentioned versions, from information available in Java code (e.g., Strings, Maps, or other such constructs).

Now that you're aware of the structure of an RSS and Atom feed, as well as the role Project Rome plays in this recipe, let's take a look at a Spring MVC controller charged with presenting a feed to an end user.

package com.apress.springrecipes.court.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.apress.springrecipes.court.feeds.TournamentContent;

import com.apress.springrecipes.court.domain.Member;
import java.util.List;
import java.util.Date;
import java.util.ArrayList;

@Controller
public class FeedController {

    @RequestMapping("/atomfeed")
    public String getAtomFeed(Model model) {
        List<TournamentContent> tournamentList = new ArrayList<TournamentContent>();
        tournamentList.add(TournamentContent.generateContent("ATP", 
How It Works
new Date(),"Australian Open","www.australianopen.com")); tournamentList.add(TournamentContent.generateContent("ATP",
How It Works
new Date(),"Roland Garros","www.rolandgarros.com")); tournamentList.add(TournamentContent.generateContent("ATP",
How It Works
new Date(),"Wimbledon","www.wimbledon.org")); tournamentList.add(TournamentContent.generateContent("ATP",
How It Works
new Date(),"US Open","www.usopen.org")); model.addAttribute("feedContent",tournamentList); return "atomfeedtemplate"; } @RequestMapping("/rssfeed") public String getRSSFeed(Model model) { List<TournamentContent> tournamentList = new ArrayList<TournamentContent>(); tournamentList.add(TournamentContent.generateContent("FIFA",
How It Works
new Date(),"World Cup","www.fifa.com/worldcup/")); tournamentList.add(TournamentContent.generateContent("FIFA",
How It Works
new Date(),"U-20 World Cup","www.fifa.com/u20worldcup/")); tournamentList.add(TournamentContent.generateContent("FIFA",
How It Works
new Date(),"U-17 World Cup","www.fifa.com/u17worldcup/")); tournamentList.add(TournamentContent.generateContent("FIFA",
How It Works
new Date(),"Confederations Cup","www.fifa.com/confederationscup/"));
model.addAttribute("feedContent",tournamentList);
        return "rssfeedtemplate";

    }
}

This last Spring MVC controller has two handler methods. One called getAtomFeed(), which is mapped to a URL in the form http://[host_name]/[app-name]/atomfeed, and another called getRSSFeed(), which is mapped to a URL in the form http://[host_name]/[app-name]/rssfeed.

Each handler method defines a List of TournamentContent objects, where the backing class for a TournamentContent object is a POJO. This List is then assigned to the handler method's Model object in order for it to become accessible to the returning view. The returning logical views for each handler methods are atomfeedtemplate and rssfeedtemplate, respectively. These logical views are defined in the following manner inside a Spring XML configuration file:

<bean id="atomfeedtemplate"
How It Works
class="com.apress.springrecipes.court.feeds.AtomFeedView"/> <bean id="rssfeedtemplate"
How It Works
class="com.apress.springrecipes.court.feeds.RSSFeedView"/>

As you can observe, each logical view is mapped to a class. Each of these classes is charged with implementing the necessary logic to build either an Atom or RSS view. If you recall from Chapter 8, you used an identical approach (i.e., using classes) for implementing PDF and Excel views.

In the case of Atom and RSS views, Spring comes equipped with two classes specially equipped and built on the foundations of Project Rome. These classes are AbstractAtomFeedView and AbstractRssFeedView. Such classes provide the foundations to build an Atom or RSS feed, without dealing in the finer details of each of these formats.

The following listing illustrates the AtomFeedView class which implements the AbstractAtomFeedView class and is used to back the atomfeedtemplate logical view:

package com.apress.springrecipes.court.feeds;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.syndication.feed.atom.Feed;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.atom.Content;

import org.springframework.web.servlet.
How It Works
view.feed.AbstractAtomFeedView; import java.util.Date; import java.util.List; import java.util.ArrayList; import java.util.Map; public class AtomFeedView extends AbstractAtomFeedView { protected void buildFeedMetadata(Map model,
How It Works
Feed feed, HttpServletRequest request) {
feed.setId("tag:tennis.org");
        feed.setTitle("Grand Slam Tournaments");
        List<TournamentContent> tournamentList = (List<TournamentContent>)model.
How It Works
get("feedContent"); for (TournamentContent tournament : tournamentList) { Date date = tournament.getPublicationDate(); if (feed.getUpdated() == null || date.compareTo(feed.getUpdated()) > 0) { feed.setUpdated(date); } } } protected List buildFeedEntries(Map model,
How It Works
HttpServletRequest request, HttpServletResponse response)
How It Works
throws Exception { List<TournamentContent> tournamentList =
How It Works
(List<TournamentContent>)model.get("feedContent"); List<Entry> entries = new ArrayList<Entry>(tournamentList.size()); for (TournamentContent tournament : tournamentList) { Entry entry = new Entry(); String date = String.format("%1$tY-%1$tm-%1$td",
How It Works
tournament.getPublicationDate()); entry.setId(String.format("tag:tennis.org,%s:%d", date,
How It Works
tournament.getId())); entry.setTitle(String.format("%s - Posted by %s",
How It Works
tournament.getName(), tournament.getAuthor())); entry.setUpdated(tournament.getPublicationDate()); Content summary = new Content(); summary.setValue(String.format("%s - %s",
How It Works
tournament.getName(),tournament.getLink())); entry.setSummary(summary); entries.add(entry); } return entries; } }

The first thing to notice about this class is that it imports several Project Rome classes from the com.sun.syndication.feed.atom package, in addition to implementing the AbstractAtomFeedView class provided by the Spring framework. In doing so, the only thing that's needed next is to provide a feed's implementation details for two methods inherited from the AbstractAtomFeedView class: buildFeedMetadata and buildFeedEntries.

The buildFeedMetadata has three input parameters. A Map object which represents the data used to build the feed (i.e., data assigned inside the handler method, in this case a List of TournamentContent objects), a Feed object based on a Project Rome class that is used to manipulate the feed itself, and an HttpServletRequest object in case it's necessary to manipulate the HTTP request.

Inside the buildFeedMetadata method, you can observe several calls are made to the Feed object's setter methods (e.g., setId, setTitle, setUpdated). Two of these calls are made using hard-coded strings, while another is made with a value determined after looping over a feed's data (i.e., the Map object). All these calls represent the assignment of an Atom feed's metadata information.

Note

Consult Project Rome's API if you want to assign more values to an Atom feed's metadata section, as well as specify a particular Atom version. The default version is Atom 1.0.

The buildFeedEntries method also has three input parameters: a Map object that represents the data used to build the feed (i.e., data assigned inside the handler method, in this case a List of TournamentContent objects), an HttpServletRequest object in case it's necessary to manipulate the HTTP request, and an HttpServletResponse object in case it's necessary to manipulate the HTTP response. It's also important to note the buildFeedEntries method returns a List objects, which in this case corresponds to a List of Entry objects based on a Project Rome class and containing an Atom feed's recurring elements.

Inside the buildFeedEntries method, you can observe that the Map object is accessed to obtain the feedContent object assigned inside the handler method. Once this is done, an empty List of Entry objects is created. Next, a loop is performed on the feedContent object, which contains a list of a List of TournamentContent objects, and for each element, an Entry object is created that is assigned to the top-level List of Entry objects. Once the loop is finished, the method returns a filled List of Entry objects.

Note

Consult Project Rome's API if you want to assign more values to an Atom feed's recurring elements section.

Upon deploying this last class, in addition to the previously cited Spring MVC controller, accessing a URL in the form http://[host_name]/[app-name]/atomfeed.atom (or http://[host_name]/atomfeed.xml) would result in the following response:

<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Grand Slam Tournaments</title>
  <id>tag:tennis.org</id>
  <updated>2010-03-04T20:51:50Z</updated>
  <entry>
    <title>Australian Open - Posted by ATP</title>
    <id>tag:tennis.org,2010-03-04:0</id>
    <updated>2010-03-04T20:51:50Z</updated>
    <summary>Australian Open - www.australianopen.com</summary>
  </entry>
  <entry>
    <title>Roland Garros - Posted by ATP</title>
    <id>tag:tennis.org,2010-03-04:1</id>
    <updated>2010-03-04T20:51:50Z</updated>
    <summary>Roland Garros - www.rolandgarros.com</summary>
  </entry>
<entry>
    <title>Wimbledon - Posted by ATP</title>
    <id>tag:tennis.org,2010-03-04:2</id>
    <updated>2010-03-04T20:51:50Z</updated>
    <summary>Wimbledon - www.wimbledon.org</summary>
  </entry>
  <entry>
    <title>US Open - Posted by ATP</title>
    <id>tag:tennis.org,2010-03-04:3</id>
    <updated>2010-03-04T20:51:50Z</updated>
    <summary>US Open - www.usopen.org</summary>
  </entry>
</feed>

Turning your attention to the remaining handler method—getRSSFeed—from the previous Spring MVC controller charged with building an RSS feed, you'll see that the process is similar to the one just described for building Atom feeds.

The handler methods also creates a List of TournamentContent objects, which is then assigned to the handler method's Model object for it to become accessible to the returning view. The returning logical view in this case though, now corresponds to one named rssfeedtemplate. As described earlier, this logical view is mapped to a class named RssFeedView.

The following listing illustrates the RssFeedView class, which implements the AbstractRssFeedView class:

package com.apress.springrecipes.court.feeds;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.syndication.feed.rss.Channel;
import com.sun.syndication.feed.rss.Item;
import org.springframework.web.servlet.
How It Works
view.feed.AbstractRssFeedView; import java.util.Date; import java.util.List; import java.util.ArrayList; import java.util.Map; public class RSSFeedView extends AbstractRssFeedView { protected void buildFeedMetadata(Map model,
How It Works
Channel feed, HttpServletRequest request) { feed.setTitle("World Soccer Tournaments"); feed.setDescription("FIFA World Soccer Tournament Calendar"); feed.setLink("tennis.org"); List<TournamentContent> tournamentList = (List<TournamentContent>)model.
How It Works
get("feedContent"); for (TournamentContent tournament : tournamentList) { Date date = tournament.getPublicationDate();
if (feed.getLastBuildDate() == null || date.compareTo(feed.
How It Works
getLastBuildDate()) > 0) { feed.setLastBuildDate(date); } } } protected List buildFeedItems(Map model,
How It Works
HttpServletRequest request, HttpServletResponse response)
How It Works
throws Exception { List<TournamentContent> tournamentList = (List<TournamentContent>)model.get
How It Works
("feedContent"); List<Item> items = new ArrayList<Item>(tournamentList.size()); for (TournamentContent tournament : tournamentList) { Item item = new Item(); String date = String.format("%1$tY-%1$tm-%1$td", tournament.get
How It Works
PublicationDate()); item.setAuthor(tournament.getAuthor()); item.setTitle(String.format("%s - Posted by %s", tournament.getName(),
How It Works
tournament.getAuthor())); item.setPubDate(tournament.getPublicationDate()); item.setLink(tournament.getLink()); items.add(item); } return items; } }

The first thing to notice about this class is that it imports several Project Rome classes from the com.sun.syndication.feed.rss package, in addition to implementing the AbstractRssFeedView class provided by the Spring framework. Once it does so, the only thing that's needed next is to provide a feed's implementation details for two methods inherited from the AbstractRssFeedView class: buildFeedMetadata and buildFeedItems.

The buildFeedMetadata method is similar in nature to the one by the same name used in building an Atom feed. Notice the buildFeedMetadata method manipulates a Channel object based on a Project Rome class, which is used to build RSS feeds, instead of a Feed object, which is used to build Atom feeds. The setter method calls made on the Channel object (e.g., setTitle, setDescription, setLink) represent the assignment of an RSS feed's metadata information.

The buildFeedItems method, which differs in name to its Atom counterpart buildFeedEntries, is so named because an Atom feed's recurring elements are called entries and an RSS feed's recurring elements are items. Naming conventions aside, their logic is similar.

Inside the buildFeedItems method, you can observe that the Map object is accessed to obtain the feedContent object assigned inside the handler method. Once this is done, an empty List of Item objects is created. Next, a loop is performed on the feedContent object, which contains a list of a List of TournamentContent objects, and for each element, an Item object is created which is assigned to the top level List of Item objects. Once the loop is finished, the method returns a filled List of Item objects.

Note

Consult Project Rome's API if you want to assign more values to an RSS feed's metadata and recurring element sections, as well as specify a particular RSS version. The default version is RSS 2.0.

When you deploy this last class, in addition to the previously cited Spring MVC controller, accessing a URL in the form http://[host_name]/rssfeed.rss (or http://[host_name]/rssfeed.xml) results in the following response:

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>World Soccer Tournaments</title>
    <link>tennis.org</link>
    <description>FIFA World Soccer Tournament Calendar</description>
    <lastBuildDate>Thu, 04 Mar 2010 21:45:08 GMT</lastBuildDate>
    <item>
      <title>World Cup - Posted by FIFA</title>
      <link>www.fifa.com/worldcup/</link>
      <pubDate>Thu, 04 Mar 2010 21:45:08 GMT</pubDate>
      <author>FIFA</author>
    </item>
    <item>
      <title>U-20 World Cup - Posted by FIFA</title>
      <link>www.fifa.com/u20worldcup/</link>
      <pubDate>Thu, 04 Mar 2010 21:45:08 GMT</pubDate>
      <author>FIFA</author>
    </item>
    <item>
      <title>U-17 World Cup - Posted by FIFA</title>
      <link>www.fifa.com/u17worldcup/</link>
      <pubDate>Thu, 04 Mar 2010 21:45:08 GMT</pubDate>
      <author>FIFA</author>
    </item>
    <item>
      <title>Confederations Cup - Posted by FIFA</title>
      <link>www.fifa.com/confederationscup/</link>
      <pubDate>Thu, 04 Mar 2010 21:45:08 GMT</pubDate>
      <author>FIFA</author>
    </item>
  </channel>
</rss>

Publishing JSON with REST services

Problem

You want to publish JavaScript Object Notation (JSON) in a Spring application.

Solution

JSON, in addition to RSS and Atom, has blossomed into a favorite payload format for REST services. However, unlike most REST service payloads, which rely on XML markup, JSON is different in the sense that its content is a special notation based on the JavaScript language.

For this recipe, in addition to relying on Spring's REST support, we will also use the MappingJacksonJsonView class that forms part of Spring to facilitate the publication of JSON content.

Note

The MappingJacksonJsonView class depends on the presence of the Jackson JSON processor library which can be downloaded at http://wiki.fasterxml.com/JacksonDownload. If you're using Maven, add the following dependency to your project:

<dependency>
  <groupId>org.codehaus.jackson</groupId>
  <artifactId>jackson-mapper-asl</artifactId>
  <version>1.4.2</version>
 </dependency>

How It Works

The first thing you need to do is determine the information you wish to publish as a JSON payload. This information can be located in a RDBMS or text file, accessed through JDBC or ORM, inclusively be part of a Spring bean or some other type of construct. Describing how to obtain this information would go beyond the scope of this recipe, so we will assume you'll use whatever means you deem appropriate to access it.

In case you're unfamiliar with JSON, the following snippet illustrates a fragment of this format:

{
    "glossary": {
        "title": "example glossary",
                "GlossDiv": {
            "title": "S",
                        "GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
                                        "SortAs": "SGML",
                                        "GlossTerm": "Standard Generalized Markup Language",
                                        "Acronym": "SGML",
                                        "Abbrev": "ISO 8879:1986",
                                        "GlossDef": {
                        "para": "A meta-markup language, used to create markup 
How It Works
languages such as DocBook.", "GlossSeeAlso": ["GML", "XML"] }, "GlossSee": "markup" } } } } }

As you can observe, a JSON payload consists of text and separators like {, }, [, ], : and ". We won't go into details about using one separator over another, but it suffices to say this type of syntax makes it easier for a JavaScript engine to access and manipulate data than if it was to process it in an XML type format.

Since you've already explored how to publish data using a REST service in recipes 9-1 and 9-3, we'll cut to the chase and show you the actual handler method needed in a Spring MVC controller to achieve this process.

@RequestMapping("/jsontournament")
    public String getJSON(Model model) {
        List<TournamentContent> tournamentList = new ArrayList<TournamentContent>();
        tournamentList.add(TournamentContent.generateContent("FIFA", 
How It Works
new Date(),"World Cup","www.fifa.com/worldcup/")); tournamentList.add(TournamentContent.generateContent("FIFA",
How It Works
new Date(),"U-20 World Cup","www.fifa.com/u20worldcup/")); tournamentList.add(TournamentContent.generateContent("FIFA",
How It Works
new Date(),"U-17 World Cup","www.fifa.com/u17worldcup/"));
tournamentList.add(TournamentContent.generateContent("FIFA", 
How It Works
new Date(),"Confederations Cup","www.fifa.com/confederationscup/")); model.addAttribute("feedContent",tournamentList); return "jsontournamenttemplate"; }

This last handler method is mapped to a URL in the form http://[host_name]/[app-name]/jsontournament. Similar to the handler methods used in recipe 9-3 to publish Atom and RSS feeds, this handler method defines a List of TournamentContent objects, where the backing class for a TournamentContent object is a POJO. This List is then assigned to the handler method's Model object, so it becomes accessible to the returning view. The returning logical view in this case is named jsontournamentemplate.

This last logical view is defined in the following manner inside a Spring XML configuration file:

<bean id="jsontournamenttemplate" 
How It Works
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>

Note the logical view jsontournamenttemplate is mapped to the MappingJacksonJsonView class provided by the Spring framework. This last class converts the entire contents of the model map (i.e., the one assigned inside the handler method) and encodes it as JSON.

In this manner, if you access a URL in the form http://[host_name]/jsontournament.json (or http://[host_name]/jsontournament.xml), you will obtain the following response:

{
   "handlingTime":1,
"feedContent":
      [
          {"link":"www.fifa.com/worldcup/",
            "publicationDate":1267758100256,
            "author":"FIFA",
            "name":"World Cup",
            "id":16},
          {"link":"www.fifa.com/u20worldcup/",
           "publicationDate":1267758100256,
           "author":"FIFA",
           "name":"U-20 World Cup",
           "id":17},
          {"link":"www.fifa.com/u17worldcup/",
            "publicationDate":1267758100256,
            "author":"FIFA",
            "name":"U-17 World Cup",
            "id":18},
          {"link":"www.fifa.com/confederationscup/",
            "publicationDate":1267758100256,
            "author":"FIFA",
            "name":"Confederations Cup",
            "id":19}
          ]
}

Accessing REST Services with Elaborate XML Responses

Problem

You want to access a REST service with an elaborate XML response and use its data inside a Spring application.

Solution

REST services have become a popular means by which to publish information. However, the data structures returned by certain REST services can turn out to be quite complex.

Though the Spring RestTemplate class is capable of performing a multitude of operations on REST services in order for their payloads to be used inside Spring applications, processing elaborate XML responses requires using a set of approaches beyond those of this last class.

These approaches include relying on data streams, XPath—an XML query language for selecting nodes from an XML document— knowledge about Spring's HttpConverterMessage, as well as supporting facilities like Spring's XPathTemplate.

How It Works

Since you've already explored how to access a REST service in recipe 9-2 using the Spring RestTemplate class, what we'll do next is concentrate on the particularities of processing a REST service that returns a more elaborate XML response, in this case an RSS feed.

Let's start with the case of accessing an RSS feed containing weather information, with the RSS feed having the following end point: http://rss.weather.com/rss/national/rss_nwf_rss.xml?cm_ven=NWF&cm_cat=rss&par=NWF_rss.

Based on what you learned in recipe 9-2, the Spring MVC controller handler method used to access the RSS feed would be the following:

@RequestMapping("/nationalweather")
    public String getWeatherNews(Model model) {
        // Return view nationalweathertemplatee. Via resolver the view
        // will be mapped to /WEB-INF/jsp/nationalweathertemplate.jsp
        String result = restTemplate.getForObject("http://rss.weather.com/rss/
How It Works
national/rss_nwf_rss.xml?cm_ven={cm_ven}&cm_cat={cm_cat}
How It Works
&par={par}", String.class, "NWF","rss","NWF_rss"); model.addAttribute("nationalweatherfeed",result); return "nationalweathertemplate"; }

The handler method makes use of the getForObject method of the RestTemplate class and assigns the returning XML payload to a String, which is then added to the handler method's Model object. Once the String is added, the method relinquishes control to the logical view named nationalweathertemplate, so the XML payload can be displayed to the requesting party.

This logic is identical to that of recipe 9-2. However, since we're now dealing with a more elaborate payload—in this case RSS—it's convenient to assign the REST service's payload to something other than a String. Why? So it becomes easier to extract and manipulate the contents of the REST service.

To extract and manipulate payloads in Spring REST in a format other than a String, it's necessary to discuss the HttpConverterMessage interface. All objects that are returned and inclusively passed to the methods belonging to the RestTemplate class—those described in Table 9-1—are converted to and from HTTP messages using a class which implements the HttpConverterMessage interface.

The default HttpConverterMessage implementations registered with the RestTemplate class are ByteArrayHttpMessageConverter, StringHttpMessageConverter, FormHttpMessageConverter, and SourceHttpMessageConverter. This means that it's possible to cast a REST service's payload into a byte array, string array, form data, or a source, respectively.

Tip

It's also possible to write your own converters relying on the MarshallingHttpMessageConverter interface that would allow the use of custom marshallers. Using custom converters requires registering them with the messageConverters bean property in a Spring application. In addition, it's also possible to override the default implementations registered with the RestTemplate class using the same messageConverters bean property.

For example, the following snippet illustrates how a REST service's payload is cast into a stream source (i.e., javax.xml.transform.stream.StreamSource ), which is an implementation of a source type (i.e., javax.xml.transform.Source):

StreamSource result = restTemplate.getForObject("
How It Works
http://rss.weather.com/rss/national/rss_nwf_rss.xml?
How It Works
cm_ven={cm_ven}&cm_cat={cm_cat}&par={par}",
How It Works
StreamSource.class, "NWF","rss","NWF_rss");

By performing this last task, it becomes easier to extract and manipulate the contents of a REST service's payload, since it can be done through the more flexible StreamSource class.

One approach involving a StreamSource payload consists of further transforming it into a better data-manipulation class such as Java's Document Object Model (DOM) interface (i.e. org.w3c.dom.Document ). By going down this route, a REST service's content can be extracted in a more granular fashion. The following listing illustrates the body of a Spring MVC handler method, which extracts a REST service's payload using the Document interface and parts from a StreamSource class obtained using the RestTemplate class:

StreamSource source = restTemplate.getForObject("
How It Works
http://rss.weather.com/rss/national/rss_nwf_rss.xml?
How It Works
cm_ven={cm_ven}&cm_cat={cm_cat}&par={par}",
How It Works
StreamSource.class, "NWF","rss","NWF_rss"); // Define DocumentBuilderFactory DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setValidating(false); dbf.setIgnoringComments(false); dbf.setIgnoringElementContentWhitespace(true); dbf.setNamespaceAware(true); // Define DocumentBuilder DocumentBuilder db = null; db = dbf.newDocumentBuilder(); // Define InputSource InputSource is = new InputSource(); is.setSystemId(source.getSystemId()); is.setByteStream(source.getInputStream()); is.setCharacterStream(source.getReader()); is.setEncoding("ISO-8859-1"); // Define DOM W3C Document Document doc = db.parse(is); // Get items NodeList itemElements = doc.getElementsByTagName("item"); // Define lists for titles and links List feedtitles = new ArrayList(); List feedlinks = new ArrayList(); // Loop over all item elements int length = itemElements.getLength(); for ( int n = 0; n < length; ++n ) { NodeList childElements = itemElements.item(n).getChildNodes(); int lengthnested = childElements.getLength(); for ( int k = 0; k < lengthnested; ++k ) { if (childElements.item(k).getNodeName() == "title") { feedtitles.add(childElements.item(k).getChildNodes().item(0).getNodeValue()); } if (childElements.item(k).getNodeName() == "link") { feedlinks.add(childElements.item(k).getChildNodes().item(0).getNodeValue()); } } }
// List for content
List feedcontent = new ArrayList();
int titlelength = feedtitles.size();
// Loop over extracted titles and links
for  ( int x = 0; x  <  titlelength; ++x ) {
  feedcontent.add(new FeedContent((String)feedtitles.get(x),(String)feedlinks.get(x)));
}
// Place feed type, version and content in model object
model.addAttribute("feedtype",
How It Works
doc.getDocumentElement().getNodeName()); model.addAttribute("feedversion",
How It Works
doc.getDocumentElement().getAttribute("version")); model.addAttribute("feedcontent",feedcontent); return "nationalweathertemplate";

Warning

Processing REST service payloads (i.e., XML) is often fraught with encoding issues. The majority of XML payloads are preceded with a statements like <?xml version="1.0" encoding="UTF-8"?> or <?xml version="1.0" encoding="ISO-8859-1" ?>—meaning the payload is encoded as UTF-8 or ISO-8859-1, respectively. Or the payload may simply have no encoding statement at all. These statements, or lack thereof, can make it difficult for a consuming party to process data appropriately. Processing errors such as "Invalid byte 1 of 1-byte UTF-8 sequence" are fairly common when encoding information conflicts with how the payload is actually encoded. To deal with these type of conflicts, it can be necessary to coerce a payload to a certain encoding or explicitly specify the encoding in a transformation class in order for it to be processed correctly.

There are multiple steps involved using this last approach. Once a REST service's payload is cast into a StreamSource class, a DocumentBuilderFactory, DocumentBuilder, and InputSource class are created. These last classes are standard in the manipulation of XML data in Java applications, as they allow the data extraction process to be highly customized (e.g., specify an encoding, validate it, and transform it using something like XSL). With the aid of these classes, a REST service's payload is placed inside a Document object.

Once the payload is available as a Document object, several iterations are performed on the data using classes and methods related to the DOM (e.g., NodeList, Node, getChildNodes()). Upon finishing the data extraction process, three objects—feedtype, feedversion, and feedcontent—are assigned to the handler method's Model object to display the values inside the returning view. In this case, the returning view is mapped to a JSP that displays the object values to an end user.

As you can attest, the process of extracting a REST service's payload can be done at a more granular level than using a Java String as it was done in recipe 9-2.

Another approach to extracting a REST service's payload involves using XPath. XPath is a query language for XML data. Similar in nature to SQL, which is used to extract granular data sets in RDBMS, XPath serves the same purpose but for XML. XPath's syntax and usage scenarios can become elaborate since it's a full-fledged language. Given this fact, we will concentrate on the basics of XPath and how it integrates with REST services and Spring. You can consult the XPath specification at http://www.w3.org/TR/xpath/ for more details on its syntax and usage scenarios.

Just like the DOM, XPath is supported in the core Java platform. The following listing illustrates the previous Spring MVC handler method using Java's javax.xml.xpath.XPathExpression interface:

// Omitted for brevity- REST payload transformation to W3C Document
// Define W3C Document
Document doc = db.parse(is);

// Define lists for titles and links
List feedtitles = new ArrayList();
List feedlinks = new ArrayList();

// Defin XPath constructs
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();

// Define XPath expression to extract titles
XPathExpression titleexpr = xpath.compile("//item/title");
// Define XPath expression to extract links
XPathExpression linkexpr = xpath.compile("//item/link");

// Evaluate XPath expressions
Object titleresult = titleexpr.evaluate(doc, XPathConstants.NODESET);
Object linkresult = linkexpr.evaluate(doc, XPathConstants.NODESET);

// Loop over extracted title elements using DOM
NodeList titlenodes = (NodeList) titleresult;
for (int i = 0; i < titlenodes.getLength(); i++) {
  feedtitles.add(titlenodes.item(i).getChildNodes().item(0).getNodeValue());
}

// Loop over extracted link elements using DOM
NodeList linknodes = (NodeList) linkresult;
for (int j = 0; j < linknodes.getLength(); j++) {
  feedlinks.add(linknodes.item(j).getChildNodes().item(0).getNodeValue());
}
   // Omitted for brevity- Values placed in Model object and returned to view
return "nationalweathertemplate";

Though this last approach also relies on the transformation of a REST service's payload into a Document object, notice how XPath makes the data extraction process simpler than just using the DOM. In one case, the XPath expression //item/title is used to extract all the <title> elements nested inside <item> elements. In another case, the XPath expression //item/link is used to extract all the <link> elements nested inside <item> elements.

Once XPath is used to obtain the elements, the elements are cast into a DOM NodeList object, where their data is finally extracted and assigned to the handler method's Model object to be displayed to the requesting user.

In addition to using Java's built-in XPath class, it's also possible to use another series of XPath-related approaches using Spring classes. These approaches form part of Spring's XML project.

Note

The Spring XML project JAR is distributed separately from Spring's core distribution and can be obtained at http://www.springsource.com/repository/app/bundle/version/download?name=org. springframework.xml&version=1.5.9.A&type=binary. If you are using Maven, add the following dependencies to your project:

<dependency>
  <groupId>org.springframework.ws</groupId>
  <artifactId>spring-xml</artifactId>
  <version>1.5.9</version>
 </dependency>

 <dependency>
  <groupId>org.springframework.ws</groupId>
  <artifactId>spring-oxm</artifactId>
  <version>1.5.9</version>
 </dependency>

The first approach involving XPath and Spring classes involves defining XPath expressions as Spring beans. This allows XPath expressions to be reused throughout an application, in addition to limiting the need to use additional XPath instantiation classes (e.g., XPathFactory, XPath) and instead rely on Spring's bean injection.

For example, the previous XPath expression can be defined in the following manner inside an application's Spring configuration file:

<bean id="feedtitleExpression" 
How It Works
class="org.springframework.xml.xpath.XPathExpressionFactoryBean"> <property name="expression" value="//item/title"/> </bean> <bean id="feedlinkExpression" class="org.springframework.xml.xpath.
How It Works
XPathExpressionFactoryBean"> <property name="expression" value="//item/link"/> </bean>

Once these XPath expression beans are defined, they can be injected into a Spring MVC controller class and used inside a handler method, just as if they were declared using Java's core XPath classes (e.g., XPathFactory, XPath.). The following listing illustrates the contents of a Spring MVC controller using this process:

@Autowired
protected XPathExpression feedtitleExpression;
@Autowired
protected XPathExpression feedlinkExpression;

// START HANDLER METHOD
// Omitted for brevity- REST payload transformation to W3C Document
// Define W3C Document
Document doc = db.parse(is);

// Define lists for titles and links
List feedtitles = new ArrayList();
List feedlinks = new ArrayList();

List<Node> titlenodes =  feedtitleExpression.
How It Works
evaluateAsNodeList(doc.getDocumentElement()); List<Node> linknodes = feedlinkExpression.
How It Works
evaluateAsNodeList(doc.getDocumentElement()); for (Node node : titlenodes) { feedtitles.add(node.getChildNodes().item(0).getNodeValue()); } for (Node node : linknodes) { feedlinks.add(node.getChildNodes().item(0).getNodeValue()); } // Omitted for brevity- Values placed in Model object and returned to view return "nationalweathertemplate";

Notice that by using Spring's XPathExpressionFactoryBean as well as Spring's XPathExpression, the code to extract a REST service's payload becomes simpler. First of all, the XPath expression beans are injected into the class using the @Autowired annotation. Once available, the XPath expression beans are evaluated by passing the REST service's payload in the form of a Document object.

Further note how the results of evaluating the evaluateAsNodeList, which belongs to Spring's XPathExpression class, are cast into a List of Node objects, instead of the DOM's NodeList class, something which also makes the data-extraction process simpler by being able to use a short-handed Java loop.

Another alternative available using Spring's XML project consists of the NodeMapper class. The purpose of the NodeMapper class is to directly map XML nodes into Java objects.

For the NodeMapper case, let's assume you have the following XPath expression bean defined inside your Spring configuration file:

<bean id="feeditemExpression" 
How It Works
class="org.springframework.xml.xpath.XPathExpressionFactoryBean"> <property name="expression" value="//item"/> </bean>

This XPath expression bean is defined with a value //item. This XPath value indicates to extract all the <item> elements that belong to an XML payload. In case you don't recall, <item> elements represent the recurring elements of an RSS feed, which further contain elements such as <title> and <link>.

The following listing illustrates how to use the NodeMapper class using this last XPath expression bean in the context of a Spring MVC controller:

@Autowired
protected XPathExpression feeditemExpression;

// START HANDLER METHOD
// Omitted for brevity- REST payload transformation to W3C Document
// Define W3C Document
Document doc = db.parse(is);

// Define lists for titles and links
List feedtitles = new ArrayList();
List feedlinks = new ArrayList();

List feedcontent = feeditemExpression.evaluate(doc, 
How It Works
new NodeMapper() { public Object mapNode(Node node, int nodeNum)
How It Works
throws DOMException { Element itemElement = (Element) node; Element titleElement =
How It Works
(Element) itemElement.getElementsByTagName("title").item(0); Element linkElement =
How It Works
(Element) itemElement.getElementsByTagName("link").item(0); return new FeedContent(titleElement.getTextContent(),
How It Works
linkElement.getTextContent()); } } ); // Place feed type, version and content in model object model.addAttribute("feedtype",
How It Works
doc.getDocumentElement().getNodeName()); model.addAttribute("feedversion",
How It Works
doc.getDocumentElement().getAttribute("version")); model.addAttribute("feedcontent",feedcontent); return "nationalweathertemplate";

The XPath expression bean is injected into the controller class using the @Autowired annotation, just as the previous example. However, notice the XPath expression bean reference—feedItemExpression—is passed a Document object as well as a NodeMapper instance. The Document object represents the XML payload cast from a StreamSource class obtained using the RestTemplate class, which is identical to the previous approaches. The NodeMapper instance, though, deserves further explanation.

The NodeMapper loops over the elements that match the XPath expression bean, in this case <item> elements. On each iteration, it relies on the DOM's Element to extract each <item> element's nested <title> and <link> values. Further note that, after each iteration, a POJO backed by the class FeedContent and containing these values is returned. As a consequence of this step, the results of evaluating the XPath expression—feedItemExpression—are a List of FeedContent objects and not List DOM Node objects, making the data available for immediate assignment to the handler method's Model object instead of requiring further processing of DOM Node objects.

As you can see, using the Spring NodeMapper class further shortens the process of extracting data in a granular fashion from a REST service.

Finally, another approach involving Spring classes based on XPath involves using XPathTemplate. XPathTemplate is by far the shortest—syntax-wise—of all the approaches available to extract data from a REST service in a Spring application.

The first thing that's needed to use the XPathTemplate is to define a XPathTemplate Spring bean to make it available (i.e. inject it) into a Spring MVC controller. The following snippet illustrates this configuration, which needs to be placed inside a Spring configuration file:

<bean id="feedXPathTemplate"
How It Works
class="org.springframework.xml.xpath.Jaxp13XPathTemplate"> </bean>

Note

Jaxp13XPathTemplate is an implementation of XPathTemplate, another implementation is JaxenXPathTemplate. Both are included in Spring's XML project, and you can use either one. The difference is that one is built on JAXP 1.3 (which is part of the Java 5 core platform), and the other is built on Jaxen, an open source Java XPath library.

Once an XPathTemplate Spring bean is defined, it's possible to inject it into a Spring MVC controller using the @Autowired annotation and then use it inside a handler method's body. The following listing illustrates this process:

@Autowired
protected org.springframework.xml.xpath.AbstractXPathTemplate feedXPathTemplate;

@RequestMapping("/nationalweather")
public String getWeatherNews(Model model) {
Source source = restTemplate.getForObject("
How It Works
http://rss.weather.com/rss/national/rss_nwf_rss.xml?
How It Works
cm_ven={cm_ven}&cm_cat={cm_cat}&par={par}",
How It Works
Source.class, "NWF","rss","NWF_rss"); // Define lists for titles and links List feedtitles = new ArrayList(); List feedlinks = new ArrayList(); List feedcontent = feedXPathTemplate.evaluate("//item", source,
How It Works
new NodeMapper() { public Object mapNode(Node node, int nodeNum) throws DOMException { Element itemElement = (Element) node; Element titleElement = (Element) itemElement.getElementsByTagName("title").item(0); Element linkElement = (Element) itemElement.getElementsByTagName("link").item(0);
return new FeedContent(titleElement.getTextContent(),
How It Works
linkElement.getTextContent()); } } ); // No Document, so just hard-code feed type and version model.addAttribute("feedtype","rss"); model.addAttribute("feedversion","2.0"); // Place feedcontent obtained using XPathTemplate model.addAttribute("feedcontent",feedcontent); return "nationalweathertemplate"; }

Notice the response of the getForObject method—part of the RestTemplate class. Unlike the previous approaches, it is assigned to a Source interface, instead of a StreamSource class, because the XPathTemplate expects to work with an XML payload built as a Source reference. It's worth mentioning that the StreamSource class implements the Source interface, so they're compatible.

If you then look at the XPathTemplate reference, feedXPathTemplate, you will note the call to the evaluate method takes three input parameters: //item, which represents an XPath query for all <item> elements; source, which represents a reference to the XML payload on which the XPath query is applied; and a NodeMapper instance used to loop over the elements extracted in applying the XPath query. The return value of calling the evaluate method corresponds to a List of FeedContent objects, making the data available for immediate assignment to the handler method's Model object.

As you can observe, by using Spring's XPathTemplate, the process of extracting a REST service's payload is further shortened, by forgoing the use of a DOM Document object and the capability of declaring XPath expression in line.

Even though Spring's XPathTemplate approach can seem like an obvious choice over all the previous methods given its succinctness, it's important to realize that flexibility can also be an important factor in processing REST service payloads. By using some of the earlier and more general-purpose approaches to processing XML, you have the ability to choose from a wider set of techniques for processing and manipulating XML (e.g., using filters, explicitly specifying encodings, or applying XSL style-sheets), which under certain circumstances, can prove to be more powerful than using Spring's XPathTemplate.

Finally, it's worth mentioning that in addition to the approaches described here—which are among the most popular for processing XML payloads—a multitude of libraries are available for processing XML in Java. Some of these other libraries include JDOM, Castor XML, and Project Rome. Depending on your previous experience with some of these libraries, you can opt to use them instead or in conjunction with the techniques described here.

Summary

In this chapter, you have learned how to develop and access REST services using Spring. REST services are closely tied to Spring MVC, whereby a controller acts to dispatch requests made to REST services, as well as access third-party REST services to use this information for application content.

You learned how REST services leverage annotations used in Spring MVC controllers, which included @RequestMapping to indicate service end points, as well as @PathVariable to specify access parameters for filtering a service's payload. In addition, you learned about Spring's XML marshallers, such as Jaxb2Marshaller, which allow application objects to be transformed into XML and be output as a REST service's payload.

You also learned about Spring's RestTemplate class and how it supports the series of HTTP protocol methods that include HEAD, GET, POST, PUT, and DELETE—all of which allow you to access and perform operations on third-party REST services directly from the context of a Spring application.

You also explored how to publish Atom and RSS feeds in a Spring application by leveraging the Project Rome API. Additionally, you learned how to publish JSON payloads in a Spring application.

Finally, you learned how to access REST services with elaborate XML payloads using a variety of techniques that included data streams, XPath, marshallers, Spring's HttpMessageConverter, and Spring's XPathTemplate.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset