This feature cannot be used in GWT, as you may all know that the client code (JavaScript) is statically generated. There is no Classloader or no Class.newInstance() or no reflection at all in Javascript. So to provide very least feature of instantiating a Class by knowing its classname, here is a tip that you may like.
We may not require all the Class types to be available for dynamic instantiation. So we are gonna mark the required Class types as Instantiable (A marker interface).
Now, we need some factory class which has a method newInstance(String className), using which we can create an instance of specified classname.
1 package name.aanand.gwt.client;
2
3 /**
4 * Platform factory to create instance of any {@link Instantiable} type.
5 * @author aanandn
6 *
7 */
8 public interface Factory {
9 Instantiable getInstance(String className);
10 }
1 package name.aanand.gwt.client;
2
3
4 /**
5 * Factory class for instantiating any {@link Instantiable} type by providing
6 * the fully qualified Class name.
7 * @author aanandn
8 *
9 */
10 public class ReflectiveFactory implements FactoryWrapper{
11 }
First have a singleton class which instantiates our Factory like this:
factory = (Factory) GWT.create(ReflectiveFactory.class);
Now you may wonder, how will it work without any real code in the ReflectiveFactory. So here is the explaination of how its gonna work.
- We are going to extend the GWT compiler to generate a wrapper or proxy for each of the Classes which implement FactoryWrapper.
- The generator should create a new class with name
Wrapper, which implements Factory. - In the case of ReflectiveFactory, first we are going to get all the Instantiable types.
- And finally generate the method newInstance(String className), conditionally returning one of the Reflectables based on the specified className.
1 <module>
2
3 -- Inherit the core Web Toolkit stuff. -->
4 <inherits name='com.google.gwt.user.User'/>
5
6 -- Specify the app entry point class. -->
7 <entry-point class='name.aanand.gwt.client.MainEntryPoint'/>
8
9 <generate-with class="name.aanand.gwt.generator.FactoryGenerator" >
10 <when-type-assignable class="name.aanand.gwt.client.FactoryWrapper" />
11 </generate-with>
12
13 </module>
14
public String generate(TreeLogger logger, GeneratorContext context, String typeName)
Simple implemenation of FactoryGenerator is given below:
1 package name.aanand.gwt.generator;
2
3 import java.io.PrintWriter;
4
5 import com.google.gwt.core.ext.Generator;
6 import com.google.gwt.core.ext.GeneratorContext;
7 import com.google.gwt.core.ext.TreeLogger;
8 import com.google.gwt.core.ext.UnableToCompleteException;
9 import com.google.gwt.core.ext.typeinfo.JClassType;
10 import com.google.gwt.core.ext.typeinfo.NotFoundException;
11 import com.google.gwt.core.ext.typeinfo.TypeOracle;
12 import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
13 import com.google.gwt.user.rebind.SourceWriter;
14
15 public class FactoryGenerator extends Generator {
16
17 public String generate(TreeLogger logger, GeneratorContext context,
18 String typeName) throws UnableToCompleteException {
19 logger.log(TreeLogger.INFO, "Generating source for " + typeName, null);
20 TypeOracle typeOracle = context.getTypeOracle();
21
22 JClassType clazz = typeOracle.findType(typeName);
23 if (clazz == null) {
24 logger.log(TreeLogger.ERROR, "Unable to find metadata for type '"
25 + typeName + "'", null);
26 throw new UnableToCompleteException();
27 }
28
29 try {
30 logger.log(TreeLogger.INFO, "Generating source for "
31 + clazz.getQualifiedSourceName(), null);
32
33 JClassType reflectableType = typeOracle
34 .getType("name.aanand.gwt.client.Instantiable");
35 SourceWriter sourceWriter = getSourceWriter(clazz, context, logger);
36 if (sourceWriter != null) {
37 sourceWriter.println("public "
38 + reflectableType.getQualifiedSourceName()
39 + " newInstance(String className) {");
40 JClassType[] types = typeOracle.getTypes();
41 int count = 0;
42 for (int i = 0; i < types.length; i++) {
43 if (types[i].isInterface() == null
44 && types[i].isAssignableTo(reflectableType)) {
45 if (count == 0) {
46 sourceWriter.println(" if(\""
47 + types[i].getQualifiedSourceName()
48 + "\".equals(className)) {"
49 + " return new "
50 + types[i].getQualifiedSourceName() + "();"
51 + "}");
52 } else {
53 sourceWriter.println(" else if(\""
54 + types[i].getQualifiedSourceName()
55 + "\".equals(className)) {"
56 + " return new "
57 + types[i].getQualifiedSourceName() + "();"
58 + "}");
59 }
60 count++;
61 }
62 }
63 sourceWriter.println("return null;");
64 sourceWriter.println("}");
65 sourceWriter.commit(logger);
66 logger.log(TreeLogger.INFO, "Done Generating source for "
67 + clazz.getName(), null);
68 return clazz.getQualifiedSourceName() + "Wrapper";
69 }
70 } catch (NotFoundException e) {
71 e.printStackTrace();
72 }
73 return null;
74
75 }
76
77 public SourceWriter getSourceWriter(JClassType classType,
78 GeneratorContext context, TreeLogger logger) {
79
80 String packageName = classType.getPackage().getName();
81 String simpleName = classType.getSimpleSourceName() + "Wrapper";
82 ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(
83 packageName, simpleName);
84 composer.addImplementedInterface("name.aanand.gwt.client.Factory");
85 PrintWriter printWriter = context.tryCreate(logger, packageName,
86 simpleName);
87 if (printWriter == null) {
88 return null;
89 } else {
90 SourceWriter sw = composer.createSourceWriter(context, printWriter);
91 return sw;
92 }
93 }
94
95 }
96
Factory factory = (Factory) GWT.create(ReflectiveFactory.class);
factory.newInstance("fully.qualified.Classname
Thats all folks!


