2010-06-14 32 views
6

創建從類名新實例有一個類int以下名稱com.test.TestClass我如何在GWT

在我的代碼一點我有隻具有類名稱的字符串獲得這個類的實例。我曾嘗試使用GWT.create() 但它只能在開發模式下工作。任何人都可以告訴我如何從類名獲得gwt中的實例。

+0

看起來像一個副本http://stackoverflow.com/questions/451658/gwt-dynamic-loading-using-gwt-create-with-string-literals-instead-of-class-lite – 2010-06-14 03:58:00

+0

Thanks.I am也期待相同。 – DonX 2010-06-14 04:03:54

回答

11

由於反射在客戶端是不可能的,因此您必須模擬反射的唯一解決方案是使用延遲綁定。

使用延遲綁定在編譯期間發現您希望用類名實例化的所有類。您可以在所有這些類上使用標記接口來幫助TypeOracle識別這些類。您可以動態生成一個工廠類,它接收該類的簡單名稱並返回該類的新實例化對象。這個方法非常簡單,你可以在谷歌的教程中找到關於延遲綁定的一個很好的解釋。

編輯: - 一些骨架代碼讓你開始。 (剝離下來的我的生產代碼版本,爲您在生成文件編譯器錯誤!和調試流程)

首先>添加下面的Blurb到您的* .gwt.xml,以使編譯器調用我們的com.package.ReflectionGenerator,它將生成一個簡單的工廠類來模仿客戶端的反射。

<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 instantiate(Class<V> clazz); 
} 

末>實施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,檢查生成的文件並調整源代碼編寫器以生成co你想要什麼。

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

我已經使用一個標記接口'MarkerInterface'在發電機以限制由工廠支持的類的數量,因此,其結果是所有參與的類必須實現'MarkerInterface'

+0

非常感謝。如果您可以發佈示例代碼,它對我和其他用戶都非常有用。 – DonX 2010-07-05 12:01:58

+0

我編輯了我的回覆帖子,展示了使用綁定的骨架代碼。請通過,如果偶然發生編譯錯誤或兩次錯誤,請原諒我,我沒有通過編譯器運行代碼。我太懶了:P – 2010-07-12 10:17:07

2

GWT。創建(Reflection.class).instantiate(YourClass.class);

爲什麼你不使用,然後只是GWT.create(YourClass.class);

也許你換貨GWT.create(Reflection.class).instantiate("YourClass");

5

這裏是很好的測試,評價和阿斯溫帕布代碼稍微重構版本:

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通過我的ClassFromStringFactory實例化my.code.client.Sample3。只有調度程序入口點在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的發生器只是一個方便。

限制「受支持」類的數量是很重要的,否則生成的ClassFromStringFactoryImpl將會太大,實際上太大或甚至超過Java類的限制。某些過濾是必要的,標記接口只是一個選項,其他標記則標記註釋(請參閱GWT的JClassType#getAnnotation(Class))或僅選擇包。無論如何,通過這個「反射」來確保支持的類的數量不會超過數百個。

非常感謝Ashwin Prabhu爲我指出了正確的方向。