Posts tagged: rest
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()); } }); } }