I have a class int the following name com.test.TestClass
At one point in my code I have to get instance of this class by only having the class name stri
Here is well tested, commented and slightly refactored version of Ashwin Prabhu's code:
https://bitbucket.org/espinosa/z025-gwt-maven-alternative-setup/src/d35a3fb7e627b5598fb763f480e3f76932cf4232/src/main/java/my/code/z025/util/ClassFromStringFactoryGenerator.java?at=master
Example of usage:
String targetEntryPointClass = "my.code.client.Sample3";
ClassFromStringFactory classFromStringFactory = GWT.create(ClassFromStringFactory.class);
Object targetEntryPointInstance = classFromStringFactory.instantiate(targetEntryPointClass);
if (targetEntryPointInstance == null) {
// throw some exception
}
if (targetEntryPointInstance instanceof EntryPoint) {
((EntryPoint) targetEntryPointInstance).onModuleLoad();
} else {
// throw some exception
}
See full source code: https://bitbucket.org/espinosa/z025-gwt-maven-alternative-setup/src/d35a3fb7e627b5598fb763f480e3f76932cf4232/src/main/java/my/code/z025/client/Dispatcher.java?at=master
In my project, I use GWT's own EntryPoint as marker interface. This enables me to run arbitrary EntryPoint just via URL: http://localhost:8080/my.code.client.Sample3
; the Dispatcher EntryPoint instantiates my.code.client.Sample3
via my ClassFromStringFactory
. Only Dispatcher Entry Point is configured in GWT module descriptor and the deferred binding, everything else is dynamic.
For curious, here is what GWT (Code Server in DevMode or Compiler for production mode) generates, content of my ClassFromStringFactoryImpl:
package my.code.client.reflection;
public class ClassFromStringFactoryImpl implements ClassFromStringFactory {
public ClassFromStringFactoryImpl( ) {}
public Object instantiate(String className) {
if (className == null) {
return null
}
else if (className.equals("my.code.client.Sample1")) {
return new my.code.client.Sample1( );
}
else if (className.equals("my.code.client.Sample2")) {
return new my.code.client.Sample2( );
}
..and so on, 3 same lines per every supported type
return null;
}
}
In temporary file like: C:\Users\espinosa\AppData\Local\Temp\my.code.client.reflection.ClassFromStringFactoryImpl4245548251877324156.java
.
Note: this file is generated only in case of failure, not on successful compilation
As you can see, it is no real introspection. Deferred binding does not do any special magic. Similar Java code can be generated by a Velocity template as a part of Maven build or special tools like XText, APT-Jelly. Using GWT's Generator is just a convenience.
It is important to limit number of "supported" classes, otherwise the generated ClassFromStringFactoryImpl
would be too huge, impractically huge or even exceeding limits on Java class. Some sort of filtering is necessary, marking interface is just one option, others are marking annotation (see GWT's JClassType#getAnnotation(Class)) or only selected packages. In any case, ensure that number of supported classes by this "reflection" does not exceeds magnitude of hundreds.
Many thanks Ashwin Prabhu for pointing me to the right direction.