Beruflich Dokumente
Kultur Dokumente
GOOGLE PROJECT
2008
ThisBookismeantjusttobeaguideforthosewhowishtodevelop applicationsusingGooglesDeveloper.
Contents
Developer's Guide
Getting started Fundamentals User Interfaces Remote Procedure Calls Unit Testing Internationalization JavaScript Native Interface (JSNI) JRE Emulation GWT Class API
Complied By Sivasankar
Getting Started
Installing Google Web Toolkit Building a Sample Application Creating an Application from Scratch (without Eclipse) Creating an Application from Scratch (with Eclipse)
4. Done! Start using Google Web Toolkit. GWT doesn't have an installer application. All the files you need to run and use GWT are located in the extracted directory. The main application you'll need to use GWT is applicationCreator, which is described below. It may be easiest to start out by building one of the sample applications shipped with GWT.
Since you're running in hosted mode, the application is running in the Java Virtual Machine (JVM). This is typically the mode you'll use to debug your applications.
Since you've compiled the project, you're now running pure JavaScript and HTML that should work in IE, Firefox, or Safari. If you were to deploy the Kitchen Sink example project in production, you would distribute the files in your www/com.google.com.google.gwt.sample.kitchensink.KitchenSink/ directory to your web servers.
Change the second string from "<h2>Introduction to the Kitchen Sink.</h2>" to "<h2>Foo bar</h2>":
return new SinkInfo("Intro", "<h2>Foo bar</h2>") {
Now, save the file and simply click "Refresh" in the hosted mode application to see your recent change (if you previously closed hosted mode, go ahead and re-run the KitchenSink-shell script). The header should now say "Foo bar" instead of "Introduction to the Kitchen Sink.":
The applicationCreator script will generate a number of files in src/com/mycompany/, including some basic "Hello, world" functionality in the class src/com/mycompany/client/MyApplication.java. The script also generates a hosted mode launch script called MyApplication-shell and a compilation script called MyApplicationcompile, just like the sample application above. To run your newly created application in hosted mode, run the MyApplication-shell script:
Try editing the files src/com/mycompany/client/MyApplication.java and src/com/mycompany/public/MyApplication.html to see how it changes your application.
Then generate your GWT application as described above, but with an additional -eclipse flag specifying the name of your Eclipse project:
applicationCreator -eclipse MyProject com.mycompany.client.MyApplication
When you're done with these scripts, in addition to the MyApplication-shell and MyApplication-compile scripts, you should see .project, .classpath, and MyApplication.launch files in your current directory. To open your project in Eclipse, launch Eclipse and click the File -> Import menu. Choose "Existing Projects into Workspace" in the first screen of the wizard, and enter the directory in which you genetrated the .project file in the next screen of the wizard. When you are complete, you should see your GWT project loaded into your Eclipse workspace:
Just click the green "Run" button at the top of the window to start your project in hosted mode.
Fundamentals
Core GWT concepts such as compiling Java source into JavaScript, debugging, cross-browser support, and defining modules.
Contents
GWTCompiler o LanguageSupport o RuntimeLibrarySupport CrossbrowserSupport DebugginginHostedMode DeploymentinWebMode HTMLHostPages ClientsideCode ServersideCode ProjectStructure Modules o ModuleXMLFormat o AutomaticResourceInclusion o FilteringPublicPackages CommandlineTools o projectCreator o applicationCreator o junitCreator o i18nCreator o benchmarkViewer
GWT Compiler
TheheartofGWTisacompilerthatconvertsJavasourceintoJavaScript,transformingyourworkingJava applicationintoanequivalentJavaScriptapplication.Generallyspeaking, 1. IfyourGWTapplicationcompilesandrunsinhostedmodeasyouexpect 2. AndGWTcompilesyourapplicationintoJavaScriptoutputwithoutcomplaint, 3. Thenyourapplicationwillworkthesamewayinawebbrowserasitdidinhostedmode. TheGWTcompilersupportsthevastmajorityoftheJavalanguageitself.TheGWTruntimelibrary emulatesarelevantsubsetoftheJavaruntimelibrary.
Language Support
GWTcompilesJavasourcethatiscompatiblewithJ2SE1.4.2orearlier.
Intrinsictypes
byte,char,short,int,long,float,double,Object,String,andarraysaresupported.
Exceptions
try,catch,finallyanduserdefinedexceptionsaresupportedasnormal,although Throwable.getStackTrace()isnotsupportedforwebmode.SeeThrowableforadditional
details.
Some specific areas in which GWT emulation differs from the standard Java runtime:
Cross-browser Support
GWTshieldsyoufromworryingtoomuchaboutcrossbrowserincompatibilities.Ifyousticktobuiltin widgetsandcomposites,yourapplicationswillworksimilarlyonthemostrecentversionsofInternet Explorer,Firefox,andSafari.(Opera,too,mostofthetime.)DHTMLuserinterfacesareremarkably quirky,though,somakesuretotestyourapplicationsthoroughlyoneverybrowser.
Whenever possible, GWT defers to browsers' native user interface elements. For example, GWT's Button widget is a true HTML <button> rather than a synthetic button-like widget built, say, from a <div>. That means that GWT buttons render appropriately in different browsers and
on different client operating systems. We like the native browser controls because they're fast, accessible, and most familiar to users. When it comes to styling web applications, CSS is ideal. So, instead of attempting to encapsulate UI styling behind a wall of least-common-denominator APIs, GWT provides very few methods directly related to style. Rather, developers are encouraged to define styles in stylesheets that are linked to application code using style names. In addition to cleanly separating style from application logic, this division of labor helps applications load and render more quickly, consume less memory, and even makes them easier to tweak during edit/debug cycles since there's no need to recompile for style tweaks.
To launch a hosted mode session, your startup class should be com.google.gwt.dev.GWTShell, found in gwt-dev-windows.jar (or gwt-dev-linux.jar).
Tip Inhostedmode,theGWTdevelopmentshelllooksformodules(andthereforeclientsidesource)using theJVM'sclasspath.Makesuretoaddyoursourcedirectoriesfirstinyourclasspathwhenrunningthe developmentshell.
To create a web mode version of your module, you compile it using either the "Compile/Browse" button available in the hosted browser window or the command-line compiler com.google.gwt.dev.GWTCompiler. Web mode demonstrates what makes GWT unusual: when your application is launched in web mode, it runs completely as JavaScript and does not require any browser plug-ins or JVM.
<!-- Properties can be specified to influence deferred binding --> <meta name='gwt:property' content='locale=en_UK'>
<!-- Stylesheets are optional, but useful --> <link rel="stylesheet" href="Calendar.css">
</head> <body>
<!-- The fully-qualified module name, followed by 'nocache.js' --> <script language="javascript" src="com.example.cal.Calendar.nocache.js"></script>
<!-- Include a history iframe to enable full GWT history support --> <!-- (the id must be exactly as shown) <iframe src="javascript:''" id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe> -->
</body> </html>
ThestructurewasdesignedtomakeiteasytoaddGWTfunctionalitytoexistingwebapplicationswith onlyminorchanges.
Client-side Code
Yourapplicationissentacrossanetworktoauser,whereitrunsasJavaScriptinsidehisorherweb browser.Everythingthathappenswithinyouruser'swebbrowserisreferredtoasclientsideprocessing. Whenyouwriteclientsidecodethatisintendedtoruninthewebbrowser,rememberthatitultimately becomesJavaScript.Thus,itisimportanttouseonlylibrariesandJavalanguageconstructsthatcanbe translated.
Server-side Code
Everythingthathappenswithinyourservercomputerisreferredtoasserversideprocessing.When yourapplicationneedstointeractwithyourserver(forexample,toloadorsavedata),itmakesaclient siderequest(fromthebrowser)acrossthenetworkusingaremoteprocedurecall(RPC).While processinganRPC,yourserverisexecutingserversidecode. Tip GWTdoesn'tmeddlewithyourabilitytorunJavabytecodeonyourserverwhatsoever.Serversidecode doesn'tneedtobetranslatable,soyou'refreetouseanyJavalibraryyoufinduseful.
Project Structure
GWTprojectsareoverlaidontoJavapackagessuchthatmostoftheconfigurationcanbeinferredfrom theclasspathandyourmoduledefinitions.
If you are starting a GWT project from scratch, you should use the standard GWT package layout, which makes it easy to differentiate client-side code from server-side code. For example, suppose your new project is called "Calendar". The standard package layout would look like this:
Package
com/example/cal/
com/example/cal/client/ com/example/cal/server/
com/example/cal/public/
com/example/cal/Calendar.gwt.xml
Inheritsthe
com/example/cal/CalendarApp.gwt.xml com.example.cal.Calenda rmodule(above)andaddsan
entrypointclass
com/example/cal/CalendarTest.gwt.xml
com/example/cal/client/CalendarApp.java
com/example/cal/client/spelling/SpellingService.java
com/example/cal/server/spelling/SpellingServiceImpl.ja implementsthelogicofthe va
spellingservice
com/example/cal/public/Calendar.html
com/example/cal/public/Calendar.css
com/example/cal/public/images/logo.gif
Tip TheeasiestwaytocreateaGWTprojectfromscratchistousetheprojectCreatorscript.
Modules
IndividualunitsofGWTconfigurationareXMLfilescalledmodules.Amodulebundlestogetherallthe configurationsettingsthatyourGWTprojectneeds,namely
Modulesmayappearinanypackageinyourclasspath,althoughitisstronglyrecommendedthatthey appearintherootpackageofastandardprojectlayout.
Entry-Point Classes
AmoduleentrypointisanyclassthatisassignabletoEntryPointandthatcanbeconstructedwithout parameters.Whenamoduleisloaded,everyentrypointclassisinstantiatedandits EntryPoint.onModuleLoad()methodgetscalled.
Source Path
Modulescanspecifywhichsubpackagescontaintranslatablesource,causingthenamedpackageandits subpackagestobeaddedtothesourcepath.Onlyfilesfoundonthesourcepatharecandidatestobe translatedintoJavaScript,makingitpossibletomixclientsideandserversidecodetogetherinthe sameclasspathwithoutconflict.
When module inherit other modules, their source paths are combined so that each module will have access to the translatable source it requires.
Public Path
Modulescanspecifywhichsubpackagesarepublic,causingthenamedpackageanditssubpackagesto beaddedtothepublicpath.WhenyoucompileyourapplicationintoJavaScript,allthefilesthatcanbe foundonyourpublicpatharecopiedtothemodule'soutputdirectory.Theneteffectisthatuservisible URLsneednotincludeafullpackagename.
When module inherit other modules, their public paths are combined so that each module will have access to the static resources it expects.
If you are using the standard project structure, your module XML can be as simple as this:
Loading Modules
ModuleXMLfilesarefoundontheJavaclasspath,referencedbytheirlogicalmodulenamesfromhost pagesandbybeinginheritedbyothermodules.
Modules are always referred to by their logical names. The logical name of a module is of the form pkg1.pkg2.ModuleName (although any number of packages may be present) and includes neither the actual file system path nor the file extension. For example, the logical name of a module XML file located at
~/src/com/example/cal/Calendar.gwt.xml
is
com.example.cal.Calendar
Available Elements
<inheritsname="logicalmodulename"/> Inheritsallthesettingsfromthespecifiedmoduleasifthecontentsoftheinheritedmodule's XMLwerecopiedverbatim.Anynumberofmodulescanbeinheritedinthismanner. <entrypointclass="classname"/> Specifiesanentrypointclass.Anynumberofentrypointclassescanbeadded,includingthose frominheritedmodules. <sourcepath="path"/> AddspackagestothesourcepathbycombiningthepackageinwhichthemoduleXMLisfound withthespecifiedpathtoasubpackage.AnyJavasourcefileappearinginthissubpackageor anyofitssubpackagesisassumedtobetranslatable.
If no <source> element is defined in a module XML file, the client subpackage is implicitly added to the source path as if <source path="client"> had been found in the XML. This default helps keep module XML compact for standard project layouts.
<publicpath="path"/>
If no <public> element is defined in a module XML file, the public subpackage is implicitly added to the public path as if <public path="public"> had been found in the XML. This default helps keep module XML compact for standard project layouts.
<servletpath="urlpath"class="classname"/> ForconvenientRPCtesting,thiselementloadsaservletclassmountedatthespecifiedURL path.TheURLpathshouldbeabsoluteandhavetheformofadirectory(forexample, /spellcheck).YourclientcodethenspecifiesthisURLmappinginacallto ServiceDefTarget.setServiceEntryPoint(String).Anynumberofservletsmaybeloadedinthis manner,includingthosefrominheritedmodules. <scriptsrc="jsurl"/> AutomaticallyinjectstheexternalJavaScriptfilelocatedatthelocationspecifiedbysrc.See automaticresourceinclusionfordetails. <stylesheetsrc="cssurl"/> AutomaticallyinjectstheexternalCSSfilelocatedatthelocationspecifiedbysrc.Seeautomatic resourceinclusionfordetails. <extendpropertyname="clientpropertyname"values="commaseparatedvalues"/> Extendsthesetofvaluesforanexistingclientproperty.Anynumberofvaluesmaybeaddedin thismanner,andclientpropertyvaluesaccumulatethroughinheritedmodules.Youwilllikely onlyfindthisusefulforspecifyinglocalesininternationalization.
<script src="js-url"/>
Thescriptisloadedintothenamespaceofthehostpageasifyouhadincludeditexplicitlyusingthe HTML<script>element.ThescriptwillbeloadedbeforeyouronModuleLoad()iscalled.
Youcanaddanynumberofstylesheetsthisway,andtheorderofinclusionintothepagereflectsthe orderinwhichtheelementsappearinyourmoduleXML.
The <public> element does not support the full FileSet semantics. Only the following attributes and nested elements are currently supported:
Otherattributesandnestedelementsarenotsupported.
Important Thedefaultvalueofdefaultexcludesistrue.Bydefault,thepatternslistedhereareexcluded.
Command-line Tools
GWTcomeswithafewhandycommandlinetoolstogetyouupandrunningquickly.Theyarealso usefulforaddingnewthingstoexistingprojects.Forexample,projectCreatorcouldbeusedtomake anEclipseprojectforoneofthesamplesthatcomeswithGWT.
projectCreator
GeneratesanAntbuildfileorEclipseproject.
projectCreator [-ant projectName] [-eclipse projectName] [-out dir] [overwrite] [-ignore]
Ignoreanyexistingfiles;donotoverwrite
Example
~/Foo> projectCreator -ant Foo -eclipse Foo Created directory src Created directory test Created file Foo.ant.xml Created file .project Created file .classpath
Running ant -f Foo.ant.xml will compile src into bin. The buildfile also contains a package target for bundling the project into a jar.
.project can be imported into an Eclipse workspace.
applicationCreator
GeneratesastarterapplicationandscriptsforlaunchinghostedmodeandcompilingtoJavaScript.
applicationCreator [-eclipse projectName] [-out dir] [-overwrite] [-ignore] className -eclipse -out
Createsadebuglaunchconfigurationforthenamedeclipseproject Thedirectorytowriteoutputfilesinto(defaultstocurrent)
Ignoreanyexistingfiles;donotoverwrite
className Thefullyqualifiednameoftheapplicationclasstocreate
Example
~/Foo> applicationCreator -eclipse Foo com.example.foo.client.Foo Created directory src/com/example/foo/client Created directory src/com/example/foo/public Created file src/com/example/foo/Foo.gwt.xml Created file src/com/example/foo/public/Foo.html Created file src/com/example/foo/client/Foo.java Created file Foo.launch Created file Foo-shell Created file Foo-compile
RunningFoo-shellbringsupthenewappinhostedmode.Foo-compiletranslatestheJavaappto JavaScript,creatingawebfolderunderwww.Foo.launchisalaunchconfigurationforEclipse.
junitCreator
GeneratesaJUnittestandscriptsfortestinginbothhostedmodeandwebmode.
junitCreator -junit pathToJUnitJar [-eclipse projectName] [-out dir] [overwrite] [-ignore] className -junit
Specifythepathtoyourjunit.jar(required)
Ignoreanyexistingfiles;donotoverwrite
className Thefullyqualifiednameofthetestclasstocreate
Example
~/Foo> junitCreator -junit /opt/eclipse/plugins/org.junit_3.8.1/junit.jar -module com.example.foo.Foo -eclipse Foo com.example.foo.client.FooTest Created directory test/com/example/foo/test Created file test/com/example/foo/client/FooTest.java Created file FooTest-hosted.launch Created file FooTest-web.launch Created file FooTest-hosted Created file FooTest-web
RunningFooTest-hostedtestsasJavabytecodeinaJVM.FooTest-webtestsascompiledJavaScript. ThelaunchconfigurationsdothesamethinginEclipse.
i18nCreator
Generatesinternationalizationscriptsforstaticinternationalization,alongwithsamplepropertiesfiles.
i18nCreator [-eclipse projectName] [-out dir] [-overwrite] [-ignore] [createMessages] interfaceName -eclipse -out -overwrite
-ignore
Ignoreanyexistingfiles;donotoverwrite
Thefullyqualifiednameoftheinterfacetocreate
Example
~/Foo> i18nCreator -eclipse Foo -createMessages com.example.foo.client.FooMessages Created file src/com/example/foo/client/FooMessages.properties Created file FooMessages-i18n.launch Created file FooMessages-i18n
~/Foo> i18nCreator -eclipse Foo com.example.foo.client.FooConstants Created file src/com/example/foo/client/FooConstants.properties Created file FooConstants-i18n.launch Created file FooConstants-i18n
Running FooMessages-i18n will generate an interface from FooMessages.properties that extends Messages (The messages will take parameters, substituting {n} with the nth parameter). Running FooConstants-i18n will generate an interface from FooConstants.properties that extends Constants (The constants will not take parameters).
Thelaunchconfigurationsdothesamethingasthescripts,fromwithinEclipse.
benchmarkViewer
Readsbenchmarkreportsfromafolderanddisplaystheirresults,includingvariousvisualizations.
benchmarkViewer [path]
path
SpecifythepathtotheXMLbenchmarkreports.Ifthepathisnotspecified, itdefaultstothecurrentworkingdirectory.
Example
~/Foo> benchmarkViewer my/benchmark/results
LooksforreportXMLfilesinthefoldermy/benchmark/resultsanddisplaysthemintheviewer.
Contents
Overview Widgets and Panels Widgets Gallery Events and Listeners Creating Custom Widgets Understanding Layout Style Sheets Image Bundles o Creating and Using an Image Bundle o Image Bundles and Localization
Overview
GWT user interface classes are similar to those in existing UI frameworks such as Swing and SWT except that the widgets are rendered using dynamically-created HTML rather than pixeloriented graphics. While it is possible to manipulate the browser's DOM directly using the DOM interface, it is far easier to use classes from the Widget hierarchy. You should rarely, if ever, need to access the DOM directly. Using widgets makes it much easier to quickly build interfaces that will work correctly on all browsers.
Widgets and panels work the same way on all browsers; by using them, you eliminate the need to write specialized code for each browser. But you are not limited to the set of widgets provided by the toolkit. There are a number of ways to create custom widgets yourself.
Panels
Panels, such as DockPanel, HorizontalPanel, and RootPanel, contain widgets and are used to define how they are laid out in the browser.
Styles
Visual styles are applied to widgets using Cascading Style Sheets (CSS). This section describes in detail how to use this feature.
Widgets Gallery
The following are widgets and panels available in the GWT user-interface library. Button RadioButton
PushButton
ToggleButton
CheckBox
TextBox
PasswordTextBox
TextArea
Hyperlink
ListBox
MenuBar
Tree
Table
TabBar
DialogBox
PopupPanel
StackPanel
HorizontalPanel
VerticalPanel
FlowPanel
VerticalSplitPanel
HorizontalSplitPanel
DockPanel
TabPanel
RichTextArea
DisclosurePanel
SuggestBox
wishing to receive events of a particular type implements the associated listener interface and then passes a reference to itself to the widget to "subscribe" to a set of events. The Button class, for example, publishes click events. The associated listener interface is ClickListener.
public void anonClickListenerExample() { Button b = new Button("Click Me"); b.addClickListener(new ClickListener() { public void onClick(Widget sender) { // handle the click event } }); }
Using anonymous inner classes as in the above example can be inefficient for a large number of widgets, since it could result in the creation of many listener objects. Widgets supply their this pointer as the sender parameter when they invoke a listener method, allowing a single listener to distinguish between multiple event publishers. This makes better use of memory but requires slightly more code, as shown in the following example:
public class ListenerExample extends Composite implements ClickListener { private FlowPanel fp = new FlowPanel(); private Button b1 = new Button("Button 1"); private Button b2 = new Button("Button 2");
public void onClick(Widget sender) { if (sender == b1) { // handle b1 being clicked } else if (sender == b2) { // handle b2 being clicked
} } }
Some event interfaces specify more than one event. If you are only interested in a subset of these events, subclass one of the event "adapters". Adapters are simply empty concrete implementations of a particular event interface, from which you can derive a listener class without having to implement every method.
public void adapterExample() { TextBox t = new TextBox(); t.addKeyboardListener(new KeyboardListenerAdapter() { public void onKeyPress(Widget sender, char keyCode, int modifiers) { // handle only this one event } }); }
Composites
Composites are by far the most effective way to create new widgets. You can easily combine groups of existing widgets into a composite that is itself a reusable widget. Composite is a specialized widget that can contain another component (typically, a panel) but behaves as if it were its contained widget. Using Composite is preferable to attempting to create complex widgets by subclassing Panel because a composite usually wants to control which methods are publicly accessible without exposing those methods that it would inherit from its panel superclass. This is an example of how to create a composite.
Using JavaScript
When implementing a custom widget that derives directly from the Widget base class, you may also write some of the widget's methods using JavaScript. This should generally be done only as a last resort, as it becomes necessary to consider the cross-browser implications of the native methods that you write, and also becomes more difficult to debug. For an example of this pattern in practice, see the TextBox widget and its underlying implementation.
Understanding Layout
Panels in GWT are much like their counterparts in other user interface libraries. The main difference lies in the fact that they use HTML elements such as DIV and TABLE to layout their child widgets.
RootPanel
The first panel you're likely to encounter is the RootPanel. This panel is always at the top of the containment hierarchy. The default RootPanel wraps the HTML document's body, and is obtained by calling RootPanel.get(). If you need to get a root panel wrapping another element in the HTML document, you can do so using RootPanel.get(String).
CellPanel
CellPanel is the abstract base class for DockPanel, HorizontalPanel, and VerticalPanel. What these panels all have in common is that they position their child widgets within logical "cells". Thus, a child widget can be aligned within the cell that contains it, using setCellHorizontalAlignment() and setCellVerticalAlignment(). CellPanels also allow you to set the size of the cells themselves (relative to the panel as a whole) using CellPanel.setCellWidth and CellPanel.setCellHeight.
Other Panels
Other panels include DeckPanel, TabPanel, FlowPanel, HTMLPanel, and StackPanel.
Style Sheets
GWT widgets rely on cascading style sheets (CSS) for visual styling. Each widget has an associated style name that binds it to a CSS rule. A widget's style name is set using
setStyleName(). For example, the Button has a default style of gwt-Button. In order to give all buttons a larger font, you could put the following rule in your application's CSS file:
.gwt-Button { font-size: 150%; }
Complex Styles
Some widgets have somewhat more complex styles associated with them. MenuBar, for example, has the following styles:
.gwt-MenuBar { the menu bar itself } .gwt-MenuBar .gwt-MenuItem { menu items } .gwt-MenuBar .gwt-MenuItem-selected { selected menu items }
In this example, there are two styles rules that apply to menu items. The first applies to all menu items (both selected and unselected), while the second (with the -selected suffix) applies only to selected menu items. A selected menu item's style name will be set to "gwt-MenuItem gwtMenuItem-selected", specifying that both style rules will be applied. The most common way of doing this is to use setStyleName to set the base style name, then addStyleName() and removeStyleName() to add and remove the second style name.
CSS Files
Typically, stylesheets are placed in a package that is part of your module's public path. Then simply include a reference to the stylesheet in your host page, such as
<link rel="stylesheet" href="mystyles.css" type="text/css">
Documentation
It is standard practice to document the relevant CSS style names for each widget class as part of its doc comment. For a simple example, see Button. For a more complex example, see MenuBar.
Image Bundles
Typically, an application uses many small images for icons. An HTTP request has to be sent to the server for each of these images, and in some cases, the size of the image is smaller than the HTTP response header that is sent back with the image data. These round trips to the server for small pieces of data are wasteful. Even when the images have been cached by the client, a 304 ("Not Modified") request is still sent to check and see if the image has changed. Since images change infrequently, these freshness checks are also wasteful. Sending out requests and freshness checks for many images will slow down your application. HTTP 1.1 requires browsers to limit the number of outgoing HTTP connections to two per domain/port. A multitude of image requests will tie up the browser's available connections,
which blocks the application's RPC requests. RPC requests are the real work that the application needs to do. To solve this problem, GWT introduces the concept of an image bundle. An image bundle is a composition of many images into a single image, along with an interface for accessing the individual images from within the composite. Users can define an image bundle that contains the images used by their application, and GWT will automatically create the composite image and provide an implementation of the interface for accessing each individual image. Instead of a round trip to the server for each image, only one round trip to the server for the composite image is needed. Since the filename of the composite image is based on a hash of the file's contents, the filename will change only if the composite image is changed. This means that it is safe for clients to cache the composite image permanently, which avoids the unnecessary freshness checks for unchanged images. To make this work, the server configuration needs to specify that composite images never expire. In addition to speeding up startup, image bundles prevent the 'bouncy' effect of image loading in browsers. While images are loading, browsers put a standard placeholder for each image in the UI. The placeholder is a standard size because the browser does not know what the size of an image is until it has been fully downloaded from the server. The result is a 'bouncy' effect, where images 'pop' into the UI once they are downloaded. With image bundles, the size of each individual image within the bundle is discovered when the bundle is created, so the size of the image can be explicitly set whenever images from a bundle are used in an application. Tip Check out the ImageBundle documentation for important information regarding: A potential security issue with the generation of the composite image on certain versions of the JVM Caching recommendations for image bundle files Protecting image bundle files with web application security constraints Using image bundles with the HTTPS protocol
takes no parameters, has a return type of AbstractImagePrototype, and may have an optional gwt.resource metadata tag which specifies the name of the image file in the module's classpath
Valid image file types are png, gif, and jpg. If the image name contains '/' characters, it is assumed to be the name of a resource on the classpath, formatted as would be expected by
package as the user-defined image bundle. If the gwt.resource metadata tag is not specified, then
the image filename is assumed to match the method name, the extension is assumed to be either .png, .gif, or .jpg, and the file is assumed to be in the same package as the derived interface
In the event that there are multiple image files with different extensions, the order of extension precedence is (1) png, (2) gif, then (3) jpg. An image bundle for icons in a word processor application could be defined as follows:
public interface WordProcessorImageBundle extends ImageBundle {
/** * Would match the file 'new_file_icon.png', 'new_file_icon.gif', or * 'new_file_icon.png' located in the same package as this type. */ public AbstractImagePrototype new_file_icon();
/** * Would match the file 'open_file_icon.gif' located in the same * package as this type. * * @gwt.resource open_file_icon.gif */ public AbstractImagePrototype openFileIcon();
/** * Would match the file 'savefile.gif' located in the package * 'com.mycompany.mygwtapp.icons', provided that this package is part * of the module's classpath. * * @gwt.resource com/mycompany/mygwtapp/icons/savefile.gif */ public AbstractImagePrototype saveFileIcon();
Methods in an image bundle return AbstractImagePrototype objects (rather than Image objects, as you might have expected) because AbstractImagePrototype objects provide additional lightweight representations of an image. For example, the AbstractImagePrototype.getHTML() method provides an HTML fragment representing an image without having to create an actual instance of the Image widget. In some cases, it can be more efficient to manage images using these HTML fragments. Another use of AbstractImagePrototype is to use AbstractImagePrototype.applyTo(Image) to transform an existing Image into one that matches the prototype without having to instantiate another Image object. This can be useful if your application has an image that needs to be swapped depending on some user-initiated action. Of course, if an Image is exactly what you need, the AbstractImagePrototype.createImage() method can be used to generate new Image instances. The following example shows how to use the image bundle that we just defined in your application:
public void useImageBundle() { WordProcessorImageBundle wpImageBundle = (WordProcessorImageBundle) GWT.create(WordProcessorImageBundle.class); HorizontalPanel tbPanel = new HorizontalPanel(); tbPanel.add(wpImageBundle.new_file_icon().createImage()); tbPanel.add(wpImageBundle.openFileIcon().createImage()); tbPanel.add(wpImageBundle.saveFileIcon().createImage()); }
Tip Image bundles are immutable, so you can keep a reference to a singleton instance of an image bundle instead of creating a new instance every time the image bundle is needed.
/** * The default 'Compose New Message' icon if no locale-specific * image is specified. * * @gwt.resource compose_new_message_icon.gif */ public AbstractImagePrototype composeNewMessageIcon();
/** * The default 'Help' icon if no locale-specific image is specified. * Will match 'help_icon.png', 'help_icon.gif', or 'help_icon.jpg' in * the same package as this type. */ public AbstractImagePrototype help_icon(); }
Suppose the application has to handle both English and French users. We define English and French variations of each image in MailImageBundle by creating locale-specific image bundles that extend MailImageBundle:
public interface MailImageBundle_en extends MailImageBundle {
/** * The English version of the 'Compose New Message' icon. * Since we are not overriding the help_icon() method, this bundle * uses the inherited method from MailImageBundle. * * @gwt.resource compose_new_message_icon_en.gif */ public AbstractImagePrototype composeNewMessageIcon(); } public interface MailImageBundle_fr extends MailImageBundle {
/** * The French version of the 'Compose New Message' icon. * * @gwt.resource compose_new_message_icon_fr.gif
/** * The French version of the 'Help' icon. * * @gwt.resource help_icon_fr.gif */ public AbstractImagePrototype help_icon(); }
The final step is to create a mechanism for choosing the correct image bundle based on the user's locale. By extending Localizable, we can create a locale-sensitive factory that will return new instances of MailImageBundle that match the factory's locale:
public interface MailImageBundleFactory extends Localizable {
public MailImageBundle createImageBundle() { return (MailImageBundle) GWT.create(MailImageBundle_en.class); } } public class MailImageBundleFactory_fr implements MailImageBundleFactory {
The application code that utilizes a locale-sensitive image bundle would look something like this:
public void useLocalizedImageBundle() { // Create a locale-sensitive MailImageBundleFactory MailImageBundleFactory mailImageBundleFactory = (MailImageBundleFactory) GWT .create(MailImageBundleFactory.class);
// This will return a locale-sensitive MailImageBundle, since we are using // a locale-sensitive factory to create it. MailImageBundle mailImageBundle = mailImageBundleFactory.createImageBundle();
// Get the image prototype for the icon that we are interested in. AbstractImagePrototype helpIconProto = mailImageBundle.help_icon();
// Create an Image object from the prototype and add it to a panel. HorizontalPanel panel = new HorizontalPanel(); panel.add(helpIconProto.createImage()); }
1. Docs> 2. RemoteProcedureCalls
Contents
Overview
AfundamentaldifferencebetweenGWTapplicationsandtraditionalHTMLwebapplicationsisthatGWT applicationsdonotneedtofetchnewHTMLpageswhiletheyexecute.BecauseGWTenhancedpages actuallyrunmorelikeapplicationswithinthebrowser,thereisnoneedtorequestnewHTMLfromthe servertomakeuserinterfaceupdates.However,likeallclient/serverapplications,GWTapplications
When used properly, RPCs give you the opportunity to move all of your UI logic to the client, resulting in greatly improved performance, reduced bandwidth, reduced web server load, and a pleasantly fluid user experience. The server-side code that gets invoked from the client is often referred to as a service, so the act of making a remote procedure call is sometimes referred to as invoking a service. To be clear, though, the term service in this context isn't the same as the more general "web service" concept. In particular, GWT services are not related to the Simple Object Access Protocol (SOAP).
Creating Services
Todevelopanewserviceinterface,beginbycreatingaclientsideJavainterfacethatextendsthe RemoteServicetaginterface.
public interface MyService extends RemoteService { public String myMethod(String s); }
public String myMethod(String s) { // Do something interesting with 's' here on the server. return s;
Asynchronous Interfaces
Beforeyoucanactuallyattempttomakearemotecallfromtheclient,youmustcreateanother interface,anasynchronousone,basedonyouroriginalserviceinterface.Continuingwiththeexample above...
interface MyServiceAsync { public void myMethod(String s, AsyncCallback callback); }
The nature of asynchronous method calls requires the caller to pass in a callback object that can be notified when an asynchronous call completes, since by definition the caller cannot be blocked until the call completes. For the same reason, asynchronous methods do not have return types; they must always return void. After an asynchronous call is made, all communication back to the caller is via the passed-in callback object.
Therelationshipbetweenaserviceinterfaceanditsasynchronouscounterpartisstraightforward:
anasynchronoussiblingmethodshouldbedefinedthatlookslikethis:
public void methodName(ParamType1 param1, ParamType2 param2, AsyncCallback callback);
SeeAsyncCallbackforadditionaldetailsonhowtoimplementanasynchronouscallback.
Implementing Services
Everyserviceultimatelyneedstoperformsomeprocessingtoordertorespondtoclientrequests.Such serversideprocessingoccursintheserviceimplementation,whichisbasedonthewellknownservlet architecture.
A service implementation must extend RemoteServiceServlet and must implement the associated service interface. Note that the service implementation does not implement the asynchronous version of the service interface. Every service implementation is ultimately a servlet, but rather than extending HttpServlet, it extends RemoteServiceServlet instead. RemoteServiceServlet automatically handles serialization and invoking the intended method in your service implementation.
Example
Supposeyouwanttocallamethodonaserviceinterfacedefinedasfollows:
public interface MyEmailService extends RemoteService { void emptyMyInbox(String username, String password); }
Itscorrespondingasynchronousinterfacewilllooklikethis:
public interface MyEmailServiceAsync { void emptyMyInbox(String username, String password, AsyncCallback callback);
Theclientsidecallwilllooklikethis:
public void menuCommandEmptyInbox() { // (1) Create the client proxy. Note that although you are creating the // service interface proper, you cast the result to the asynchronous // version of // the interface. The cast is always safe because the generated proxy // implements the asynchronous interface automatically. // MyEmailServiceAsync emailService = (MyEmailServiceAsync) GWT.create(MyEmailService.class);
// (2) Specify the URL at which our service implementation is running. // Note that the target URL must reside on the same domain and port from // which the host page was served. // ServiceDefTarget endpoint = (ServiceDefTarget) emailService; String moduleRelativeURL = GWT.getModuleBaseURL() + "email"; endpoint.setServiceEntryPoint(moduleRelativeURL);
// (3) Create an asynchronous callback to handle the result. // AsyncCallback callback = new AsyncCallback() { public void onSuccess(Object result) { // do some UI stuff to show success }
// (4) Make the call. Control flow will continue immediately and later // 'callback' will be invoked when the RPC completes.
Itissafetocachetheinstantiatedserviceproxytoavoidcreatingitforsubsequentcalls.
Serializable Types
Methodparametersandreturntypesmustbeserializable,whichmeanstheymustconformtocertain restrictions.GWTtriesreallyhardtomakeserializationaspainlessaspossible,sowhiletherules regardingserializationaresubtle,inpracticethebehaviorbecomesintuitiveveryquickly.
Polymorphism
GWTRPCsupportspolymorphicparametersandreturntypes.Tomakethebestuseofpolymorphism, however,youshouldstilltrytobeasspecificasyourdesignallowswhendefiningserviceinterfaces. Increasedspecificityallowsthecompilertodoabetterjobofremovingunnecessarycodewhenit optimizesyourapplicationforsizereduction.
Type Arguments
/** * This field is a Map that must always contain Strings as its keys and * values. * * @gwt.typeArgs <java.lang.String,java.lang.String> */ public Map mapOfStringToString;
/** * Default Constructor. The Default Constructor's explicit declaration * is required for a serializable class. */ public MyClass() { } }
Notethatthereisnoneedtospecifythenameofthefieldinthe@gwt.typeArgsdeclarationsinceit canbeinferred.
public interface MyService extends RemoteService { /** * The first annotation indicates that the parameter named 'c' is a List * that will only contain Integer objects. The second annotation * indicates that the returned List will only contain String objects * (notice there is no need for a name, since it is a return value). * * @gwt.typeArgs c <java.lang.Integer> * @gwt.typeArgs <java.lang.String> */ List reverseListAndConvertToStrings(List c); }
Handling Exceptions
MakingRPCsopensupthepossibilityofavarietyoferrors.Networksfail,serverscrash,andproblems occurwhileprocessingaservercall.GWTletsyouhandletheseconditionsintermsofJavaexceptions. RPCrelatedexceptionsfallintotwocategories.
Checked Exceptions
Serviceinterfacemethodssupportthrowsdeclarationstoindicatewhichexceptionsmaybethrown backtotheclientfromaserviceimplementation.Callersshouldimplement AsyncCallback.onFailure(Throwable)tocheckforanyexceptionsspecifiedintheserviceinterface.
Unexpected Exceptions
InvocationException AnRPCmaynotreachtheserviceimplementationatall.Thiscanhappenformanyreasons:thenetwork maybedisconnected,aDNSservermightnotbeavailable,theHTTPservermightnotbelistening,and soon.Inthiscase,anInvocationExceptionispassedtoyourimplementationof
AsyncCallback.onFailure(Throwable).TheclassiscalledInvocationExceptionbecausetheproblem waswiththeinvocationattemptitselfratherthanwiththeserviceimplementationitself.
An RPC can also fail with an invocation exception if the call does reach the server, but an undeclared exception occurs during normal processing of the call. There are many reasons such a situation could arise: a necessary server resource, such as a database, might be unavailable, a NullPointerException could be thrown due to a bug in the service implementation, and so on. In these cases, a InvocationException is thrown in application code.
IncompatibleRemoteServiceException
Another type of failure can be caused by an incompatibility between the client and the server. This most commonly occurs when a change to a service implementation is deployed to a server but out-of-date clients are still active. For more details please see IncompatibleRemoteServiceException. When the client code receives an IncompatibleRemoteServiceException, it should ultimately attempt to refresh the browser in order to pick up the latest client.
For example, suppose your application displays a large table containing many widgets. Constructing and laying out all those widgets can be time consuming. At the same time, you need to fetch data from the server to display inside the table. This is a perfect reason to use asynchronous calls. Initiate an asynchronous call to request the data immediately before you begin constructing your table and its widgets. While the server is fetching the required data, the browser is executing your user interface code. When the client finally receives the data from the server, the table has been constructed and laid out, and the data is ready to be displayed. To give you an idea of how effective this technique can be, suppose that building the table takes 1 second and fetching the data takes 1 second. If you make the server call synchronously, the whole process will require at least 2 seconds. But if you fetch the data asynchronously, the whole process still takes just 1 second, even though you are doing 2 seconds' worth of work. The hardest thing to get used to about asynchronous calls is that the calls are non-blocking. However, Java inner classes go a long way toward making this manageable.
Tip TheAsyncCallbackinterfaceisthekeyinterfaceyou'llextendtohandleRPCresponses.
Architectural Perspectives
Therearevariouswaystoapproachserviceswithinyourapplicationarchitecture.Understandfirstofall thatGWTservicesarenotintendedtoreplaceJ2EEservers,noraretheyintendedtoprovideapublic webservices(e.g.SOAP)layerforyourapplication.GWTRPCs,fundamentally,aresimplyamethodof "gettingfromtheclienttotheserver."Inotherwords,youuseRPCstoaccomplishtasksthatarepartof yourapplicationbutthatcannotbedoneontheclientcomputer.
Architecturally, you can make use of RPC two alternative ways. The difference is a matter of taste and of the architectural needs of your application. The first and most straightforward way to think of service definitions is to treat them as your application's entire back end. From this perspective, client-side code is your "front end" and all service code that runs on the server is "back end." If you take this approach, your service implementations would tend to be more general-purpose APIs that are not tightly coupled to one specific application. Your service definitions would likely directly access databases through JDBC or Hibernate or even files in the server's file system. For many applications, this view is appropriate, and it can be very efficient because it reduces the number of tiers. In more complex, multi-tiered architectures, your GWT service definitions could simply be lightweight gateways that call through to back-end server environments such as J2EE servers. From this perspective, your services can be viewed of as the "server half" of your application's user interface. Instead of being general-purpose, services are created for the specific needs of your user interface. Your services become the "front end" to the "back end" classes that are written by stitching together calls to a more general-purpose back-end layer of services, implemented, for example, as a cluster of J2EE servers. This kind of architecture is appropriate if you require your back-end services to run on a physically separate computer from your HTTP server.
1. Docs> 2. UnitTesting
JUnit Integration
Integration with JUnit lets you test your AJAX code almost as easily as any other Java code.
Contents
Overview
GWTincludesaspecialGWTTestCasebaseclassthatprovidesJUnitintegration.Runningacompiled GWTTestCasesubclassunderJUnitlaunchesaninvisibleGWTbrowser.
By default, tests run in hosted mode as normal Java bytecode in a JVM. Overriding this default behavior requires passing arguments to the GWT shell. Arguments cannot be passed directly through the command line, because normal command-line arguments go directly to the JUnit runner. Instead, define the system property gwt.args to pass arguments to GWT. For example, to run in web mode, declare -Dgwt.args="-web" as a JVM argument when invoking JUnit. To get a full list of supported options, declare -Dgwt.args="-help" (instead of running the test, help is printed to the console).
Example
Writethecom.example.foo.client.FooTesttestcase.
public class FooTest extends GWTTestCase {
/* * Specifies a module to use when running this test case. The returned * module must cause the source for this class to be included. * * @see com.google.gwt.junit.client.GWTTestCase#getModuleName()
Createthecom.example.foo.Foomodule.
<!--> <!-- Copyright 2007 Google Inc. -> <!-- Licensed under the Apache License, Version 2.0 (the "License"); you -> <!-- may not use this file except in compliance with the License. You may -> <!-- may obtain a copy of the License at -> <!--> <!-- http://www.apache.org/licenses/LICENSE-2.0 -> <!--> <!-- Unless required by applicable law or agreed to in writing, software -> <!-- distributed under the License is distributed on an "AS IS" BASIS, -> <!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -> <!-- implied. License for the specific language governing permissions and -> <!-- limitations under the License. -> -
-->
-->
<!-- It's okay for your module to declare an entry point. <!-- This gets ignored when running under JUnit. <entry-point class='com.example.foo.FooModule'/>
--> -->
<!-- You can also test remote services during a JUnit run.
-->
Asynchronous Testing
GWT'sJUnitintegrationprovidesspecialsupportfortestingfunctionalitythatcannotexecuteinstraight linecode.Forexample,youmightwanttomakeanRPCcalltoaserverandthenvalidatetheresponse. However,inanormalJUnittestrun,theteststopsassoonasthetestmethodreturnscontroltothe caller,andGWTdoesnotsupportmultiplethreadsorblocking.Tosupportthisusecase,GWTTestCase hasextendedtheTestCaseAPI.
The two key methods are GWTTestCase.delayTestFinish(int) and GWTTestCase.finishTest(). Calling delayTestFinish() during a test method's execution puts that test in asynchronous mode, which means the test will not finish when the test method returns control to the caller. Instead, a delay period begins, which lasts the amount of time specified in the call to delayTestFinish(). During the delay period, the test system will wait for one of three things to happen:
1. IffinishTest()iscalledbeforethedelayperiodexpires,thetestwillsucceed. 2. Ifanyexceptionescapesfromaneventhandlerduringthedelayperiod,thetestwillerrorwith thethrownexception.
3. Ifthedelayperiodexpiresandneitheroftheabovehashappened,thetestwillerrorwitha TimeoutException.
The normal use pattern is to setup an event in the test method and call delayTestFinish() with a timeout significantly longer than the event is expected to take. The event handler validates the event and then calls finishTest().
Example
public void testTimer() { // Setup an asynchronous event handler. Timer timer = new Timer() { public void run() { // do some validation logic
// Set a delay period significantly longer than the // event is expected to take. delayTestFinish(500);
// Schedule the event and return control to the test system. timer.schedule(100); }
Benchmarking
GWT'sJUnitintegrationprovidesspecialsupportforcreatingandreportingonbenchmarks.Specifically, GWThasintroducedanewBenchmarkclasswhichprovidesbuiltinfacilitiesforcommonbenchmarking needs.Totakeadvantageofbenchmarkingsupport,takethefollowingsteps: 1. ReviewthedocumentationonBenchmark.Takealookattheexamplebenchmarkcode. 2. CreateyourownbenchmarkbysubclassingBenchmark.Executeyourbenchmarklikeyouwould anynormalJUnittest.Bydefault,thetestresultsarewrittentoareportXMLfileinyourworking directory. 3. RunbenchmarkViewertobrowsevisualizations(graphs/charts)ofyourreportdata.The benchmarkViewerisaGWTtoolintherootofyourGWTinstallationdirectorythatdisplays benchmarkreports.
Internationalization
Easily support multiple locales with a single code base.
Contents
Overview Static String Internationalization Dynamic String Internationalization Specifying a Locale Localized Properties Files
Overview
GWT includes a flexible set of tools to help you internationalize your applications and libraries. GWT internationalization support provides a variety of techniques to internationalize strings, typed values, and classes.
Getting Started
Since GWT supports a variety of ways of internationalizing your code, begin by researching which approach best matches your development requirements. Are you writing code from scratch? If so, you'll probably want to read up on GWT's static string internationalization techniques. Do you want to internationalize mostly settings or end-user messages? If you have mostly settings (the kind of thing for which you'd normally use simple properties
files), consider Constants. If you have a lot a of end-user messages, then Messages is probably what you want. Do you have existing localized properties files you'd like to reuse? The i18nCreator tool can automatically generate interfaces that extend either Constants or Messages. Are you adding GWT functionality to an existing web application that already has a localization process defined? Dictionary will help you interoperate with existing pages without requiring you to use GWT's concept of locale. Do you really just want a simple way to get properties files down to the client regardless of localization? You can do that, too. Try using Constants without specifying a locale.
Internationalization Techniques
GWT offers multiple internationalization techniques to afford maximum flexibility to GWT developers and to make it possible to design for efficiency, maintainability, flexibility, and interoperability in whichever combinations are most useful. Static string internationalization refers to a family of efficient and type-safe techniques that rely on strongly-typed Java interfaces, properties files, and code generation to provide locale-aware messages and configuration settings. These techniques depend on the interfaces Constants and Messages. At the other end of the spectrum, dynamic string internationalization is a simplistic and flexible technique for looking up localized values defined in a module's host page without needing to recompile your application. This technique is supported by the class Dictionary. Using an approach similar to static string internationalization, GWT also supports internationalizing sets of algorithms using locale-sensitive type substitution. This is an advanced technique that you probably will not need to use directly, although it is useful for implementing complex internationalized libraries. For details on this technique, see Localizable.
Messages
ConstantsWithLookup Like Constants but with extra lookup flexibility for highly data-driven applications
Dictionary Useful when adding a GWT module to existing localized web pages
The GWT internationalization types are included in the module com.google.gwt.i18n.I18N. To use any of these types, your module must inherit from it:
<!--> <!-- Copyright 2007 Google Inc. -> <!-- Licensed under the Apache License, Version 2.0 (the "License"); you -> <!-- may not use this file except in compliance with the License. You may -> <!-- may obtain a copy of the License at -> <!--> <!-- http://www.apache.org/licenses/LICENSE-2.0 -> <!--> <!-- Unless required by applicable law or agreed to in writing, software -> <!-- distributed under the License is distributed on an "AS IS" BASIS, -> <!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -> <!-- implied. License for the specific language governing permissions and -> <!-- limitations under the License. -> -
<module> <!-- other inherited modules, such as com.google.gwt.user.User --> <inherits name="com.google.gwt.i18n.I18N"/> <!-- additional module settings --> </module>
Now create an associated default properties file called MyConstants.properties in the same package:
helloWorld = hello, world goodbyeWorld = goodbye, world
You can also create a localized translation for each supported locale in separate properties file. In this case, we localize for Spanish:
helloWorld = hola, mundo goodbyeWorld = adis, mundo
To use the internationalized constants, you create an implementation of MyConstants using GWT.create(Class):
public void useMyConstants() { MyConstants myConstants = (MyConstants) GWT.create(MyConstants.class); Window.alert(myConstants.helloWorld()); }
way has a number of advantages. The GWT compiler can optimize deeply, removing uncalled methods and inlining localized strings -- making generated code as efficient as if the strings had been hard-coded. The value of compile-time checking becomes even more apparent when applied to messages that take multiple arguments. Creating a Java method for each message allows the compiler to check both the number and types of arguments supplied by the calling code against the message template defined in a properties file. For example, attempting to use this interface:
public interface ErrorMessages extends Messages { String permissionDenied(int errorCode, String username); }
results in a compile-time error because the message template in the properties file expects three arguments, while the permissionDenied method can only supply two.
method to look up strings by property name, which facilitates dynamic binding to constants by name at runtime. ConstantsWithLookup can sometimes be useful in highly data-driven applications. One caveat: ConstantsWithLookup is less efficient than Constants because the compiler cannot discard unused constant methods, resulting in larger applications. Extend Messages to create a collection of formatted messages that can accept parameters. You might think of the Messages interface as a statically verifiable equivalent of the traditional Java combination of Properties, ResourceBundle, and MessageFormat rolled into a single mechanism.
Properties Files
All of the types above use properties files based on the traditional Java properties file format, although GWT uses an enhanced properties file format that are encoded as UTF-8 and can therefore contain Unicode characters directly.
Specifying a Locale
GWT represents locale as a client property whose value can be set either using a meta tag embedded in the host page or in the query string of the host page's URL. Rather than being supplied by GWT, the set of possible values for the locale client property is entirely a function of your module configuration. If that sounded like gibberish (and it probably did), a quick digression into the purpose of client properties is in order...
In deployment, the end-user's browser only needs one particular compilation, which is determined by mapping the end user's client properties onto the available compiled permutations. Thus, only the exact code required by the end user is downloaded, no more. By making locale a client property, the standard startup process in gwt.js chooses the appropriate localized version of an application, providing ease of use (it's easier than it might sound!), optimized performance, and minimum script size.
<!-- implied. License for the specific language governing permissions and -> <!-- limitations under the License. ->
<!-- English language, independent of country --> <extend-property name="locale" values="en"/> </module>
For example, the following host HTML page sets the locale to "ja_JP":
<html> <head> <meta name="gwt:module" content="com.google.gwt.examples.i18n.ColorNameLookupExample"> <meta name="gwt:property" content="locale=ja_JP"> </head> <body>
To specify the locale client property using a query string, specify a value for the name locale. For example,
http://www.example.org/myapp.html?locale=fr_CA
Contents
Overview Writing Native JavaScript Methods Accessing Java Methods and Fields from JavaScript Sharing objects between Java source and JavaScript Exceptions and JSNI
Overview
The GWT compiler translates Java source into JavaScript. Sometimes it's very useful to mix handwritten JavaScript into your Java source code. For example, the lowest-level functionality of certain core GWT classes are handwritten in JavaScript. GWT borrows from the Java Native Interface (JNI) concept to implement JavaScript Native Interface (JSNI).
Writing JSNI methods is a powerful technique, but should be used sparingly. JSNI code is less portable across browsers, more likely to leak memory, less amenable to Java tools, and hard for the compiler to optimize. We think of JSNI as the web equivalent of inline assembly code. You can:
Implement a Java method directly in JavaScript Wrap type-safe Java method signatures around existing JavaScript Call from JavaScript into Java code and vice-versa Throw exceptions across Java/JavaScript boundaries Read and write Java fields from JavaScript Use hosted mode to debug both Java source (with a Java debugger) and JavaScript (with a script debugger, only in Windows right now)
Tip When accessing the browser's window and document objects from JSNI, you must reference them as $wnd and $doc, respectively. Your compiled script runs in a nested frame, and $wnd and $doc are automatically initialized to correctly refer to the host page's window and document.
Example
public static native void alert(String msg) /*-{ $wnd.alert(msg); }-*/;
Tip In hosted mode, you can set a breakpoint on the source line containing the opening brace of a JSNI method, allowing you to see invocation arguments.
where [instance-expr.] must be present when calling an instance method and must be absent when calling a static method class-name is the fully-qualified name of the class in which the method is declared (or a subclass thereof) param-signature is the internal Java method signature as specified here but without the trailing signature of the method return type since it isn't needed to choose the overload arguments the actual argument list to pass to the called method
Example
public class JSNIExample {
public native void bar(JSNIExample x, String s) /*-{ // Call instance method instanceFoo() on this this.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s) ;
// Read static field (no qualifier) @com.google.gwt.examples.JSNIExample::myStaticField = val + " and stuff"; }-*/;
Tip When writing JSNI code, it's helpful to occasionally run in web mode. The JavaScript compiler checks your JSNI code and can flag errors at compile time that you wouldn't catch until runtime in hosted mode.
followed whether the values enter and leave through normal method call semantics, or through the special syntax.
a JavaScript string, as in var s = "my string"; a JavaScript boolean value, as in var b = true; JavaScriptObject (see a JavaScriptObject that must have originated from notes) JavaScript code, typically as the return value of some other JSNI method Java array an opaque value that can only be passed back into Java code any other Java Object an opaque value accessible through special syntax
a JavaScript string, as in return "boo"; boolean a JavaScript boolean value, as in return false; JavaScriptObject (see a native JavaScript object, as in return document.createElement("div") notes) any other Java Object a Java Object of the correct type that must have (including arrays) originated in Java code; Java objects cannot be constructed from "thin air" in JavaScript
Important Notes
A Java numeric primitive is one of byte, short, char, int, long, float, or double. You must ensure the value is appropriate for the declared type. Returning 3.7 when the declared type is int will cause unpredictable behavior. Java null and JavaScript null are identical and always legal values for any nonprimitive Java type. JavaScript undefined is not identical to null; never return undefined from a JSNI method or unpredictable behavior will occur. Violating any of these marshaling rules in hosted mode will generate a com.google.gwt.dev.shell.HostedModeException detailing the problem. This exception is not translatable and never thrown in web mode.
JavaScriptObject is a magical type that gets special treatment from the GWT compiler and hosted browser. Its purpose is to provide an opaque representation of native JavaScript objects to Java code.
Tip When returning a possibly undefined value from a JSNI method, we suggest using the idiom return (value == null) ? null : value; to avoid returning undefined.
Package java.lang
o o
o o o o o o o o
o o o o o o o o o
Boolean Boolean(boolean), Boolean(String), booleanValue(), equals(Object), hashCode(), toString(boolean), toString(), valueOf(boolean), valueOf(String)
Byte o Byte(byte), o Byte(String), o byteValue(), o compareTo(Byte), o compareTo(Object), o decode(String), o doubleValue(), o equals(Object), o floatValue(), o hashCode(), o intValue(), o longValue(), o parseByte(String), o parseByte(String, int), o shortValue(), o toString(byte), o toString(), o valueOf(String), o valueOf(String, int) CharSequence o charAt(int), o length(), o subSequence(int, int), o toString()
Character o Character(char), o charValue(), o compareTo(Character), o compareTo(Object), o digit(char, int), o equals(Object), o forDigit(int, int), o hashCode(), o isDigit(char), o isLetter(char), o isLetterOrDigit(char), o isLowerCase(char), o isSpace(char), o isUpperCase(char), o toLowerCase(char), o toString(char), o toString(), o toUpperCase(char) Class ClassCastException o ClassCastException(), o ClassCastException(String) Cloneable Comparable o compareTo(Object) Double Double(double), Double(String), byteValue(), compare(double, double), compareTo(Double), compareTo(Object), doubleValue(), equals(Object), floatValue(), hashCode(), intValue(), isInfinite(double), isInfinite(), isNaN(double), isNaN(),
o o o o o o o o o o o o o o o
o o o o o o
o o o o
Exception o Exception(), o Exception(String), o Exception(String, Throwable), o Exception(Throwable) Float o Float(float), o Float(String), o byteValue(), o compare(float, float), o compareTo(Float), o compareTo(Object), o doubleValue(), o equals(Object), o floatValue(), o hashCode(), o intValue(), o isInfinite(float), o isInfinite(), o isNaN(float), o isNaN(), o longValue(), o parseFloat(String), o shortValue(), o toString(float), o toString(), o valueOf(String) IllegalArgumentException o IllegalArgumentException(), o IllegalArgumentException(String) IllegalStateException
o o o o
IndexOutOfBoundsException o IndexOutOfBoundsException(), o IndexOutOfBoundsException(String) Integer o Integer(int), o Integer(String), o byteValue(), o compareTo(Integer), o compareTo(Object), o decode(String), o doubleValue(), o equals(Object), o floatValue(), o hashCode(), o intValue(), o longValue(), o parseInt(String), o parseInt(String, int), o shortValue(), o toBinaryString(int), o toHexString(int), o toString(int), o toString(), o valueOf(String), o valueOf(String, int) Long o Long(long), o Long(String), o byteValue(), o compareTo(Long), o compareTo(Object), o decode(String), o doubleValue(), o equals(Object), o floatValue(), o hashCode(), o intValue(), o longValue(), o parseLong(String), o parseLong(String, int),
o o o o o o o
Math o abs(double), o abs(float), o abs(int), o abs(long), o acos(double), o asin(double), o atan(double), o ceil(double), o cos(double), o exp(double), o floor(double), o log(double), o max(double, double), o max(float, float), o max(int, int), o max(long, long), o min(double, double), o min(float, float), o min(int, int), o min(long, long), o pow(double, double), o random(), o round(double), o round(float), o sin(double), o sqrt(double), o tan(double), o toDegrees(double), o toRadians(double) NegativeArraySizeException NegativeArraySizeException(), NegativeArraySizeException(String)
o o
Number o byteValue(), o doubleValue(), o floatValue(), o intValue(), o longValue(), o shortValue() NumberFormatException o NumberFormatException(), o NumberFormatException(String) Object equals(Object), hashCode(), toString() RuntimeException RuntimeException(), RuntimeException(String), RuntimeException(String, Throwable), RuntimeException(Throwable) Short Short(short), Short(String), byteValue(), compareTo(Object), compareTo(Short), decode(String), doubleValue(), equals(Object), floatValue(), hashCode(), intValue(), longValue(), parseShort(String), parseShort(String, int), shortValue(), toString(short), toString(), valueOf(String), valueOf(String, int) String String(), String(char[]),
o o o
o o o o
o o o o o o o o o o o o o o o o o o o
o o
o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
String(char[], int, int), String(String), charAt(int), compareTo(Object), compareTo(String), concat(String), endsWith(String), equals(Object), equalsIgnoreCase(String), hashCode(), indexOf(int), indexOf(int, int), indexOf(String), indexOf(String, int), lastIndexOf(int), lastIndexOf(int, int), lastIndexOf(String), lastIndexOf(String, int), length(), matches(String), replace(char, char), replaceAll(String, String), replaceFirst(String, String), split(String), split(String, int), startsWith(String), startsWith(String, int), subSequence(int, int), substring(int), substring(int, int), toCharArray(), toLowerCase(), toString(), toUpperCase(), trim(), valueOf(boolean), valueOf(char), valueOf(char[], int, int), valueOf(char[]), valueOf(double), valueOf(float), valueOf(int), valueOf(long), valueOf(Object)
StringBuffer StringBuffer(),
o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
StringBuffer(int), StringBuffer(String), append(boolean), append(char), append(char[]), append(char[], int, int), append(double), append(float), append(int), append(long), append(Object), append(String), append(StringBuffer), charAt(int), delete(int, int), deleteCharAt(int), getChars(int, int, char[], int), indexOf(String), indexOf(String, int), insert(int, boolean), insert(int, char), insert(int, char[]), insert(int, char[], int, int), insert(int, double), insert(int, float), insert(int, int), insert(int, long), insert(int, Object), insert(int, String), lastIndexOf(String), lastIndexOf(String, int), length(), replace(int, int, String), setCharAt(int, char), setLength(int), subSequence(int, int), substring(int), substring(int, int), toString()
o o o
o o o
o o o o o o o o o o o o o o
Throwable Throwable(), Throwable(String), Throwable(String, Throwable), Throwable(Throwable), fillInStackTrace(), getCause(), getLocalizedMessage(), getMessage(), getStackTrace(), initCause(Throwable), printStackTrace(), printStackTrace(PrintStream), setStackTrace(StackTraceElement[]), toString()
Package java.util
o o o o o o o o o o o o o o
AbstractCollection add(Object), addAll(Collection), clear(), contains(Object), containsAll(Collection), isEmpty(), iterator(), remove(Object), removeAll(Collection), retainAll(Collection), size(), toArray(), toArray(Object[]), toString()
o o o o o o o o o o o o o
clear(), equals(Object), get(int), hashCode(), indexOf(Object), indexOutOfBounds(int), iterator(), lastIndexOf(Object), listIterator(), listIterator(int), remove(int), removeRange(int, int), set(int, Object)
AbstractMap o clear(), o containsKey(Object), o containsValue(Object), o entrySet(), o equals(Object), o get(Object), o hashCode(), o isEmpty(), o keySet(), o put(Object, Object), o putAll(Map), o remove(Object), o size(), o toString(), o values() AbstractSet o equals(Object), o hashCode(), o removeAll(Collection) ArrayList o ArrayList(), o ArrayList(Collection), o ArrayList(int), o add(int, Object), o add(Object), o addAll(Collection), o clear(), o clone(), o contains(Object), o get(int),
o o o o o o o o o o o o
indexOf(Object), indexOf(Object, int), isEmpty(), lastIndexOf(Object), lastIndexOf(Object, int), remove(int), remove(Object), removeRange(int, int), set(int, Object), setSize(int), size(), toArray(Object[])
o o o o o o o o o o o o
Arrays asList(Object[]), binarySearch(byte[], byte), binarySearch(char[], char), binarySearch(double[], double), binarySearch(float[], float), binarySearch(int[], int), binarySearch(long[], long), binarySearch(Object[], Object), binarySearch(Object[], Object, Comparator), binarySearch(short[], short), sort(Object[]), sort(Object[], Comparator) Collection add(Object), addAll(Collection), clear(), contains(Object), containsAll(Collection), equals(Object), hashCode(), isEmpty(), iterator(), remove(Object), removeAll(Collection), retainAll(Collection), size(), toArray(), toArray(Object[]) Collections binarySearch(List, Object), binarySearch(List, Object, Comparator),
o o o o o o o o o o o o o o o
o o
o o o
o o
o o
Date o Date(), o Date(int, int, int), o Date(int, int, int, int, int), o Date(int, int, int, int, int, int), o Date(long), o Date(String), o UTC(int, int, int, int, int, int), o __parse(String), o after(Date), o before(Date), o clone(), o compareTo(Date), o compareTo(Object), o equals(Object), o getDate(), o getDay(), o getHours(), o getMinutes(), o getMonth(), o getSeconds(), o getTime(), o getTimezoneOffset(), o getYear(), o hashCode(), o parse(String), o setDate(int), o setHours(int), o setMinutes(int), o setMonth(int), o setSeconds(int), o setTime(long), o setYear(int), o toGMTString(), o toLocaleString(),
toString()
EmptyStackException EventListener EventObject EventObject(Object), getSource() HashMap HashMap(), HashMap(int), HashMap(int, float), HashMap(Map), clear(), clone(), containsKey(Object), containsValue(Object), entrySet(), get(Object), isEmpty(), put(Object, Object), putAll(Map), remove(Object), size()
o o
o o o o o o o o o o o o o o o
HashSet o HashSet(), o HashSet(Collection), o HashSet(int), o HashSet(int, float), o add(Object), o clear(), o clone(), o contains(Object), o isEmpty(), o iterator(), o remove(Object), o size(), o toString() Iterator o hasNext(), o next(), o remove()
List o add(int, Object), o add(Object), o addAll(Collection), o addAll(int, Collection), o clear(), o contains(Object), o containsAll(Collection), o equals(Object), o get(int), o hashCode(), o indexOf(Object), o isEmpty(), o iterator(), o lastIndexOf(Object), o listIterator(), o listIterator(int), o remove(int), o remove(Object), o removeAll(Collection), o retainAll(Collection), o set(int, Object), o size(), o toArray() ListIterator o add(Object), o hasNext(), o hasPrevious(), o next(), o nextIndex(), o previous(), o previousIndex(), o remove(), o set(Object) Map clear(), containsKey(Object), containsValue(Object), entrySet(), equals(Object), get(Object), hashCode(), isEmpty(), keySet(), put(Object, Object),
o o o o o o o o o o
o o o o
MissingResourceException o MissingResourceException(String, String, String), o getClassName(), o getKey() NoSuchElementException NoSuchElementException(), NoSuchElementException(String) RandomAccess Set add(Object), addAll(Collection), clear(), contains(Object), containsAll(Collection), equals(Object), hashCode(), isEmpty(), iterator(), remove(Object), removeAll(Collection), retainAll(Collection), size(), toArray()
o o
o o o o o o o o o o o o o o
Stack o clone(), o empty(), o peek(), o pop(), o push(Object), o search(Object) TooManyListenersException Vector Vector(), Vector(Collection), Vector(int), add(int, Object),
o o o o
o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
add(Object), addAll(Collection), addAll(int, Collection), addElement(Object), clear(), clone(), contains(Object), copyInto(Object[]), elementAt(int), firstElement(), get(int), indexOf(Object), indexOf(Object, int), insertElementAt(Object, int), isEmpty(), iterator(), lastElement(), lastIndexOf(Object), lastIndexOf(Object, int), remove(int), removeAllElements(), removeElement(Object), removeElementAt(int), removeRange(int, int), set(int, Object), setElementAt(Object, int), setSize(int), size(), toArray()
Package java.io
Serializable
Packagescom.google.gwt.core.clientFundamentalclassesusedinclientsideGWTcode.
com.google.gwt.core.extClassesusedtoextendtheGWTcompiler. com.google.gwt.core.ext.typeinfoTypeintrospectionsupportclassesusedbygenerators. com.google.gwt.http.clientProvidestheclientsideclassesandinterfacesformakingHTTPrequestsand processingtheassociatedresponses. com.google.gwt.i18n.clientInternationalizationsupportforGWTapplications. com.google.gwt.json.clientClassesforparsingandcreatingJSONencodedvalues. com.google.gwt.junit.clientClassesandmodulesusedinbuildingJUnittests. com.google.gwt.user.clientFundamentaluserinterfaceclassesusedinclientsideGWTcode.