如何在gwt中从类名创建新实例

时间:2010-06-14 03:54:55

标签: gwt

我有一个类名为com.test.TestClass

的类

在我的代码中的某一点,我必须通过只有类名字符串来获取此类的实例。我尝试过使用GWT.create() 但它只在开发模式下工作。任何人都可以告诉我如何从类名中获取gwt中的实例。

3 个答案:

答案 0 :(得分:13)

由于客户端无法进行反射,因此模拟反射的唯一解决方案是使用延迟绑定。

使用延迟绑定在编译期间发现您希望使用类名实例化的所有类。您可以在所有这些类上使用标记接口来帮助TypeOracle识别这些。您动态生成工厂类,它接受类的简单名称并返回该类的新实例化对象。这种方法非常简单,您可以在谷歌的教程中找到延迟绑定的一个很好的解释。

修改: - 一些骨架代码可以帮助您入门。 (我的生产代码的精简版,检查生成的文件中的编译器错误!并调试流程)

首先> 将以下blurb添加到* .gwt.xml中,以便编译器调用我们的com.package.ReflectionGenerator,它将生成一个简单的工厂类来模仿客户端上的反射侧。

  <generate-with class="com.package.ReflectionGenerator">
      <when-type-assignable class="com.package.client.Reflection" />
  </generate-with>

下一步&gt; 为我们的工厂类定义接口

public interface Reflection {
    public <T, V extends T> T instantiate( Class<V> clazz );
}

上次&gt; 实施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( );
    }
}

这应该在工作区中生成工厂类ReflectionGenerator,检查生成的文件并调整源编写器代码以生成所需的代码。

用法GWT.create( Reflection.class ).instantiate( YourClass.class );

我在生成器中使用了标记接口'MarkerInterface'来限制工厂支持的类数,因此所有参与的类必须实现'MarkerInterface'

答案 1 :(得分:6)

这是经过充分测试,评论和稍微重构的Ashwin Prabhu代码版本:

https://bitbucket.org/espinosa/z025-gwt-maven-alternative-setup/src/d35a3fb7e627b5598fb763f480e3f76932cf4232/src/main/java/my/code/z025/util/ClassFromStringFactoryGenerator.java?at=master

使用示例:

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
}

查看完整源代码: 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运行任意EntryPoint:http://localhost:8080/my.code.client.Sample3; Dispatcher EntryPoint通过我的my.code.client.Sample3实例化ClassFromStringFactory。只有Dispatcher入口点在GWT模块描述符和延迟绑定中配置,其他一切都是动态的。

对于好奇,这里是GWT(DevMode中的代码服务器或生产模式的编译器)生成的,我的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;
  }
}

在像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指出我正确的方向。

答案 2 :(得分:2)

  

GWT.create(Reflection.class).instantiate(YourClass.class);

为什么不使用GWT.create( YourClass.class );

也许你会GWT.create( Reflection.class ).instantiate( "YourClass" );