【问题标题】:CDI injection of types in heirarchy层次结构中类型的 CDI 注入
【发布时间】:2017-11-19 12:19:51
【问题描述】:

我有一个超类型 (CaseDTO),其中包含我想要注入的几个子类型 (GroupCaseDTO、IPCaseDTO)。开发环境为 JDev 12c。

这里是两个注入点:

  1. 注入超类型(此注入点适用于两种子类型):

    @Inject @CaseContext 私人案例DTO muwCase;

  2. 注入特定的子类型(此注入点仅适用于一个子类型):

    @Inject @CaseContext 私有 GroupCaseDTO muwCase;

为了获得这些值,我尝试设置了一些生产者方法:

// supertype
@Produces @CaseContext
public CaseDTO getContextCase()  {
    return JSFUtils.getFromPageFlowScope("case", CaseDTO.class);
}

// subtype 1
@Produces @CaseContext
public IPCaseDTO getContextIpCase()  {
    return JSFUtils.getFromPageFlowScope("case", IPCaseDTO.class);
}

// subtype 2
@Produces @CaseContext
public GroupCaseDTO getContextGroupCase()  {
    return JSFUtils.getFromPageFlowScope("case", GroupCaseDTO.class);
}

问题是,如果我只包含超类型生产者方法,那么子类型注入点不起作用:

:org.jboss.weld.exceptions.DeploymentException:WELD-001408: Unsatisfied dependencies for type GroupCaseDTO with qualifiers @CaseContext
at injection point [BackedAnnotatedField] @Inject @CaseContext private ca.bluecross.ab.muw.view.controller.decision.ManageGrpDecisionController.muwCase
at ca.bluecross.ab.muw.view.controller.decision.ManageGrpDecisionController.muwCase(ManageGrpDecisionController.java:0)
WELD-001475: The following beans match by type, but none have matching qualifiers:
- Managed Bean [class ca.bluecross.ab.muw.model.type.dto.grp.GroupCaseDTO] with qualifiers [@Any @Default]

但是如果我包含所有三个生产者方法,我会在超类型注入点上得到这个异常:

:org.jboss.weld.exceptions.DeploymentException:WELD-001409: Ambiguous dependencies for type CaseDTO with qualifiers @CaseContext
at injection point [BackedAnnotatedField] @Inject @CaseContext private ca.bluecross.ab.muw.view.controller.UploadAssociatedDocumentController.muwCase
at ca.bluecross.ab.muw.view.controller.UploadAssociatedDocumentController.muwCase(UploadAssociatedDocumentController.java:0)
Possible dependencies: 
  - Producer Method [CaseDTO] with qualifiers [@CaseContext @Any] declared as [[BackedAnnotatedMethod] @Produces @CaseContext public ca.bluecross.ab.muw.view.util.DataContextHelper.getContextCase()],
  - Producer Method [GroupCaseDTO] with qualifiers [@CaseContext @Any] declared as [[BackedAnnotatedMethod] @Produces @CaseContext public ca.bluecross.ab.muw.view.util.DataContextHelper.getContextGroupCase()],
  - Producer Method [IPCaseDTO] with qualifiers [@CaseContext @Any] declared as [[BackedAnnotatedMethod] @Produces @CaseContext public ca.bluecross.ab.muw.view.util.DataContextHelper.getContextIpCase()]

只有两个子类型生产者方法也不起作用:

:org.jboss.weld.exceptions.DeploymentException:WELD-001409: Ambiguous dependencies for type CaseDTO with qualifiers @CaseContext
  at injection point [BackedAnnotatedField] @Inject @CaseContext private ca.bluecross.ab.muw.view.controller.UploadAssociatedDocumentController.muwCase
  at ca.bluecross.ab.muw.view.controller.UploadAssociatedDocumentController.muwCase(UploadAssociatedDocumentController.java:0)
  Possible dependencies: 
  - Producer Method [GroupCaseDTO] with qualifiers [@CaseContext @Any] declared as [[BackedAnnotatedMethod] @Produces @CaseContext public ca.bluecross.ab.muw.view.util.DataContextHelper.getContextGroupCase()],
  - Producer Method [IPCaseDTO] with qualifiers [@CaseContext @Any] declared as [[BackedAnnotatedMethod] @Produces @CaseContext public ca.bluecross.ab.muw.view.util.DataContextHelper.getContextIpCase()]

我想我可以通过为我需要的每个子类型使用限定符注释来解决这个问题,但这似乎太过分了。如果没有大量限定符注释,就没有办法让注入工作吗?

事实上,这就是我想要的:一个生产者方法 + 一个限定符注释,它允许我注入上下文案例,而不管它是什么子类型。同样,我认为 CDI 不可能做到这一点,因为它(太)是强类型的。

【问题讨论】:

    标签: java dependency-injection cdi jsf-2.2 oracle-adf


    【解决方案1】:

    我想你可能误解了typesafe resolution mechanism。 CDI 注入基于拥有一组 bean(在您的情况下,是它们的生产者)和一组注入点(又名 IP;您 @Inject 的位置)。现在这两个都有特定的类型和限定符集

    为了注入 IP,您需要有一个包含 必需类型的 bean,并且所有请求的限定符都是 bean 提供的限定符的子集。。 p>

    Bean types, in case of producers,是从方法的返回类型派生的。在您的情况下,它将是类、每个超类和所有实现的接口(无论是直接还是间接)。

    因此,在您的代码示例中,如果您只是 @Inject CaseDTO,您将收到 Ambiguous dependency 异常 - 所有三个生产者都会生成一个 bean,在其他类型中还包含 CaseDTO

    另一方面,获得Unsatisfied dependency 异常意味着您没有适合这种注入点的bean。在您的示例中,只有超类型生产者意味着 @Inject GroupCaseDTO 将失败并出现此异常,因为 GroupCaseDTO 不在生产者创建的 bean 类型中。

    至于您的问题的解决方案 - 您肯定可以使用限定符。这解决了注入超类型的问题。 @maress 在另一个答案中的建议也是一个好主意(例如,没有新的限定符并在现有的限定符中使用一个值)

    其实我想要的是:一种生产者方法+一种限定符 允许我注入上下文案例的注释

    您可以使用一个限定符给出不同的结果,但您需要根据其他属性来确定您想要哪一个。例如。你可以:

    @Produces
    @CaseContext
    public CaseDTO produce() {
      if (methodToDetermineConfiguration()) {
        return JSFUtils.getFromPageFlowScope("case", IPCaseDTO.class);
      } else {
        return JSFUtils.getFromPageFlowScope("case", GroupCaseDTO.class);
      }
    }
    

    当然,您需要以某种方式定义methodToDetermineConfiguration() 才能知道您真正想要生成什么。不确定您有哪些选择,只是分享有关如何设置制作人的信息。

    【讨论】:

    • 你的建议是不是和我第一个失败的场景一模一样:只包括超类型生产者?
    • CDI/WELD 在确定类型匹配时是否查看生产者方法的返回类型?或者它看起来是方法中的返回语句?如果是后者,那会让我大吃一惊:)
    • 这与您的第一个不同,我试图向您解释这是如何工作的,以便您可以根据您的代码定制解决方案以满足您的需求。你可以有一个生产者,如果你有办法确定每次注射时要生产什么。至于你的第二个问题,我想你甚至都懒得打开我放在那里的文档的链接。第一行以 - 生产者方法的 bean 类型取决于方法返回类型:
    • 没有必要居高临下。当您知道我希望能够注入到 GroupCaseDTO 属性时,为什么要建议一个返回类型 CaseDTO 的单一生产者方法?也许您没有阅读您链接的文章?
    【解决方案2】:

    我会在这方面做点什么:

    public abstract class CaseDTO {
    }
    

    以及子类,创建限定符。

    @Qualifier
    @Retention(RUNTIME)
    @Target({TYPE, FIELD, METHOD, PARAMETER})
    public @interface CaseContext {
    
        @Nonbinding
        String value() default "";
    
    }
    
    @ApplicationScoped
    public class CaseDTOProducer {
    
        @ApplicationScoped
        @CaseContext("")
        public CaseDTO produce(InjectionPoint ip) {
            //You can make the instantiation as complex as you want:
            final CaseContext caseContext = ip.getAnnotated().getAnnotation(CaseContext.class);
            switch (caseContext.value()) {
                case "ip":
                    return new IpCaseDTO();
                case "group":
                    return new GroupCaseDTO();
                default:
                    throw new ContextException("Unknown Case Context");
            }
        }
    
    }
    

    然后是注入点:

    public class CaseService {
    
        @Inject 
        @CaseContext("ip")
        private CaseDTO caseDTO;
    
        @Inject 
        @CaseContext("group")
        private CaseDTO caseDTO;
    }
    

    【讨论】:

    • 我无法在 DTO 类上添加注释,它们不在我控制的项目中
    • @GregSt.Onge 使用动态生产者查看更新。
    • 这确实对我有用,只是需要使该技术适应我的情况。注释:
    • 我认为我们需要放弃注释定义的“非绑定”部分
    • 如果你放弃@Nonbinding,那么你将不得不为CaseContext的每个值创建一个生产者方法
    【解决方案3】:

    我认为这是我能做的最好的;适应@maress

    @Produces @CaseContext
    public CaseDTO getContextCase()  {
        return JSFUtils.getFromPageFlowScope("case", CaseDTO.class);
    }
    
    @Produces @CaseContext("ip")
    public IPCaseDTO getContextIpCase()  {
        return JSFUtils.getFromPageFlowScope("case", IPCaseDTO.class);
    }
    
    @Produces @CaseContext("group")
    public GroupCaseDTO getContextGroupCase()  {
        return JSFUtils.getFromPageFlowScope("case", GroupCaseDTO.class);
    }
    

    注释:

    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ FIELD, METHOD })
    public @interface CaseContext {
        public String value() default "";
    }
    

    然后是注入点

    @Inject @CaseContext
    private CaseDTO muwCase;
    
    @Inject @CaseContext("group")
    private GroupCaseDTO muwCase;
    
    @Inject @CaseContext("ip")
    private IPCaseDTO muwCase;
    

    【讨论】:

    • 诚然,这仍然不是很好,因为我仍然需要每个子类型一个生产者方法......但它比必须为每个子类型创建一个新注释更好
    猜你喜欢
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    • 2016-09-14
    • 2013-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-26
    相关资源
    最近更新 更多