15

GWT.create() は GWT のリフレクションに相当しますが、クラス名の完全修飾文字列ではなく、クラス リテラルのみを取ります。GWT.create() を使用して文字列を持つクラスを動的に作成するにはどうすればよいですか?

多くの GWT フォーラムの投稿によると、それは不可能ですが、Rocket-GWT ( http://code.google.com/p/rocket-gwt/wiki/Ioc ) や Gwittir ( http://code .google.com/p/gwittir/wiki/内省)

4

9 に答える 9

13

トリッキーですが、可能です。悲惨な詳細は次のとおりです。

GWT を Java から JS へのストレートなものとしか考えていないと、うまくいきません。ただし、GWT コンパイラを使用した特別なクラスのジェネレーターを考慮すれば、コンパイル中にコンパイルおよび実行される可能性があります。したがって、コンパイル中でも Java ソースを生成できます。

私は今日これを必要としていました - 私たちのシステムは、サービスから離れた動的リソースを処理し、文字列とクラスの必要性に終わります。これが私が思いついた解決策です-ところで、ホストされたIEおよびFirefoxで動作します。

  • 以下を宣言する GWT モジュールを作成します。
    • ソース パス
    • ジェネレーター ( GWT モジュール ソース パスのパッケージの外部に保持する必要があります)
    • インターフェイスの置き換え (インターフェイスの代わりに Generated クラスを挿入します)
  • そのパッケージ内で、Marker インターフェイスを作成します (私はそれを Constructable と呼びます)。ジェネレーターはそのマーカーを検索します
  • そのファクトリを保持する基本抽象クラスを作成します。生成されたソースコードを簡単にするためにこれを行います
  • Application.gwt.xml を継承するモジュールを宣言します。

いくつかのメモ:

  • 理解の鍵は、ジェネレーターの概念にあります。
  • 簡単にするために、Abstract 基底クラスが役に立ちました。
  • また、生成された .js ソースや、生成された Java ソースにも名前マンドリングがあることを理解してください。
  • Generator が Java ファイルを出力することを思い出してください。
  • GWT.create には、.class ファイルへの参照が必要です。ジェネレーターの出力は、アプリケーションから何らかの方法で参照されている限り、それを行う可能性があります ( Application.gwt.xml がモジュールを継承していることを確認してください。これにより、 Application.gwt.xml が宣言するジェネレーターとのインターフェイスも置き換えられます)。
  • GWT.create 呼び出しをファクトリ メソッド/シングルトン内にラップし、GWT.isClient() の下にもラップします。
  • モジュールのロードをトリガーする必要がある場合があるため、code-class-loading-calls を GWT.runAsync にラップすることも非常に良い考えです。これは非常に重要です。

近いうちにソースコードを投稿したいと思います。指を交差させます。:)

于 2010-02-24T21:42:15.590 に答える
5

ブライアン、

問題は、GWT.create が抽象クラスの適切な実装を選択する方法を知らないことです。

新しい GWT MVP コーディング スタイルでも同様の問題がありました ( GWT MVP のドキュメントを参照) 。

私が電話したとき:

ClientFactory clientFactory = GWT.create(ClientFactory.class);

同じエラーが発生しました:

据え置きバインディングの結果タイプ 'com.test.mywebapp.client.ClientFactory' は抽象であってはなりません

私がしなければならなかったのは、MyWebapp.gwt.xml ファイルに次の行を追加することだけでした。

<!-- Use ClientFactoryImpl by default -->
    <replace-with class="com.test.mywebapp.client.ClientFactoryImpl">
    <when-type-is class="com.test.mywebapp.client.ClientFactory"/>
    </replace-with>

その後、それは魅力のように機能します

于 2010-11-14T17:27:10.600 に答える
5

私は今日これに遭遇し、解決策を見つけました。質問者は基本的に、次のようなメソッドを書きたいと考えています。

public <T extends MyInterface> T create(Class<T> clz) {
    return (T)GWT.create(clz);
}

ここで MyInterface は、動的に生成できるようにしたいクラスの範囲を定義する単なるマーカー インターフェイスです。上記をコーディングしようとすると、エラーが発生します。秘訣は、次のような「インスタンス化子」を定義することです。

public interface Instantiator {
    public <T extends MyInterface> T create(Class<T> clz);
}

次に、上記のインスタンスを返す GWT 遅延バインディング ジェネレーターを定義します。ジェネレーターで、TypeOracle にクエリを実行して MyInterface のすべての型を取得し、他の型の場合と同様にそれらの実装を生成します。

例えば:

public class InstantiatorGenerator extends Generator {

public String generate(...) {
   TypeOracle typeOracle = context.getTypeOracle();
   JClassType myTYpe= typeOracle.findType(MyInterface.class.getName());

    JClassType[] types = typeOracle.getTypes();
    List<JClassType> myInterfaceTypes = Collections.createArrayList();

    // Collect all my interface types.
    for (JClassType type : types) {
        if (type.isInterface() != null && type.isAssignableTo(myType)
                && type.equals(myType) == false) {
            myInterfaceTypes.add(type);
        }
        for (JClassType nestedType : type.getNestedTypes()) {
            if (nestedType.isInterface() != null && nestedType.isAssignableTo(myType)
                    && nestedType.equals(myTYpe) == false) {
                myInterfaceTypes.add(nestedType);
            }
        }
    }

    for (JClassType jClassType : myInterfaceTypes) {
        MyInterfaceGenerator generator = new MyInterfaceGenerator();
        generator.generate(logger, context, jClassType.getQualifiedSourceName());
    }
 }

 // Other instantiator generation code for if () else if () .. constructs as 
 // explained below.
}

MyInterfaceGenerator クラスは、他の遅延バインディング ジェネレーターと同じです。GWT.create 経由ではなく、上記のジェネレーター内で直接呼び出すことを除いて。MyInterface のすべての既知のサブタイプの生成が完了したら (ジェネレーターで MyInterface のサブタイプを生成するときは、クラス名が MyInterface.class.getName() + "_MySpecialImpl" などの一意のパターンを持つようにしてください)。 、 MyInterface のすべての既知のサブタイプを再度繰り返し、一連のサブタイプを作成することにより、単純に Instantiator を作成します

if (clz.getName().equals(MySpecialDerivativeOfMyInterface)) { return (T) new MySpecialDerivativeOfMyInterface_MySpecialImpl();}

コードのスタイル。最後に例外をスローして、すべての場合に値を返すことができるようにします。

GWT.create(clz);代わりに、次のように呼び出します。

private static final Instantiator instantiator = GWT.create(Instantiator.class);
...
return instantiator.create(clz);

また、GWT モジュール xml では、MyInterface ジェネレーターではなく、Instantiator のジェネレーターのみを定義することに注意してください。

<generate-with class="package.rebind.InstantiatorGenerator">
    <when-type-assignable   class="package.impl.Instantiator" />
</generate-with>

ビンゴ!

于 2011-12-12T20:09:00.600 に答える
4

質問は正確には何ですか-クラスリテラルに加えてパラメーターをジェネレーターに渡したいと思います。

おそらくすでにご存じのとおり、GWT.create() に渡されるクラス リテラルはほとんどがセレクタであるため、GWT は最終的にクラスを吐き出すジェネレータを選択して実行できます。パラメーターをジェネレーターに渡す最も簡単な方法は、インターフェースでアノテーションを使用し、interface.class を GWT.create() に渡すことです。もちろん、インターフェイス/クラスは、GWT.create() に渡されたクラス リテラルを拡張する必要があることに注意してください。

class Selector{
}

@Annotation("string parameter...")
class WithParameter extends Selector{}

Selector instance = GWT.create( WithParameter.class )
于 2009-01-31T02:58:32.063 に答える
2

クラスをロードしてイベントに動的にバインドするという、あなたがやろうとしていると思うことを行うことができました。ジェネレーターを使用して、クラスをイベントに動的にリンクしました。私はそれをお勧めしませんが、これが役立つ場合の例を次に示します。

http://francisshanahan.com/index.php/2010/a-simple-gwt-generator-example/

于 2010-04-09T23:57:29.353 に答える
2

すべてが可能です..難しいかもしれませんが、役に立たないかもしれません. Jan が述べたように、そのためにはジェネレーターを使用する必要があります。基本的に、そのインターフェイスを使用して作成時にコンパイルし、インスタンスを返すジェネレーターコードでインターフェイスを作成できます。例は次のとおりです。

//A marker interface
public interface Instantiable {
}
//What you will put in GWT.create
public interface ReflectionService {
 public Instantiable newInstance(String className);
}
//gwt.xml, basically when GWT.create finds reflectionservice, use reflection generator
<generate-with class="...ReflectionGenerator" >
<when-type-assignable class="...ReflectionService" />
</generate-with>  
//In not a client package
public class ReflectionGenerator extends Generator{
...
}
//A class you may instantiate
public class foo implements Instantiable{
}
//And in this way
ReflectionService service = GWT.create(ReflectionService.class);
service.newInstance("foo");

知っておく必要があるのは、ジェネレーターの実行方法だけです。最後に、ジェネレーターで行うことは、次のような方法で Java コードを作成することです。

if ("clase1".equals(className)) return new clase1();
else if ("clase2".equals(className)) return new clase2();
...

最後に、一種の InstanceFactory で手動でそれを行うことができると思いました...よろしくお願いします

于 2009-09-08T19:52:26.620 に答える
1

あなたがやろうとしていることはGWTでは不可能です。

GWTはコンパイル時にJavaをエミュレートするのに優れていますが、実行時間はもちろん完全に異なります。ほとんどのリフレクションはサポートされておらず、実行時にクラスを生成したり動的にロードしたりすることはできません。

Gwittirのコードを簡単に調べたところ、コンパイル時に「リフレクション処理」を行っていると思います。ここで:http ://code.google.com/p/gwittir/source/browse/trunk/gwittir-core/src/main/java/com/totsp/gwittir/rebind/beans/IntrospectorGenerator.java

于 2009-06-18T09:18:38.903 に答える
1

ロケット/gwittir のコード (彼らがどのようにそれを行ったかを知りたい場合は、これを実行する必要があります。結局のところ、それはオープンソースです) を調べていないので、コンパイル中にその後、リフレクションへのすべての呼び出しを実行し、それらの呼び出しを実装するために必要なすべてのコードを静的に生成します。そのため、実行時に別のことを行うことはできません。

于 2009-01-18T10:26:11.670 に答える