It took me a week to write my first generator (with help - thanks mP).
Am hoping that this How-To will save time for others.
This How-To is targetted for newbies and upwards.
A generator that returns a properties file as a Map.
Usage :: Map myPropertiesMap = (Map) GWT.create(MyPropertiesMap.class)
Valid :: HashMap myPropertiesMap = (HashMap)
GWT.create(MyPropertiesMap.class)
*** Step 1 *** Write a marker interface/class.
**************
In the following example, "extends Map" is not necessary. I have
included it as it is more *descriptive*. This interface/class *must*
reside in a "client side" folder as it needs to be accessed by the
GWTCompiler to generate client side code (example location:
module.client[.generator])
file :: PropertyMap.java
========================
package rm.gwt.core.client.generator;
import java.util.Map;
public interface PropertyMap extends Map {
}
*** Step 2 *** Write your generator.
**************
Writes out the source code for the new class. The source code is self
explanatory. This class *must* *not* reside in a "client side" folder.
This class can use *any* class available to it - it is *not* limited
to the GWT runtimes. By convention, it is placed in the module.rebind
folder.
file :: PropertyMapGenerator.java
=================================
package rm.gwt.core.rebind;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.ResourceBundle;
/**
* GWT generator that returns a <code>Map</code> (<code>HashMap</
code>)
* from a properties file.
* Usage :: Map myPropertyMap = (Map) GWT.create(MyPropertyMap.class);
* Where :: MyProperMap extends PropertyMap (marker interface)
* :: MyPropertyMap.properties is in same package as
MyPropertyMap.java
*
* @author
riyaz....@gmail.com
* @version 2007.12-1
*/
public class PropertyMapGenerator extends Generator {
/** Simple name of class to be generated */
private String className = null;
/** Package name of class to be generated */
private String packageName = null;
/** Fully qualified class name passed into GWT.create() */
private String typeName = null;
// inherited generator method
public String generate(TreeLogger logger, GeneratorContext
context,
String typeName) throws UnableToCompleteException {
this.typeName = typeName;
TypeOracle typeOracle = context.getTypeOracle();
try {
// get classType and save instance variables
JClassType classType = typeOracle.getType(typeName);
packageName = classType.getPackage().getName();
className = classType.getSimpleSourceName() + "Wrapper";
// Generate class source code
generateClass(logger, context);
} catch (Exception e) {
// record to logger that Map generation threw an exception
logger.log(TreeLogger.ERROR, "PropertyMap ERROR!!!", e);
}
// return the fully qualifed name of the class generated
return packageName + "." + className;
}
/**
* Generate source code for new class. Class extends
<code>HashMap</code>.
*
* @param logger Logger object
* @param context Generator context
*/
private void generateClass(TreeLogger logger, GeneratorContext
context) {
// get print writer that receives the source code
PrintWriter printWriter = null;
printWriter = context.tryCreate(logger, packageName, className);
// print writer if null, source code has ALREADY been generated,
return
if (printWriter == null) return;
// init composer, set class properties, create source writer
ClassSourceFileComposerFactory composer = null;
composer = new ClassSourceFileComposerFactory(packageName,
className);
composer.setSuperclass("java.util.HashMap");
SourceWriter sourceWriter = null;
sourceWriter = composer.createSourceWriter(context, printWriter);
// generator constructor source code
generateConstructor(sourceWriter);
// close generated class
sourceWriter.outdent();
sourceWriter.println("}");
// commit generated class
context.commit(logger, printWriter);
}
/**
* Generate source code for the default constructor. Create
default
* constructor, call super(), and insert all key/value pairs from
* the resoruce bundle.
*
* @param sourceWriter Source writer to output source code
*/
private void generateConstructor(SourceWriter sourceWriter) {
// init resource bundle
ResourceBundle bundle = ResourceBundle.getBundle(typeName);
// start constructor source generation
sourceWriter.println("public " + className + "() { ");
sourceWriter.indent();
sourceWriter.println("super();");
// add statements to pub key/value pairs from the resrouce bundle
for (Enumeration<String> keys = bundle.getKeys();
keys.hasMoreElements();) {
String key = keys.nextElement();
sourceWriter.println("put(\"" + Generator.escape(key) +
"\", \""
+ bundle.getString(key) + "\");");
}
// end constructor source generation
sourceWriter.outdent();
sourceWriter.println("}");
}
}
*** Step 3 *** Update the module.gwt.xml file
**************
Include generator info as the last element within your xml file.
Module.xml (sample) ::
======================
<?xml version="1.0" encoding="UTF-8"?>
<module>
<inherits name="com.google.gwt.user.User"/>
<generate-with class="rm.gwt.core.rebind.PropertyMapGenerator" >
<when-type-assignable
class="rm.gwt.core.client.generator.PropertyMap"/>
</generate-with>
</module>
*** Step 4 *** Write sample files. *Must* be in the same folder.
**************
file :: MyPropertiesMap.java
============================
package <package>;
import <imports>;
public interface MyPropertiesMap extends PropertiesMap {}
file :: MyPropertiesMap.properties
==================================
key1=value1
key2=value2
END