【问题标题】:Using a proxy to inject with a CDI Producer使用代理注入 CDI 生产者
【发布时间】:2017-02-09 11:33:42
【问题描述】:

我已尝试遵循我在之前发布的问题中找到的一些建议,但我似乎无法获得完整的解决方案。使用以下代码:

@Produces
@Dependent
@RestClientResourceConnector
public <T> RestClientProxy<T> getStatusResource(InjectionPoint injectionPoint) throws NamingException, OAuthClientException {
String propertiesFile = null;
String url = null;
AuthenticationStrategy authStrategy = null;

Class<T> clazz = (Class<T>) ((ParameterizedType)injectionPoint.getType()).getActualTypeArguments()[0];

for (Annotation qualifier : injectionPoint.getQualifiers()) {
  if (qualifier instanceof RestClientResourceConnector) {
    RestClientResourceConnector connector = (RestClientResourceConnector) qualifier;
    propertiesFile = connector.value();
    url = connector.clientUrl();
    LOGGER.debug("url set to: " + url);

    authStrategy = this.createAuthStrategry(propertiesFile);
  }
}

Constructor<?> constructor;
try {
  constructor = clazz.getConstructor(String.class, AuthenticationStrategy.class);
} catch (NoSuchMethodException | SecurityException e1) {
  // TODO Auto-generated catch block
  e1.printStackTrace();
  return null;
}

try {
  RestClientProxy rcp = new RestClientProxy();
  rcp.setService(constructor.newInstance(url, authStrategy));
  return rcp;
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}

return null;
}

限定符的来源是:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface RestClientResourceConnector
{  
  @Nonbinding String value() default "";
  @Nonbinding String clientUrl() default "";
}

RestClientProxy 定义为:

public class RestClientProxy<T> {
 private T client;

 public RestClientProxy() {
 }

 public RestClientProxy(T service) {
     this.client = service;
 }

 public void setService(T service) {
   this.client = service;
 }

 public T get() {
   return client;
 }
}

并尝试注入:

@Inject
  @RestClientResourceConnector(value="ferpa.properties", clientUrl="person.enpoint.url")
  RestClientProxy<PersonResourceClient> personProxy;

我得到了焊接异常:

2016-09-30 14:07:08,372 WARN [org.jboss.weld.Bootstrap] (weld-worker-1) WELD-001125: Illegal bean type javax.validation.ConstraintValidator<edu.psu.injection.validator.NotNullNotEmptyCollection, java.util.Collection<?>> ignored on [EnhancedAnnotatedTypeImpl] public class edu.psu.injection.validator.NotNullNotEmptyCollectionValidator
2016-09-30 14:07:08,782 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-2) MSC000001: Failed to start service jboss.deployment.unit."account-activation-web.war".WeldStartService: org.jboss.msc.service.StartException in service jboss.deployment.unit."account-activation-web.war".WeldStartService: Failed to start service
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1904)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type RestClientProxy<AccountActivationClient> with qualifiers @RestClientResourceConnector
at injection point [BackedAnnotatedField] @Inject @RestClientResourceConnector private edu.psu.activation.services.AccountActivationTokenService.accountActivationClientProxy
at edu.psu.activation.services.AccountActivationTokenService.accountActivationClientProxy(AccountActivationTokenService.java:0)

at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:359)
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:281)
at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:134)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:155)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:518)
at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:68)
at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:66)
at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:60)
at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:53)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
... 3 more

2016-09-30 14:07:08,787 ERROR [org.jboss.as.controller.management-operation] (management-handler-thread - 8) WFLYCTL0013: Operation ("full-replace-deployment") failed - address: ([]) - failure description: {"WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"account-activation-web.war\".WeldStartService" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"account-activation-web.war\".WeldStartService: Failed to start service
Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type RestClientProxy<AccountActivationClient> with qualifiers @RestClientResourceConnector
at injection point [BackedAnnotatedField] @Inject @RestClientResourceConnector private edu.psu.activation.services.AccountActivationTokenService.accountActivationClientProxy
at edu.psu.activation.services.AccountActivationTokenService.accountActivationClientProxy(AccountActivationTokenService.java:0)
"}}

与往常一样,非常感谢任何帮助。

【问题讨论】:

    标签: generics jakarta-ee cdi weld producer


    【解决方案1】:

    幸运的是,答案很简单。

    为了解决您的问题,当 Weld 比较两个注释实例时,您应该排除您的注释成员(value 和 clientUrl)。要实现这一点,请使用 @Nonbinding 注释。

    import javax.enterprise.util.Nonbinding;
    import javax.inject.Qualifier;
    
    @Qualifier
    @Retention(RUNTIME)
    @Target({TYPE, METHOD, FIELD, PARAMETER})
    public @interface RestClientResourceConnector {
    
        @Nonbinding
        String value() default "value";
    
        @Nonbinding
        String clientUrl() default "clientUrl";
    }
    

    详细解释

    如果您仔细阅读堆栈跟踪,您会发现如下内容:

    WELD-001475: The following beans match by type, but none have matching qualifiers:
      - Managed Bean [class RestClientProxy] with qualifiers [@Any @Default],
      - Producer Method [RestClientProxy<T>] with qualifiers [@RestClientResourceConnector @Any] declared as [[BackedAnnotatedMethod] @Produces @Dependent @RestClientResourceConnector public *your_producer_method_goes_here*...
    

    这意味着 Weld 找到了匹配的 bean,但它没有所需的限定符。你可能会问,“为什么?”。因为您的注入点包含一个带有两个参数的限定符:

    @RestClientResourceConnector(value="ferpa.properties", clientUrl="person.enpoint.url")
    

    但您的 Producer 方法仅使用 a 定义

    @Produces
    @Dependent
    @RestClientResourceConnector
    

    这就是为什么你应该告诉 Weld 忽略这些参数。

    更新

    正如用户@ussmith 发现的那样,问题是由于没有在 CDI bean 存档中定义生产者方法造成的。

    我再次发现 CDI 比它应该的更令人困惑。使用显式配置,这样的问题应该不会发生。

    【讨论】:

    • 谢谢和道歉,我应该在上面添加限定符代码。注释成员已经是@Nonbinding。我已经成功使用与生成的实例完全相同的代码和非泛型,所以我现在陷入了泛型兔子洞。
    • 嗯。上面的代码对我来说非常适合 Weld 2.3.5.Final。您使用哪个 Weld 版本?顺便说一句:还请使用完整的堆栈跟踪更新您的问题。这可能会有所帮助。
    • 我们正在运行 2.2.14.Final。我会和我的操作人员谈谈升级的问题。完整的堆栈跟踪现在在帖子中。再次感谢。
    • 我找到了!不知何故,您的生产者方法未注册。请快速检查并在您的beans.xml 中设置bean-discovery-mode="all"。 Weld 2.2.14.Final 在这里不是问题。
    • 你成功了!项目中的 beans.xml 位于 web 模块中,最终在战争中打包。这段代码在一个客户端子模块中,它有自己的 jar 包,并且没有在 web 模块中识别 bean 扫描器。再次,非常感谢您的帮助。
    猜你喜欢
    • 2013-09-17
    • 1970-01-01
    • 2013-09-16
    • 2014-03-04
    • 1970-01-01
    • 2013-01-07
    • 2023-03-29
    • 2015-04-08
    • 1970-01-01
    相关资源
    最近更新 更多