Google Web Toolkit or more commonly known as “GWT” is a very powerful and simple way for developers to quickly design web applications that run on all major browsers and taking the pain away from some browsers’s quirks. Today we are going to talk through building a simple GWT RPC web app.
To begin you will need the following installed:
1. Java 6 JDK
2. Eclipse IDE 3.5 for Java EE Developers
3. Google Web Toolkit (GWT) 2.0.x – this is installed already with the GWT Plug-in for Eclipse which I will be using for this tutorial so I would suggest installing that.
4. (Optional) The latest version of Google Chrome, I’ve found debugging and general speed is just much better using Chrome when working with GWT but also know that Internet Explorer and Firefox work pretty good as well.
Ensure that is installed and ready to go before proceeding. There are plenty of instructions on the Internet on how to get this all working so I would suggest using Google for any install help you might need.
Once everything is installed and working fire up Eclipse and create a new GWT project:
Use the following defaults for your project:
Lets test the project before we do anything else and in fact you will see by default a greeting service is created that already uses RPC. Run the project by clicking on the debug icon in Eclipse and ensuring you select the “SimpleRPC” option with the blue Google logo beside it. You should see something like this once you load the project in a browser:
Clicking the button results in this:
You can see that already we have an RPC web app working with no code from us however we will ignore this code and write our own from scratch to better understand what is going on. In fact, you will notice the GWT RPC we build will be even more simple in it’s features but we will do this step-by-step versus the pre-made RPC example code generated for us.
Just for fun though lets change the theme (yes, GWT web apps can be themed). Go into the “SimpleRPC.gwt.xml” file and uncomment the following line:
<inherits name='com.google.gwt.user.theme.dark.Dark'/>
Now comment this line:
<inherits name='com.google.gwt.user.theme.standard.Standard'/>
Your file will look like this:
<?xml version="1.0" encoding="UTF-8"?> <module rename-to='simplerpc'> <!-- Inherit the core Web Toolkit stuff. --> <inherits name='com.google.gwt.user.User'/> <!-- Inherit the default GWT style sheet. You can change --> <!-- the theme of your GWT application by uncommenting --> <!-- any one of the following lines. --> <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> --> <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> --> <inherits name='com.google.gwt.user.theme.dark.Dark'/> <!-- Other module inherits --> <!-- Specify the app entry point class. --> <entry-point class='com.giantflyingsaucer.client.SimpleRPC'/> <!-- Specify the paths for translatable code --> <source path='client'/> <source path='shared'/> </module>
Stop your server and run the project again and you will see the theme has changed completely.
Alright enough messing around, lets get into the meat of this tutorial. Start by adding a new interface to the project. Right-click on the “com.giantflyingsaucer.client” package and select: New-> Interface
Use the following settings:
Make sure to add the interface we are going to extend:
We need to create one more interface. Right-click on the “com.giantflyingsaucer.client” package and select: New-> Interface
We need to add a few lines of code now to the following files. First add this code to the “SimpleService.java” file
// Add this to the "imports"
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
// Add this above the interface declaration
@RemoteServiceRelativePath("simpleservice")
// Add this inside the SimpleService interface
public int handleSimpleRequest(int num1, int num2) throws IllegalArgumentException;
The file should look like this now:
package com.giantflyingsaucer.client;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
@RemoteServiceRelativePath("simpleservice")
public interface SimpleService extends RemoteService
{
public int handleSimpleRequest(int num1, int num2) throws IllegalArgumentException;
}
Add this line of code to the “SimpleServiceAsync.java” file:
void handleSimpleRequest (int num1, int num2, AsyncCallback<integer> callback) throws IllegalArgumentException;
Your code should resemble this:
package com.giantflyingsaucer.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface SimpleServiceAsync
{
void handleSimpleRequest (int num1, int num2, AsyncCallback<integer> callback) throws IllegalArgumentException;
}
Now we need to add the server side implementation of the “handleSimpleRequest”. Create a new class file, right-click on the “com.giantflyingsaucer.server” package: New -> Class
Note: Make sure to include both the interface and inherited class.
Your code for this new class should look similar to this:
package com.giantflyingsaucer.server;
import com.giantflyingsaucer.client.SimpleService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
@SuppressWarnings("serial")
public class SimpleServiceImpl extends RemoteServiceServlet implements SimpleService
{
@Override
public int handleSimpleRequest(int num1, int num2) throws IllegalArgumentException
{
// TODO Auto-generated method stub
return 0;
}
}
Compile the project (make sure the project’s web server is stopped first) just to ensure you have no errors.
If you have any errors double check your code and go through the above steps again.
Rather than modify the “SimpleRPC.java” file we are going to build our own entry point. Right-click on the “com.giantflyingsaucer.client” package and select: New -> Other -> Google Web Toolit -> Entry Point Class
Your code will look like this:
package com.giantflyingsaucer.client;
import com.google.gwt.core.client.EntryPoint;
public class SimpleRPCEntry implements EntryPoint
{
@Override
public void onModuleLoad()
{
// TODO Auto-generated method stub
}
}
We will need to add some sort of UI to this. Essentially what we will have is two textboxes, two labels, and a button. We will use a HorizontalPanel to keep them (poorly) organized. I say poorly organized not to talk bad about the HorizontalPanel but because I don’t want to get into the topic of laying out the components neatly in GWT but instead keep this article simple and to the point. Yes the UI will be a tad ugly as the result. Go ahead and add the following code which will bring in the imports we want to use:
import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.RootPanel;
Add the following components to the “onModuleLoad” method so we can create the UI:
final HorizontalPanel horzPanel = new HorizontalPanel();
final Button submitButton = new Button("Submit");
final TextBox number1Textbox = new TextBox();
final TextBox number2Textbox = new TextBox();
final Label messageLabel = new Label();
final Label additionLabel = new Label("+");
Your code should look like this now:
package com.giantflyingsaucer.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.RootPanel;
public class SimpleRPCEntry implements EntryPoint
{
@Override
public void onModuleLoad()
{
final HorizontalPanel horzPanel = new HorizontalPanel();
final Button submitButton = new Button("Submit");
final TextBox number1Textbox = new TextBox();
final TextBox number2Textbox = new TextBox();
final Label messageLabel = new Label();
final Label additionLabel = new Label("+");
}
}
So there are the components we will need. Lets add the code to create the remote service proxy to talk to the serverside implementation class for SimpleService – this can be added right above the “onModuleLoad” method and below the class declaration.
private final SimpleServiceAsync simpleService = GWT.create(SimpleService.class);
Lets now setup the click handler for the submit button as well as bring the components into the HorizontalPanel:
horzPanel.add(number1Textbox);
horzPanel.add(additionLabel);
horzPanel.add(number2Textbox);
horzPanel.add(submitButton);
horzPanel.add(messageLabel);
submitButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event)
{
}
});
Lets add the code for the “onClick” event now to call the RPC service (and add the HorizontalPanel to the RootPanel):
submitButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event)
{
simpleService.handleSimpleRequest(Integer.parseInt(number1Textbox.getText()), Integer.parseInt(number2Textbox.getText()), new AsyncCallback<integer>() {
@Override
public void onFailure(Throwable caught)
{
messageLabel.setText(caught.getMessage());
}
@Override
public void onSuccess(Integer result)
{
messageLabel.setText(String.valueOf(result));
}
});
}
});
RootPanel.get().add(horzPanel);
The code should now look like this:
package com.giantflyingsaucer.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
public class SimpleRPCEntry implements EntryPoint
{
private final SimpleServiceAsync simpleService = GWT.create(SimpleService.class);
@Override
public void onModuleLoad()
{
final HorizontalPanel horzPanel = new HorizontalPanel();
final Button submitButton = new Button("Submit");
final TextBox number1Textbox = new TextBox();
final TextBox number2Textbox = new TextBox();
final Label messageLabel = new Label();
final Label additionLabel = new Label("+");
horzPanel.add(number1Textbox);
horzPanel.add(additionLabel);
horzPanel.add(number2Textbox);
horzPanel.add(submitButton);
horzPanel.add(messageLabel);
submitButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event)
{
simpleService.handleSimpleRequest(Integer.parseInt(number1Textbox.getText()), Integer.parseInt(number2Textbox.getText()), new AsyncCallback<integer>() {
@Override
public void onFailure(Throwable caught)
{
messageLabel.setText(caught.getMessage());
}
@Override
public void onSuccess(Integer result)
{
messageLabel.setText(String.valueOf(result));
}
});
}
});
RootPanel.get().add(horzPanel);
}
}
Before we run this project there are a few more things we need to do. First, we need to add the rest of the code to the “SimpleServiceImpl.java” file so that our numbers are computed. One line of code is all we need to accomplish that:
return num1 + num2;
So the “SimpleServiceImpl.java” looks like this:
package com.giantflyingsaucer.server;
import com.giantflyingsaucer.client.SimpleService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
@SuppressWarnings("serial")
public class SimpleServiceImpl extends RemoteServiceServlet implements SimpleService
{
@Override
public int handleSimpleRequest(int num1, int num2) throws IllegalArgumentException
{
return num1 + num2;
}
}
Second, go into the “SimpleRPC.html” file and remove everything between the “noscript” and ending “body” tag.
<!doctype html>
<!-- The DOCTYPE declaration above will set the -->
<!-- browser's rendering engine into -->
<!-- "Standards Mode". Replacing this declaration -->
<!-- with a "Quirks Mode" doctype may lead to some -->
<!-- differences in layout. -->
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!-- -->
<!-- Consider inlining CSS to reduce the number of requested files -->
<!-- -->
<link type="text/css" rel="stylesheet" href="SimpleRPC.css">
<!-- -->
<!-- Any title is fine -->
<!-- -->
<title>Web Application Starter Project</title>
<!-- -->
<!-- This script loads your compiled module. -->
<!-- If you add any GWT meta tags, they must -->
<!-- be added before this line. -->
<!-- -->
<script type="text/javascript" language="javascript" src="simplerpc/simplerpc.nocache.js"></script>
</head>
<!-- -->
<!-- The body can have arbitrary html, or -->
<!-- you can leave the body empty if you want -->
<!-- to create a completely dynamic UI. -->
<!-- -->
<body>
<!-- OPTIONAL: include this if you want history support -->
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
<!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
<noscript>
<div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
Your web browser must have JavaScript enabled
in order for this application to display correctly.
</div>
</noscript>
</body>
</html>
Go into the “SimpleRPC.gwt.xml” file and make sure the following line is changed from this:
<entry-point class="com.giantflyingsaucer.client.SimpleRPC"></entry-point>
…and points to the new entry point class:
<entry-point class="com.giantflyingsaucer.client.SimpleRPCEntry"></entry-point>
Make sure there are not two entry points in that file.
The final thing we have to do is to modify the “web.xml” file inside the “war/WEB-INF” folder. The following needs to be added:
<servlet> <servlet-name>simpleServlet</servlet-name> <servlet-class>com.giantflyingsaucer.server.SimpleServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>simpleServlet</servlet-name> <url-pattern>/simplerpc/simpleservice</url-pattern> </servlet-mapping>
The web.xml file should look like this now:
<?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>
<!-- Servlets -->
<servlet>
<servlet-name>greetServlet</servlet-name>
<servlet-class>com.giantflyingsaucer.server.GreetingServiceImpl</servlet-class>
</servlet>
<servlet>
<servlet-name>simpleServlet</servlet-name>
<servlet-class>com.giantflyingsaucer.server.SimpleServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>greetServlet</servlet-name>
<url-pattern>/simplerpc/greet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>simpleServlet</servlet-name>
<url-pattern>/simplerpc/simpleservice</url-pattern>
</servlet-mapping>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>SimpleRPC.html</welcome-file>
</welcome-file-list>
</web-app>
Compile the project just to eliminate any errors.
Assuming everything went well go ahead and run the web app. Enter a number in each of the textboxes and press the submit button. Nothing fancy but it does show how easy RPC is with GWT. Keep in mind we didn’t add ANY code to check the validity of what is typed into those textboxes so you can easily crash this app if you so choose.
If your using Chrome then you can open up the developers tools and inspect what went across the wire and came back.
Here are the SimpleRPC source files in case you need them.
I hope you enjoyed working with GWT 2.0.



















Pingback: Snart är takskottandet över! | Mina dagliga bestyr
Someone sent me this demo on my GWT Sushi Demo blog so I have followed it and included it in my demo library for GWT. See the post here for more details and thanks for posting this information.
http://gwtsushi.blogspot.com/2010/03/sample-7-learning-gwt-20-and-rpc.html
I have not seen such a nice and Explanatory tutrial.
Great job I Appreciate it.
Thanks, couldn’t have linked GWT and GData API’s without this.
Very easy to follow, thank you!
Awesome tutorial. Thank you!!
Very good tutorial. I’ve used GWT a lot, but am upgrading to the latest version. Was looking for something simple I can use as a prototype.
Thanks a lot.
I believe on the gwt-simple-rpc-81.jpg “create interface dialog” image you meant for it to be named SimpleServiceAsync (it says SimpleService again).
I had a little trouble getting this running until I realized all the references to should be capitalized, so .
Also comment #7 is right, in your example you create the same interface class twice, when of course the second one should be named Async.
Thanks for helping a Java noob like me get started
I followed the above code
gtg the following error
Compiling module com.giantflyingsaucer.SimpleRPC
Validating newly compiled units
[ERROR] Errors in ‘file:/C:/Users/Mantra/workspace/simpleRPC/src/com/giantflyingsaucer/client/SimpleRPCEntry.java’
[ERROR] Line 37: The type new AsyncCallback(){} must implement the inherited abstract method AsyncCallback.onSuccess(integer)
[ERROR] Line 37: integer cannot be resolved to a type
[ERROR] Line 45: The method onSuccess(Integer) of type new AsyncCallback(){} must override or implement a supertype method
Finding entry point classes
[ERROR] Unable to find type ‘com.giantflyingsaucer.client.SimpleRPCEntry’
[ERROR] Hint: Previous compiler errors may have made this type unavailable
[ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly
[ERROR] Unable to find type ‘com.giantflyingsaucer.client.SimpleRPCEntry’
[ERROR] Hint: Previous compiler errors may have made this type unavailable
[ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly
Please assist