Posts Tagged GWT
GWT 2.0 RC2 available
Posted by Olivier Gérardin in GWT on 2009-11-29
The book is out… Le livre est sorti…
Posted by Olivier Gérardin in GWT on 2009-11-18
The same day as GWT 2.0 RC1, that has to be a good sign…
(cliquez sur le livre pour feuilleter une sélection de pages)
GWT 2.0 RC1 is out!
Posted by Olivier Gérardin in GWT on 2009-11-18
Hi folks!
GWT 2.0 RC1 is now ready for you to try. The full documentation is still very much a work in progress, but you can at least start trying out the GWT SDK distribution and the Google Plugin for Eclipse using the following instructions:
http://code.google.com/p/google-web-toolkit/wiki/GWT_2_0_RC
GWT 2.0 is going to be a big release, so don’t be surprised if there are a few bumps and surprises as we continue to finalize everything.
Read full announcement on GWT group
GWT is the present of web development
Posted by Olivier Gérardin in GWT on 2009-11-04
I’ve read a few articles by people who didn’t like GWT, but usually I don’t care to reply because it requires a lot of time to do it properly. However, today I came across this article on dzone: Lost in Translation or Why GWT Isn’t the Future of Web Development.
This one was troubling because it made good points on the way, some that I can’t agree more with (like the quality of Ext-GWT…) but it comes to a completely biased conclusion about GWT. So I took some time and wrote a reply…
GWT: generating the factory
Posted by Olivier Gérardin in GWT on 2009-11-02
Controllers galore
In my current GWT project, we make heavy use of MVC, which means we have controllers and views all over the place. To link menu items and other actions to screens, the action item only keeps a reference to the controller class. This implies that we have to be able to instantiate the controller when the action is triggered.
No problem, we have a controllerClass, so we call controllerClass.newInstance(), right?
Well, not in the GWT world.
When you’re running the web version of your GWT application, due to the amount of meta-data that would have to be carried together with your code, Java reflection capabilities are not available. Which means that, even though the Class class exists, you can’t use it to list methods or fields, and you definitely can’t use it to obtain an instance of that class. This is a classic trap, because it might appear to work in hosted mode, simply because hosted mode runs in a standard JVM… but when you try to compile and run your application in web mode, you can forget it.
The poor man’s dynamic instantiation
Basically, the only option you have when you want to instantiate a class from a class reference, is to compare it with known classes, and when one is recognized, to call “new”, like this:
if (controllerClass == Controller1.class) {
return new Controller1();
}
if (controllerClass == Controller2.class) {
return new Controller2();
}
// (many lines omitted...)
throw new IllegalArgumentException("The class " +
controllerClass.getName() + " is unknown in this factory.");
You can see how this is painful:
- whenever you create a new controller, you have to remember to add it to this method, otherwise instantiation will fail during runtime
- this method rapidly grows and becomes unmaintainable
To make things as clean as possible, this should be wrapped in a controller factory: a simple class that implements an interface with a single method
Controller createController(Class<? extends Controller> controllerClass) throws IllegalArgumentException;
While this hides the “details” of the implementation, it does not remove the burden of maintaining the factory method.
This is when GWT’s deferred binding mechanism can be useful. To compensate for the lack of runtime introspection, the GWT compiler can dynamically (during compilation) provide the best-suited implementation of an interface, or subclass of a given class. The client requests an implementation of this class by calling GWT.create(MyInterface.class).
The replacement class can be provided in one of two ways:
- by substitution: under certain conditions, the class is substituted with an existing implementation. This is how GWT internally handles differences between browsers.
- by generation: the implementation is constructed at compile-time by a Generator.
So why not use the second option and let the GWT compiler generate the factory class for us? It’s simple enough, we just need to generate an if statement for each known controller. So let’s try to do that.
Declaring the generator
First we need to tell the GWT compiler to invoke our generator, and when. Suppose our factory method is contained in an interface named ControllerFactory, then we just need to add the following lines to the GWT module file:
<generate-with class="oge.gwt.rebind.ControllerFactoryGenerator">
<when-type-assignable class="oge.gwt.client.ControllerFactory"/>
</generate-with>
This translates to “when the client calls GWT.create() with a parameter class that is assignable to ControllerFactory, use ControllerFactoryGenerator to build the implementation class and return an instance of this class”. The interface must reside in the client package, but the generator must be somewhere else. The common practice is to put all generators in a package named “rebind”.
Next the generator itself.
Building the generator
The generator must implement the interface com.google.gwt.core.ext.Generator, which defines a single method:
generate(TreeLogger logger, GeneratorContext context, java.lang.String typeName)
where:
- logger is used to log debug/info messages
- context is used to obtain context information, and helpers to write the generated class
- typeName is the name of the type being substitued; in our case this should always be “oge.gwt.client.ControllerFactory”
This method is invoked by the GWT compiler whenever the generate-with clause of the module is activated. The generated class must be written as full java source like you would write by hand; luckily some convenience methods exist.
The first thing the generator needs to decide is what the name of the generated class will be. The common practice is to add the “Impl” suffix to the interface name (we use “GeneratedImpl” to distinguish it from our hand-coded implementation).
This is how we do it:
public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException {
logger.log(TreeLogger.Type.INFO, "Generating " + typeName);
this.typeName = typeName;
TypeOracle typeOracle = context.getTypeOracle();
try {
// obtain JClassType instance for target type and construct target class name
JClassType classType = typeOracle.getType(typeName);
this.packageName = classType.getPackage().getName();
this.className = classType.getSimpleSourceName() + "GeneratedImpl";
// generate class source code
generateClass(logger, context);
} catch (Exception e) {
logger.log(TreeLogger.ERROR, "Failed to generate implementation for " + typeName, e);
}
// return the fully qualifed name of the generated class
return this.packageName + "." + this.className;
}
Things to note:
- we use TypeOracle (from the context) to obtain a JClassType instance for the type being substituted. TypeOracle and the associated classes (JClassType, JPackage, JField, JConstructor, JMethod, etc.) provide a powerful tool to query Java source and meta-information. It can be seen as the equivalent of native Java introspection. Once we have our JClassType instance, we can easily obtain the package name and class name.
- if the generation succeeds, the method must return the fully qualified name of the generated class
Generating the class
The class generation itself requires the following steps:
- Begin source generation by calling context.tryCreate(logger, packageName, className). This method returns a PrintWriter, which we will use to write the source code. If it returns null, it means that the target class has already been generated and we can safely skip the generation.
- Instantiate a ClassSourceFileComposerFactory with the package name and class name. This is a utility class that helps building the target class.
- If necessary, call addImport(), addImplementedInterface(), setSuperclass() on the ClassSourceFileComposerFactory instance.
- Obtain a SourceWriter by calling createSourceWriter(context, printWriter) on the instance of ClassSourceFileComposerFactory.
- Use methods of SourceWriter (println(), indent(), outdent(), …) to write the meat of the class.
- When you’re done, commit the generated source by calling context.commit(logger, printWriter).
This is how we do it for our controller factory:
private void generateClass(TreeLogger logger, GeneratorContext context) throws Exception {
// get a PrintWriter to write source code to
PrintWriter printWriter = context.tryCreate(logger, packageName, className);
if (printWriter == null) {
// source code has already been generated, abort
return;
}
ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(packageName, className);
composer.addImport("oge.gwt.client.mvc.Controller");
composer.addImplementedInterface(typeName);
SourceWriter sourceWriter = composer.createSourceWriter(context, printWriter);
generateCreateControllerMethod(sourceWriter, context.getTypeOracle());
sourceWriter.println("}");
// commit source generation
context.commit(logger, printWriter);
}
Almost done… now we only need to implement generateCreateControllerMethod(), which will generate the body of the method “createController()”. To do this, we need to generate a block like the following for each controller class that might be instantiated dynamically at runtime:
if (controllerClass == ControllerXXX.class) {
return new ControllerXXX();
}
To do this, we wil simply iterate on all known classes by using getTypes() from TypeOracle, and retain only those that:
- implement our substituted interface (ControllerFactory)
- are public
- are not abstract
- have a public no-args constructor
These conditions are checked by using various methods on JClassType.
This is the result:
private void generateCreateControllerMethod(SourceWriter sourceWriter, TypeOracle typeOracle) throws Exception {
// start method source generation
sourceWriter.println("public Controller createController(Class<? extends Controller> controllerClass) throws IllegalArgumentException {");
sourceWriter.indent();
JClassType simpleViewClassType = typeOracle.getType("oge.gwt.client.mvc.Controller");
JClassType classTypes[] = typeOracle.getTypes();
for (JClassType classType : classTypes) {
// we're only interested in subclasses of simpleViewClassType that are public and not abstract
if (!classType.isAssignableTo(simpleViewClassType)
|| !classType.isPublic()
|| classType.isAbstract()) {
continue;
}
// check that we have a no-arg constructor
try {
classType.getConstructor(new JType[] {});
} catch (NotFoundException nfe) {
continue;
}
System.out.println("Found controller: " + classType);
sourceWriter.println("if (controllerClass == " + classType.getQualifiedSourceName() + ".class) {");
sourceWriter.println(" return new " + classType.getQualifiedSourceName() + "();");
sourceWriter.println("}");
}
sourceWriter.println("throw new IllegalArgumentException(\"The class \" + controllerClass.getName() + \" is unknown in this factory.\");");
// end methods source generation
sourceWriter.outdent();
sourceWriter.println("}");
}
Using the generated factory
Finally, we need to replace our old manual instantiation of the hand-coded ControllerFactoryImpl with a call to GWT.create() so that the generator mechanism is triggered:
//controllerFactory = new SimpleViewControllerFactoryImpl();
controllerFactory = GWT.create(SimpleViewControllerFactory.class);
Now when we GWT-compile the application, we will see our log message indicating that the generator is being called:
Computing all possible rebind results for 'oge.gwt.client.ControllerFactory' Rebinding oge.gwt.client.ControllerFactory Invoking <generate-with class='oge.gwt.rebind.ControllerFactoryGenerator'/> Generating oge.gwt.client.ControllerFactory
The application should work exactly as before, since we only substituted a hand-written implementation of ControllerFactory with a computer generated version, which does exactly the same.
You will notice that the generator also gets called when you reload the hosted mode window… this makes sense, because you could very well have added a new Controller , in which case the factory needs to be updated. This is the only downside of this approach, but in my opinion the benefits are well worth the added overhead.
GWT 2.0 milestone 2
Posted by Olivier Gérardin in GWT on 2009-10-27
We are excited to release the second milestone build for GWT 2.0
today. This milestone is essentially feature complete, and provides
somewhat more stability in the various bits of core functionality that
will be coming in GWT 2.0.
Announcing GWT 2.0 Milestone 1
Posted by Olivier Gérardin in GWT on 2009-10-06

Amit Manjhi:
Hi everyone,
We are excited to release the first milestone build for GWT 2.0 today. This milestone provides early access (read: known to still be unfinished and buggy) to the various bits of core functionality that will be coming in GWT 2.0. Please download the bits from:http://code.google.com/p/google-web-toolkit/downloads/list?can=1&q=2….
(…)
Announcing GWT 2.0 Milestone 1 – Google Web Toolkit | Google Groups.
Livre sur GWT: la sortie s’approche
Posted by Olivier Gérardin in GWT on 2009-10-01
(For the english speaking crowd: this is about the book I’m writing about GWT in french)
Le livre que je suis en train d’écrire portera sur GWT 1.7 et 2.0, et s’adressera plutôt aux développeurs Java qui souhaitent passer à GWT. La sortie est prévue en novembre aux éditions Dunod.
Le bout du tunnel approche ! Je mets actuellement la dernière main aux nouveautés de GWT 2.0, OOPHM, code splitting, UiBinder & co.
Pour info vous pouvez déjà précommander sur Amazon
Building GWT on the Mac
Posted by Olivier Gérardin in GWT on 2009-09-25
If you try to build the latest GWT from the svn repository on a Mac, you may end up with a bunch of errors like the following:
BUILD FAILED /Users/ogerardin/Documents/GWT 2/trunk/build.xml:105: The following error occurred while executing this line: /Users/ogerardin/Documents/GWT 2/trunk/build.xml:27: The following error occurred while executing this line: /Users/ogerardin/Documents/GWT 2/trunk/build.xml:58: The following error occurred while executing this line: /Users/ogerardin/Documents/GWT 2/trunk/platforms.ant.xml:36: The following error occurred while executing this line: /Users/ogerardin/Documents/GWT 2/trunk/platforms.ant.xml:13: The following error occurred while executing this line: /Users/ogerardin/Documents/GWT 2/trunk/dev/core/build.xml:192: The following error occurred while executing this line: /Users/ogerardin/Documents/GWT 2/trunk/common.ant.xml:277: Non-zero status code result (1) running command: svn info
The last line indicates a problem with the “svn” command. The problem is that Mac’s builtin svn client is version 1.4.4 (wich you can check by typing “svn --version” in a terminal), but to build GWT, you need a newer svn client.
The steps to fix this are:
- go to http://www.open.collab.net/downloads/community and download the latest subversion binaries for Mac OS X
- you will get a disk image file; mount it and run the included installer. It will install to /opt/subversion/bin
- edit your ~/.profile file to add the following line:
export PATH=/opt/subversion/bin:$PATH
- start a new shell or type “. ~/.profile” to make sure the change is loaded in the current shell
- type “svn --version” and check that the version is the latest one (1.6.5 as of today)
- cd to your checked out GWT trunk directory, type “ant” and watch GWT build
GWT + Snow Leopard: fixed with GWT 1.7.1
Posted by Olivier Gérardin in GWT on 2009-09-24
Google has just released GWT 1.7.1 to fix the issue I mentioned a few days ago regarding Snow Leopard compatibility.
In short, you can now run GWT on Snow Leopard using the Java command line argument -d32 without further modification. The GWT SDK no longer directs you to only use Java 5.
http://googlewebtoolkit.blogspot.com/2009/09/gwt-171-release-fixes-mac-os-x-snow.html