我有一个类int以下名称 com.test.TestClass
在我的代码中,我必须通过只有类名字符串来获取此类的实例.我尝试过使用GWT.create()
但它只在dev模式下工作.任何人都可以告诉我如何从类名中获取gwt中的实例.
Ash*_*bhu 14
由于客户端无法进行反射,因此模拟反射的唯一解决方案是使用延迟绑定.
在编译期间使用延迟绑定来发现您希望使用类名实例化的所有类.您可以在所有这些类上使用标记接口来帮助TypeOracle识别这些.您动态生成工厂类,它接受类的简单名称并返回该类的新实例化对象.这种方法非常简单,您可以在谷歌的教程中找到延迟绑定的一个很好的解释.
编辑: - 一些骨架代码,以帮助您入门.(剥离我的生产代码版本,检查生成的文件中的编译器错误!并调试流程)
First>将以下blurb添加到*.gwt.xml中,以便编译器调用我们的com.package.ReflectionGenerator,它将生成一个简单的工厂类来模仿客户端的反射.
<generate-with class="com.package.ReflectionGenerator">
<when-type-assignable class="com.package.client.Reflection" />
</generate-with>
Run Code Online (Sandbox Code Playgroud)
Next>为我们的工厂类定义一个接口
public interface Reflection {
public <T, V extends T> T instantiate( Class<V> clazz );
}
Run Code Online (Sandbox Code Playgroud)
最后>实现ReflectionGenerator
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.PropertyOracle;
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;
public class ReflectionGenerator extends Generator
{
@Override
public String generate( TreeLogger logger, GeneratorContext context, String typeName ) throws UnableToCompleteException
{
TypeOracle oracle = context.getTypeOracle( );
JClassType instantiableType = oracle.findType( MarkerInterface.class.getName( ) );
List<JClassType> clazzes = new ArrayList<JClassType>( );
PropertyOracle propertyOracle = context.getPropertyOracle( );
for ( JClassType classType : oracle.getTypes( ) )
{
if ( !classType.equals( instantiableType ) && classType.isAssignableTo( instantiableType ) )
clazzes.add( classType );
}
final String genPackageName = "com.package.client";
final String genClassName = "ReflectionImpl";
ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory( genPackageName, genClassName );
composer.addImplementedInterface( Reflection.class.getCanonicalName( ) );
composer.addImport( "com.package.client.*" );
PrintWriter printWriter = context.tryCreate( logger, genPackageName, genClassName );
if ( printWriter != null )
{
SourceWriter sourceWriter = composer.createSourceWriter( context, printWriter );
sourceWriter.println( "ReflectionImpl( ) {" );
sourceWriter.println( "}" );
printFactoryMethod( clazzes, sourceWriter );
sourceWriter.commit( logger );
}
return composer.getCreatedClassName( );
}
private void printFactoryMethod( List<JClassType> clazzes, SourceWriter sourceWriter )
{
sourceWriter.println( );
sourceWriter.println( "public <T, V extends T> T instantiate( Class<V> clazz ) {" );
for ( JClassType classType : clazzes )
{
if ( classType.isAbstract( ) )
continue;
sourceWriter.println( );
sourceWriter.indent( );
sourceWriter.println( "if (clazz.getName().endsWith(\"." + classType.getName( ) + "\")) {" );
sourceWriter.indent( );
sourceWriter.println( "return (T) new " + classType.getQualifiedSourceName( ) + "( );" );
sourceWriter.outdent( );
sourceWriter.println( "}" );
sourceWriter.outdent( );
sourceWriter.println( );
}
sourceWriter.indent();
sourceWriter.println("return (T) null;");
sourceWriter.outdent();
sourceWriter.println();
sourceWriter.println("}");
sourceWriter.outdent( );
sourceWriter.println( );
}
}
Run Code Online (Sandbox Code Playgroud)
这应该在工作区中生成工厂类ReflectionGenerator,检查生成的文件并调整源编写器代码以生成所需的代码.
用法 GWT.create( Reflection.class ).instantiate( YourClass.class );
我'MarkerInterface'在生成器中使用了一个标记接口来限制工厂支持的类的数量,因此所有参与的类必须实现'MarkerInterface'
这是经过充分测试,评论和稍微重构的Ashwin Prabhu代码版本:
用法示例:
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
}
Run Code Online (Sandbox Code Playgroud)
查看完整源代码:https: //bitbucket.org/espinosa/z025-gwt-maven-alternative-setup/src/d35a3fb7e627b5598fb763f480e3f76932cf4232/src/main/java/my/code/z025/client/Dispatcher.java?at=master
在我的项目中,我使用GWT自己的EntryPoint作为标记接口.这使我只是通过URL来运行任意入口点:http://localhost:8080/my.code.client.Sample3; Dispatcher EntryPoint my.code.client.Sample3通过我的实例化实例化ClassFromStringFactory.只有Dispatcher入口点在GWT模块描述符和延迟绑定中配置,其他一切都是动态的.
好奇,这是我的ClassFromStringFactoryImpl的GWT(DevMode中的代码服务器或生产模式的编译器)生成的内容:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
在临时文件,如:C:\Users\espinosa\AppData\Local\Temp\my.code.client.reflection.ClassFromStringFactoryImpl4245548251877324156.java.
注意:仅在发生故障时生成此文件,而不是在成功编译时生成
如你所见,这并不是真正的内省.延迟绑定不会做任何特殊的魔法.类似的Java代码可以由Velocity模板生成,作为Maven构建的一部分或者像XText,APT-Jelly这样的特殊工具.使用GWT的Generator只是一种方便.
限制"受支持"类的数量很重要,否则生成的ClassFromStringFactoryImpl对于Java类来说太大,不切实际,甚至超出限制.某种过滤是必要的,标记接口只是一个选项,其他标记注释(请参阅GWT的JClassType#getAnnotation(Class))或仅标记选定的包.在任何情况下,确保此"反射"所支持的类的数量不超过数百.
非常感谢Ashwin Prabhu指出我正确的方向.
| 归档时间: |
|
| 查看次数: |
10534 次 |
| 最近记录: |