0

必要なときに「機能させる」だけの WELD の機能を利用するために作成した汎用 EL プロデューサーがあり、戻り値の型が確実に一致するように型強制を関数に書き込んでいます。溶接注入点。

ここに私の問題があります: WELD は、注入ポイントの割り当て可能な型から解決します。つまり、注入ポイントが文字列の場合、文字列の戻り値の型を持つプロデューサーのみを探します。

型強制を処理し、正しく型付けされたオブジェクトを返す 1 つのプロデューサーが必要なため、これには問題があります。

クラッジとして、実際のプロデューサーにエイリアスする String プロデューサー メソッドがあり、型クラッジングのみを行います。

これは...少なくとも、オブジェクト型の注入ポイントを持つ状況に到達するまでは機能します。その時点で、@Typedを使用しても、すべてのkludgeメソッドとジェネリックプロデューサーALLが一致し、あいまいな依存関係の例外が発生しますプロデューサーについて。

これを回避する正気の方法はありますか、それとも WELD にすべての面倒な作業を任せるというこの考えをあきらめるべきでしょうか?

Request スコープを持つエラー処理 Bean からの、このプロデューサーの使用例を次に示します。この場合、RequestURI が厄介です。他の 2 つは、型指定された「kludge」メソッドが機能する必要があります。この特定の Bean (コードは含まれていません) の主な機能は、未処理の例外をキャッチし、電子メールで報告して、将来の改訂でより具体的なエラー処理を行うことです。ここでの基本的な使用例は、EL へのプログラムによるアクセスを簡素化し、値バインディングを使用して EL に書き戻すことを可能にすることですが、この特定のコードではそれは不可能です。

他の方法を使用して以下を実行できることはわかっていますが、それは重要ではありません。現実的には、特に JSF 2.0 によって導入されたいくつかのよりエキゾチックなスコープ (特に Flash スコープ) を扱う場合に、IMO でプログラムから EL に簡単にアクセスできるようにすることは良いことです。私のユースケースのほとんどはFlashスコープに関係していますが、ここで開示するのは安全ではなく、予測可能な型でも、それらのために書かれたクラッジが必要な型でもないため、このより一般化された方法が必要な理由.

   @Inject
   @ELResource("#{requestScope['javax.servlet.error.exception']}")
   protected Exception exception;

   @Inject
   @ELResource("#{requestScope['javax.servlet.error.status_code']}")
   protected String statusCode;

   @Inject
   @ELResource("#{requestScope['javax.servlet.error.request_uri']}")
   protected Object requestUri;

ここに私の修飾子があります:

@Target(value = {ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface ELResource {
    @Nonbinding
    String value();
}

プロデューサー:

@Dependent
public class ELProducer {

    @Inject
    FacesContext facesContext;

    @Inject
    Logger log;

    @Produces
    @ELResource("")
    public Object getELResource(InjectionPoint ip) {
        log.entering(getClass().getName(), "getELResource()",new Object[] {ip});

        ExpressionFactory expFactory = facesContext.getApplication().getExpressionFactory();
        String elString = ip.getAnnotated().getAnnotation(ELResource.class).value();
        Class coercionType = resolveClass(ip);

        log.log(Level.INFO, "EL String: {0} of type: {1}", new Object[] {elString, coercionType.getName()});
        if (elString == null || elString.length() <= 0) {
            log.log(Level.SEVERE,"No EL String specified for injection");
            log.exiting(getClass().getName(), "getELResource()");
            return null;
        }

        ValueExpression ve = expFactory.createValueExpression(facesContext.getELContext(), elString, coercionType);

        if (ve != null) {
            Object retval = ve.getValue(facesContext.getELContext());
            log.log(Level.INFO,"EL Result: {0} of type: {1}",new Object[] { retval, ((retval != null) ? retval.getClass().getName() : "NULL") } );
            log.exiting(getClass().getName(), "getELResource()",new Object[] {retval} );
            return retval;
        } else {
            log.log(Level.WARNING,"Null EL Result");
            log.exiting(getClass().getName(), "getELResource()");
            return null;
        }
    }

    // TODO: There should be a better way of accomplishing the below
    @Produces
    @ELResource("")
    public String getELStringResource(InjectionPoint ip) {
        return (String)getELResource(ip);
    }

    @Produces
    @ELResource("")
    public Exception getELExceptionResource(InjectionPoint ip) {
        return (Exception)getELResource(ip);
    }

    private Class resolveClass(InjectionPoint ip) {
        Annotated annotated = ip.getAnnotated();
        Member member = ip.getMember();

        if (member instanceof Field) {
            Field field = (Field)member;
            return field.getType();
        } else if (member instanceof Constructor) {
            Constructor con = (Constructor)member;
            AnnotatedParameter ap = (AnnotatedParameter)annotated;
            return con.getParameterTypes()[ap.getPosition()];
        } else if (member instanceof Method) {
            Method method = (Method)member;
            AnnotatedParameter ap = (AnnotatedParameter)annotated;
            return method.getParameterTypes()[ap.getPosition()];
        } else {
            return null;
        }

    }
}

そしてエラー:

org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [Object] with qualifiers [@ELResource] at injection point [[field] @Inject @ELResource protected xxx.backing.ErrorHandler.requestUri]. Possible dependencies [[Producer Method [Exception] with qualifiers [@Any @ELResource] declared as [[method] @Produces @Typed @ELResource public xxx.ELProducer.getELExceptionResource(InjectionPoint)], Producer Method [String] with qualifiers [@Any @ELResource] declared as [[method] @Produces @Typed @ELResource public xxx.ELProducer.getELStringResource(InjectionPoint)], Producer Method [Object] with qualifiers [@Any @ELResource] declared as [[method] @Produces @Dependent @ELResource public xxx.ELProducer.getELResource(InjectionPoint)]]]
        at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:309)
        at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:139)
        at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:162)
        ...
4

1 に答える 1

1

他の方法を使用して以下を実行できることはわかっていますが、それは重要ではありません。

私は本当に一生懸命努力しましたが、型安全性を失っていること (これは CDI の主な設計目標の 1 つです) と、EL 評価がパフォーマンスキラーであることについてコメントせずにはいられませんでし... ;-)

とにかく、(ほとんどない)これを言った:

これを克服する実際の CDI オプションはありません。私がお勧めするのはElObject、プロデューサーによって構築され、それ自体がクライアントに型安全なアクセサーを提供する、EL 式などに特定の型を使用することです。

編集: EL機能をきちんと提供するSeam Solderを見たいと思うかもしれません...

于 2011-04-20T14:40:23.587 に答える