如何在gwt的类名中创建新的实例 [英] How to create new instance from class name in gwt
问题描述
我有一个类int以下名称 com.test.TestClass
在我的代码中的某一点我必须通过只有类名字符串来获得此类的实例。我曾尝试使用 GWT.create()
但它只能在开发模式下工作。任何人都可以告诉我如何从类名获得gwt中的实例。
由于反射在客户端不可行,因此您必须模拟反射的唯一解决方案是使用延迟绑定。
使用延迟绑定在编译期间发现所有您希望用类名实例化的类。您可以在所有这些类上使用标记接口来帮助TypeOracle识别这些类。您可以动态生成一个工厂类,它接收该类的简单名称并返回该类的新实例化对象。这个方法非常简单,你可以在谷歌的教程中找到关于延迟绑定的一个很好的解释。
编辑:
一些骨架代码让你开始。 (剥离我的产品代码版本,检查生成的文件中的编译器错误并调试流程)
<为了让编译器调用我们的com.package.ReflectionGenerator,它将生成一个简单的工厂类,以模仿客户端的反射,将下面的blurb添加到* .gwt.xml中。 。
< generate-with class =com.package.ReflectionGenerator>
< when-type-assignable class =com.package.client.Reflection/>
< / generate-with>
下一步> 为我们的工厂类定义一个接口
public interface Reflection {
public< T,V extends T> T实例化(Class< V> clazz);
}
Last> 实现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;
导入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;
$ b $ 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());
列表< JClassType> clazzes = new ArrayList< JClassType>();
PropertyOracle propertyOracle = context.getPropertyOracle(); (JClassType classType:oracle.getTypes())
if(!classType.equals(instantiableType)&& classType.isAssignableTo(instantiableType))
clazzes.add(classType);
}
最终字符串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();
$ b $ private void printFactoryMethod(List< JClassType> clazzes,SourceWriter sourceWriter)
{
sourceWriter.println();
sourceWriter.println(public< T,V extends T> T instantiate(Class< V> clazz){); (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();
这应该在工作区中生成工厂类ReflectionGenerator,检查生成的文件并调整源代码编写器代码以生成您想要的代码。
用法 GWT.create(Reflection.class).instantiate(YourClass.class);
我在生成器中使用了一个标记接口'MarkerInterface'
来限制工厂支持的类的数量,因此结果所有参与的类必须实现'MarkerInterface'
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 string. I have tried using GWT.create()
But it is working only in dev mode. Can any one tell me how to get instance in gwt from class name.
解决方案 Since reflection is not possible on the client side, the only solution you have to mimic reflection is using deferred binding.
Use deferred binding to discover all classes you wish to instantiate with the class name during compile time. You may use a marker interface on all such classes to aid TypeOracle to identify these. You dynamically generate a factory class, which takes in the simple name of the class and returns a newly instantiated object of that class. The approach is very straight forward and you will find a good explanation of deferred binding in google's tutorials to boot.
Edit:-
Some skeletal code to get you started. (Stripped down version of my production code, check for compiler errors in the generated file! and debug the flow)
First> Add the following blurb into your *.gwt.xml, to so that the compiler invokes our com.package.ReflectionGenerator, which will generate a simple factory class to mimic reflection on the client side.
<generate-with class="com.package.ReflectionGenerator">
<when-type-assignable class="com.package.client.Reflection" />
</generate-with>
Next> Define an interface for our factory class
public interface Reflection {
public <T, V extends T> T instantiate( Class<V> clazz );
}
Last> Implement 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( );
}
}
This should generate the factory class ReflectionGenerator in your workspace, check the generated file and tweak the source writer code to generate the code you desire.
Usage GWT.create( Reflection.class ).instantiate( YourClass.class );
I have used a marker interface 'MarkerInterface'
in the generator to restrict the number of classes supported by the factory, hence as a result all the participating classes must implement 'MarkerInterface'
这篇关于如何在gwt的类名中创建新的实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!