0

我有一个通用的 EL 生产者,我编写它以利用 WELD 的能力,在我需要它完成时“让它工作”,甚至将类型强制写入函数中,以确保返回类型与焊接注射点。

这是我的问题:WELD 从注入点的可分配类型解析,即,如果您的注入点是一个字符串,它只会寻找具有字符串返回类型的生产者。

这是有问题的,因为我想要一个负责类型强制的生产者,并交还一个正确类型的对象。

作为一个 kludge,我有一个 String 生产者方法,它别名为真正的生产者,并且只做类型 kludging。

这...至少有效,直到我遇到对象类型注入点的情况,此时我的所有 kludge 方法和通用生产者 ALL 都匹配,即使我使用 @Typed 也会给出模棱两可的依赖异常对生产者。

有没有一种理智的方法可以解决这个问题,还是我应该放弃让 WELD 为我完成所有艰苦工作的想法?

这是一个使用此生产者的示例,来自具有请求范围的错误处理 bean。RequestURI 在这种情况下很麻烦,另外两个需要键入的“kludge”方法才能工作。这个特定 bean(不包括代码)的主要功能是捕获未处理的异常并通过电子邮件将它们报告给我们,以便在未来的修订中进行更具体的错误处理。这里的基本用例是简化对 EL 的编程访问,并可能允许使用值绑定写回 EL,尽管这在此特定代码中是不可能的。

我知道我可以使用其他方法执行以下操作,这不是重点。实际上,以编程方式更容易地访问 EL IMO 是一件好事,尤其是在处理 JSF 2.0 引入的一些更奇特的作用域(尤其是 Flash 作用域)时。我的大多数用例都与 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 的主要设计目标之一),并且 EL 评估是性能杀手...... ;-)

无论如何,已经(几乎没有)这样说:

没有真正的 CDI 选项可以克服这一点。我建议您为这些 EL 表达式使用特定类型,例如ElObject,它由生产者构造,并且它本身为客户端提供类型安全的访问器。

编辑:您可能想看看Seam Solder,它以一种简洁的方式提供 EL 功能......

于 2011-04-20T14:40:23.587 回答