Install this theme

Posts tagged: rest

GWT: Creating REST Services with Jersey and RestyGWT

GWT-RPC is known to be a preferred way to implement client-server communication in GWT. Sometimes however it is a good idea to implement server-client communication using REST (e.g. backend services for non-GWT clients, application’s REST API for the world outside etc…)

In this small tutorial we’ll create a simple REST service with Jersey Framework on the serverside and a corresponding REST client with RestyGWT library on the clientside (GWT-side).

Check out the complete maven example project on GitHub: https://github.com/bigpuritz/javaforge-blog/tree/master/restgwt

First we need some domain model class:

public class Person {

    private int id;

    private String name;

    private Date dateOfBirth;

    public Person() {
    }

    public Person(int id, String name, Date dateOfBirth) {
        this.id = id;
        this.name = name;
        this.dateOfBirth = dateOfBirth;
    }

    // getter / setter goes here
}

Now let’s create Person’s REST resource using Jersey:

@Path("/person")
public class PersonResource {

    private static final Logger logger = LoggerFactory
            .getLogger(PersonResource.class);

    private static int counter = 1;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List getPersons() {

        List persons = new ArrayList();
        for (int i = 0; i < 5; i++) {
            persons.add(new Person(counter, "name-" + counter, new Date()));
            counter++;
        }

        logger.info("Returning {} persons...", persons.size());

        return persons;
    }

}

On each http request http://…../rest/person it will return 5 persons as JSON like this:

[
   {"id":1,"name":"name-1","dateOfBirth":1346268802016},
   {"id":2,"name":"name-2","dateOfBirth":1346268802016},
   {"id":3,"name":"name-3","dateOfBirth":1346268802016},
   {"id":4,"name":"name-4","dateOfBirth":1346268802016},
   {"id":5,"name":"name-5","dateOfBirth":1346268802016}
]

Last thing to be done on the serverside is a Jersey configuration in web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
        PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

    <servlet>
        <servlet-name>jersey-rest</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>net.javaforge.gwt.rest.server.remote.rest</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>jersey-rest</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

    <!-- Default page to serve -->
    <welcome-file-list>
        <welcome-file>App.html</welcome-file>
    </welcome-file-list>

</web-app>

Furthermore we need to create a REST client, that will be used as asynchronous remote service in our GWT classes. Writing a REST proxy with RestyGWT is fairly straightforward:

public interface PersonResourceAsync extends RestService {

    @GET
    void getPersons(MethodCallback<List> callback);

    /**
     * Utility class to get the instance of the Rest Service
     */
    public static final class Util {

        private static PersonResourceAsync instance;

        public static final PersonResourceAsync get() {
            if (instance == null) {
                instance = GWT.create(PersonResourceAsync.class);
                ((RestServiceProxy) instance).setResource(new Resource(
                        "rest/person"));
            }
            return instance;
        }

        private Util() {
            // Utility class should not be instantiated
        }
    }

}

Now we can write simple GWT EntryPoint that populates a table from the Person’s REST resource on button click:

public class App implements EntryPoint {

    private FlexTable personsTable;

    static {
        // if you don't do this, on JSON response you'll get something like
        // this:
        // "Could not parse response: org.fusesource.restygwt.client.ResponseFormatException: Response was NOT a valid JSON document"
        Defaults.setDateFormat(null);
    }

    @Override
    public void onModuleLoad() {

        Button button = new Button("load persons");
        button.addClickHandler(new ClickHandler() {

            @Override
            public void onClick(ClickEvent event) {
                loadPersons();
            }
        });

        personsTable = new FlexTable();
        personsTable.setCellPadding(1);
        personsTable.setCellSpacing(0);
        personsTable.setWidth("600px");

        RootPanel.get().add(button);
        RootPanel.get().add(personsTable);

    }

    private void loadPersons() {

        PersonResourceAsync.Util.get().getPersons(
                new MethodCallback<List>() {

                    @Override
                    public void onSuccess(Method method, List persons) {
                        if (personsTable.getRowCount() == 0) { // add header
                            personsTable.setText(0, 0, "ID");
                            personsTable.setText(0, 1, "NAME");
                            personsTable.setText(0, 2, "DATE OF BIRTH");
                            personsTable.getRowFormatter().addStyleName(0,
                                    "tableHeader");
                        }

                        for (Person p : persons) {
                            int rowNum = personsTable.getRowCount();
                            personsTable.setText(rowNum, 0,
                                    String.valueOf(p.getId()));
                            personsTable.setText(rowNum, 1, p.getName());
                            personsTable.setText(rowNum, 2,
                                    String.valueOf(p.getDateOfBirth()));
                        }
                    }

                    @Override
                    public void onFailure(Method method, Throwable exception) {
                        Window.alert("Error while loading persons! Cause: "
                                + exception.getMessage());
                    }
                });
    }
}