2

プロジェクトにCDI(Weld)を導入したかったのですが、手動で作成されたオブジェクトで問題が発生しました。

したがって、インターフェイスを実装するクラスがいくつかIReportあり、注入する必要のあるフィールドがあります。これらのクラスはすべて、クラスReportFactory内のによって生成されているため、これは実行時にnullになりますReportController

private Map<String,Object> generateReport(ReportInfo ri, ...) {
// some input validation
    IReport report = ReportControllerFactory.getReportInstance( ri.getClassName() );
// ...
}

@Producesでアノテーションを別のカスタムアノテーションと一緒に使用できることは知っていますが、メソッドで検証が行われた後にのみ作成できる変数ReportControllerFactoryにを使用するにはどうすればよいですか?そして、どのようにパラメータを送信しますか?が構築されたとき、オブジェクトは不明です。@Injectri.getClassName()riReportController

どうもありがとうございます!

よろしく、セバスチャン

2011年7月8日(10:00)に編集:

ReportFactoryクラス:

public static IReport getReportInstance( String className ) throws ReportException {

    IReport report = null;

    try {
        Class<?> clazz = Class.forName( className );
        report = (IReport) clazz.newInstance();
    }
    catch ( Exception e ) { … }        

    return report;
}

編集2(適切なレポート実装の選択)

レポートインスタンスは、JSFフロントエンドからReportControllerに向かういくつかのパスによって選択されます。ManagedBeanは、どのボタンがどこで押されたかに応じて、いくつかのメソッドを持つセッションBeanを呼び出します。これらのメソッドはすべて、レポート名を設定し、より一般的なメソッドを呼び出しますsendOrGetReport。このメソッドは、指定されたレポートの一意のキーをデータベースから選択し、電子メールを送信するか、すぐにレポートを配信するかを決定します。配達されるべきだとしましょう。

次に、ReportControllerが登場します。ReportInfo彼は、上記のメソッドによって提供された一意のキーとその他の情報に基づいてオブジェクトをフェッチし、を呼び出してReportFactoryタイプのレポートを作成しますri.getClassName()

ファンシーですね このセクション全体でリファクタリングが必要になると思います。簡単な場所が見つからない場合は@Inject、レポートの実装をスキップして、そのリソースのJDNIルックアップを実行します。

4

3 に答える 3

12

適切なレポートクラスを動的に作成するために、受け入れられた回答に小さな変更を加えると問題が解決します。解決策は、Instance<...>が特定のタイプのすべてのBeanのリストを提供するという事実です。生成アノテーションは必要ありません。

実行時に注入されたインスタンスから選択できるファクトリクラスを作成します

public class ReportFactory {

@Inject Instance<IReport> availableReports;

public IReport createReport(String type) {

   for (IReport report: availableReports) {
      if (report.getType().equals(type)) { //or whatever test you need
         return report;
      }
   }
   return null;
}

これで、動的に選択されたレポートが必要なクラスは、このファクトリを使用できます。

public class ReportCreator {

    @Inject
    private ReportFactory reportFactory;

    public void createReport(String type) {
        IReport report = reportFactory.createReport(type);
        report.execute();
    }
 }
于 2011-09-13T10:54:34.267 に答える
8

依存関係を管理するためのCDI(およびその他のDIフレームワーク)の背後にある考え方は、管理対象Beanのライフサイクルの制御を引き継ぐことです。これは、特に、コンテナによって管理されるようにしたい場合は、管理対象Beanの作成を妨害できないことを意味します。

確かに、これはあなたのシナリオが解決できないことを意味するのではなく、あなたはあなたの視点を少し変える必要があります;-)

アイデアは(明らかに)マネージドBeanを操作することですが、使用可能なすべてのインスタンスのどのインスタンスが正しいかを独自のロジックに決定させます。

...
@Inject Instance<IReport> availableReports;
...
@Produces
public IReport createReport() {
   IReport result;
   for (IReport report: availableReports) {
      // choose correct instance, you might want to query the injection
      // point or any attached qualifier a bit more in order to 
      // determine which is the correct instance
      if ...
         result = report;
      ...
   }
   return result;
}
...

BeantypeIReportのBeanを好きなだけ使用できます

public class AReport implements IReport {
...
@Inject
...
}

public class BReport implements IReport {
...
@Inject
...
}

そして、このような自動魔法の使用法

public class MyStuff {
...
@Inject
IReport myReport;
...
}

詳細については、ここここを参照してください。

私があなたの問題を誤解していなかったなら、これはあなたを前進させるはずです-さらなる質問/コメントを投稿してください。

更新

このようなものがあなたの要件に合うなら、すべてがまったく単純かもしれません:

@AReport
public class AReport implements IReport {
...
@Inject
...
}

@BReport
public class BReport implements IReport {
...
@Inject
...
}

このような使い方で

public class MyStuff {
...
@Inject
@AReport
IReport myAReport;
...
@Inject
@BReport
IReport myBReport;
...
}
于 2011-07-08T08:37:48.880 に答える
1

わかりました。私が間違っていなければ、ドキュメントに基づいています(これは適切なフレームワークですか?http://docs.jboss.org/seam/3/latest/reference/en-US/html/solder-beanmanagerprovider。 html)、ファクトリはBeanManagerシングルトンへのハンドルを取得する必要があり(それを注入するか、フレームワークからアクセサを呼び出す)、次の行に沿って何かを実行する必要があります。

Class<?> clazz = Class.forName( className );
report = beanManager.getBean(clazz);

CDIが可能なクラス名のそれぞれを処理するように構成されていると仮定すると、正しいBeanを取得する必要があります。これで、これは常に同じインスタンスになる可能性があります。これがあなたに必要なものかどうかわかりません、ごめんなさい。

間違えたらごめんなさい; それが役立つことを願っています。

于 2011-07-08T08:32:51.203 に答える