Spring, rest, jax-b, xml, data binding technologies

Easy REST with Spring RestTemplate and JAX-B

Representational state transfer (REST) is a very popular architecture for distributed hypermedia. Lots of different web services expose their APIs in a RESTful manner. It is very convenient when a service of a choice provides a library for its API, but this is not always so. In this case you have to construct valid requests and parse responses by yourself. Assuming that you are familiar with REST itself, I will tell you how you can make your life easier with the help of Spring and Java annotations.

Let’s consider a service that stores some accounts. To retrieve one we must issue a request
GET https://api.example.com/accounts/{id}

Providing “1” as the id we get something like this in response body

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<account href="https:// api.example.com/accounts/1">
 <id type="integer">1</id>
 <username>tester</username>
 <email>tester@ example.com</email>
 <full_name>John Doe</full_name>
 <created_at type="datetime">2011-10-25T12:00:00</created_at>
</account>

Our goal is to map this data to a JavaBean and be able to GET and POST it back and forth. Doing such a task manually is very low level with all the consequences. You can use a ready solution such as Spring RestTemplate for HTTP communications and JAX-B for data binding.

Mapping a JavaBean to an XML element is as easy as putting @XmlRootElement on top of your class and annotating every field you want to be mapped with @XmlElement. If you put bare annotation then the name of the XML Schema element is derived from the JavaBean field name. If names don’t match you can specify it with the “name” element.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@XmlRootElement(name = "account")
public class Account {
    @XmlElement
    private Integer id;
    @XmlElement
    private String username;
    @XmlElement
    private String email;
    @XmlElement(name = "full_name")
    private String fullName;
    @XmlElement(name = "created_at")
    private Date createdAt;

    public Account() {}
   
    /* Getters and setters */
}

Issuing requests and receiving responses is not a single bit harder. All data binding occurs automatically.

1
2
3
RestTemplate rest = new RestTemplate();
Account account = rest.getForObject("https://api.example.com/accounts/1",
                                    Account.class);

First you create a RestTemplate object and then you invoke according methods against it. First part of method's name indicates what HTTP method will be used, while the second part of the name indicates what is returned. In this case a GET is performed, HTTP response is converted into an object type of Account, which is then returned. There are dedicated methods for each of six main HTTP methods (DELETE, GET HEAD, OPTIONS, POST, PUT) in RestTemplate.

Let’s make some changes to the entity’s state

1
2
account.setEmail("changed@ example.com");
URI uri = rest.postForLocation("https:// api.example.com/accounts/1", account);

And delete it when it is no longer needed

1
rest.delete(uri);

Now, suppose our service mandates authentication for using its API. For this purpose it requires an API key to be present in request headers. For such manipulations on the request we must implement ClientHttpRequestFactory interface and provide this object as a constructor parameter during RestTemplate initialization. Here’s an example of extending CommonsClientHttpRequestFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.sysgears.example;

import org.apache.commons.httpclient.HttpMethodBase;
import org.springframework.http.client.CommonsClientHttpRequestFactory;

public class RequestWithHeadersFactory extends CommonsClientHttpRequestFactory {
    private final String apiKey;

    public RequestWithHeadersFactory(String apiKey) {
        super();
        this.apiKey = apiKey;
    }

    @Override
    protected void postProcessCommonsHttpMethod(HttpMethodBase httpMethod) {
        super.postProcessCommonsHttpMethod(httpMethod);
        httpMethod.addRequestHeader("Accept", "application/xml");
        httpMethod.addRequestHeader("Content-Type",
                                    "application/xml; charset=utf-8");
        httpMethod.addRequestHeader("Authorization", apiKey);
    }
}

Now the construction of RestTemplate looks like this

1
RestTemplate rest = new RestTemplate(new RequestWithHeadersFactory("mySecureKey"));

And all subsequent request will contain above headers. This is it, working with REST should be as easy as rest.

Looking to hire a software developer?
Don't hesitate to contact us.

Comments