2011-04-15 23 views
0

我有一个通用的EL生产者,我写了这个来利用WELD的功能,当我需要它的时候使它“工作”,甚至把类型强制写入函数,以确保返回类型匹配焊接注入点。如何解决与WELD一起使用EL Resolver时的类型差异?

这是我的问题: WELD从注入点的可指定类型中解析出来,也就是说,如果您的注入点是一个字符串,它只会查找具有字符串返回类型的生产者。

这是有问题的,因为我想让一个生产者负责类型强制转换,并且返回一个正确类型的对象。

作为一个kludge,我有一个字符串生产者方法,别名到真正的生产者,只做类型kludging。

这个......至少可以工作,直到我开始有一个Object类型注入点的情况,在这一点上,我的所有kludge方法和泛型生成器ALL都匹配,给出了一个模糊的依赖异常,即使我在制作人上使用@Typed。

有没有一种合理的解决方法,还是我应该放弃这个让WELD为我做好所有努力的想法?

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

我知道我可以用其他方法做下面的事情,那不是重点。实际上,让程序化访问EL更容易,尤其是在处理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) 
     ... 
+0

你能描述一下你想达到什么样的? EL-注射的一个或两个例子用法是很好的。 – 2011-04-15 05:03:28

回答

1

I know I can do the below using other methods, that's not the point.

我努力尝试,但我做了而不是管理而不是评论说你正在失去类型安全(这是CDI的主要设计目标之一),并且EL评估是性能杀手...; )

总之,有(几乎没有)对此表示:

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

编辑:你可能想看看Seam Solder,它提供了一个整洁的方式EL-功能...

+0

Seam Solder功能与我想要的非常接近,只是缺少在注射时自动完成此操作的最后一步。尽管我现在可能已经尽可能地接近了,所以我很欣赏这个建议。 – SplinterReality 2011-04-26 07:32:36