8

JSF /JavaEEアプリケーションにCDIを使用しようとしています。次のクラス階層があります。

/**
 * base controller class
 * also contains some final methods and an inner enum class declaration
 */
public abstract class AbstractCrudController<K, E> implements Serializable {
  private Class<E> entityClass;

  public AbstractCrudController(Class<E> entityClass) {
    this.entityClass = entityClass;
  }

  // ...
}


import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named
@SessionScoped
public class CategoryController extends AbstractCrudController<Long, Category> implements Serializable {
  public CategoryController() {
    super(Category.class);
  }
  //...
}

アプリケーションをGF3.1にデプロイしようとすると、次のCDI/Weld例外が発生します。

重大:アプリのロード中の例外:WELD-001435通常のスコープのBeanクラスcom.web.AbstractCrudControllerは、引数なしのコンストラクターがないため、プロキシできません。org.jboss.weld.exceptions.UnproxyableResolutionException:WELD-001435通常のスコープのBeanクラスcom.web.AbstractCrudControllerは、引数なしのコンストラクターがないため、プロキシ可能ではありません。org.jboss.weld.util.Proxies.getUnproxyableClassException(Proxies.java:215)at org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.java:166)at org.jboss.weld.util.Proxies.getUnproxyableTypesException (Proxies.java:191)org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:134)、org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:148)、org.jboss。 weld.bootstrap.Validator。

基本クラスに引数なしのコンストラクターを追加しても、Weldは、finalメソッドがあるため、クラスがプロキシ可能ではないという同じ例外を除いて文句を言います。WELDがクラスの設計を変更するように強制するのはなぜですか?JSF@ManagedBeanアノテーションを使用するとすべてが正常に機能しました。

助けていただければ幸いです。ありがとう、テオ

4

3 に答える 3

16

WELDがクラスの設計を変更するように強制するのはなぜですか?JSF@ManagedBeanアノテーションを使用するとすべてが正常に機能しました。

まあ、Weld/CDIは同じようには機能しません。私の理解では、インジェクションを使用してBeanへの参照を取得すると、ほとんどの場合、取得されるのはプロキシオブジェクトです。このプロキシオブジェクトは、Beanをサブクラス化し、委任を実装するためのメソッドをオーバーライドします。そして、これにより、CDIがプロキシできるクラスにいくつかの制限が導入されます。

CDI仕様では、次のようになっています。

5.4.1。プロキシできないBeanタイプ

特定の正当なBeanタイプは、コンテナによってプロキシできません。

  • パラメータのない非プライベートコンストラクタを持たないクラス、
  • finalと宣言されたクラス、またはfinalメソッドを持つクラス。
  • プリミティブ型、
  • および配列型。

宣言されたタイプがコンテナによってプロキシできないインジェクションポイントが通常のスコープのBeanに解決されると、コンテナは自動的に問題を検出し、それをデプロイメントの問題として扱います。

私の提案は、メソッドを非最終的なものにすることです。

参考文献

  • CDI仕様
    • セクション5.4。「クライアントプロキシ」
    • セクション5.4.1「プロキシできないBeanタイプ」
    • セクション6.3。「通常のスコープと疑似スコープ」
于 2010-10-01T15:28:24.487 に答える
0

JSFマネージドBeanからCDIマネージドBeanに移行中ですが、祖先CDIBeanを「拡張」する子孫CDIBean(「カスタム」@Descendant修飾子を使用)で非常にうまく使用できることを確認しました。 (@Default修飾子を使用)。

@Default修飾子を持つCDIBeanの祖先:

@Default
@Named("pf_pointOfContactController")
@SessionScoped
public class pf_PointOfContactController implements Serializable {

祖先Beanには次のものがあります。

@PostConstruct
protected void init() {

@Descendant修飾子を持つCDIBeanの子孫:

@Descendant
@Named("pf_orderCustomerPointOfContactController")
@SessionScoped
public class pf_OrderCustomerPointOfContactController extends pf_PointOfContactController {

子孫Beanには次のものがあります。

@PostConstruct
public void init(){
    super.init();

祖先CDIBeanの@PostConstructはCDI@DescendantBeanで実行されないため、祖先CDI BeanのメソッドがNullPointerExceptionを発生させていたため、super.init()を追加/使用する必要がありました。

CDIを使用する場合は、Constructorメソッドの代わりに@PostConstructを使用することをお勧めします。そのため、祖先Beanのコンストラクターには「初期化」ロジックがあり、JSFマネージドBeanを使用すると、祖先Beanのコンストラクターが自動的に呼び出され/実行されます。

于 2012-11-21T09:09:49.950 に答える
0

受け入れられた答えは正しいが不完全なので、将来の読者のためだけに2セントを追加できると思います。

OPが遭遇した問題は、次の2つの方法で解決できます。

  1. finalメソッドとクラス自体からキーワードを削除する
  2. そのような「プロキシ不可能なクラス」を@Singletonまたは@Dependent疑似スコープでマークする(もちろん、それが理にかなっている場合)。CDIは疑似スコープBeanのプロキシオブジェクトを作成しないため、これは機能します。

OPのユースケースでは、コントローラーをシングルトンとしてマークできるため、2番目のアプローチであるIMHOが推奨されました。

それが誰かを助けることを願っています

于 2015-11-11T19:27:55.477 に答える