【问题标题】:What type literal must I use to have CDI's Instance::select method work properly?我必须使用什么类型的文字才能使 CDI 的 Instance::select 方法正常工作?
【发布时间】:2017-03-06 18:50:08
【问题描述】:

假设我有一个这样的界面:

public interface Converter<T> { /*...*/ }

假设在 CDI 环境中我已经成功地做到了这一点:

@Inject
@Any
private Instance<Converter<?>> converters;

(“成功”是指我可以执行以下操作并在输出中看到几个转换器,因此可以正确发现和提供 bean:

for (final Object o : converters) {
  System.out.println("*** converter: " + o);
}

...所以 bean 发现不是问题。)

现在假设给定Integer.class,我想这样做:

final TypeLiteral<Converter<Integer>> typeLiteral = new TypeLiteral<Converter<Integer>>(){};
final Instance<Converter<Integer>> subInstance = converters.select(typeLiteral);
final Converter<Integer> converter = subInstance.get();

这很好用。

现在,在我的实际代码中,Integer.class 被传入,作为一个满足声明为Class&lt;T&gt; 的参数的值,所以我真正拥有的是:

final TypeLiteral<Converter<T>> typeLiteral = new TypeLiteral<Converter<T>>(){};
final Instance<Converter<T>> subInstance = converters.select(typeLiteral);
final Converter<T> converter = subInstance.get(); // this does not work

get() 调用失败,堆栈跟踪开始于如下所示:

org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001334: Unsatisfied dependencies for type Converter<T> with qualifiers @Any 
    at org.jboss.weld.bean.builtin.InstanceImpl.get(InstanceImpl.java:105)

我必须怎么做才能使这个选择成功?

我注意到的一件事是堆栈报告找不到Converter&lt;T&gt;。这看起来很可疑:我原以为它会用Converter&lt;Integer&gt; 来代替,因为T“插槽”在运行时被Integer.class“填充”,但公平地说,我确实提供了一个new TypeLiteral&lt;Converter&lt;T&gt;&gt;(){},不是new TypeLiteral&lt;Converter&lt;Integer&gt;&gt;(){}

无论如何,这一切都告诉我TypeLiteral&lt;T&gt; 使用T 作为要查找的类型,而不是“填充”T“槽”的实际值,实际上,没有声明为@ 的转换器987654340@,只有一个声明为implements Converter&lt;Integer&gt;的转换器,所以我担心我想在这里做的事情根本不可能。

【问题讨论】:

  • 这可能是一个愚蠢的问题,但是您是否定义了一个 beans.xml,其中列出了(或未列出)您的可注入依赖项
  • 是的;我应该提到我可以成功迭代converters 对象,并且可以看到找到了几个。
  • 这可能与 new TypeLiteral&lt;Converter&lt;T&gt;&gt;(){} 有关 - T 在编译时未知,因此它将表示类型 Converter&lt;Object&gt;,而不是 Converter&lt;T&gt;
  • @JosephEarl 我相信你是对的。看来我不能以这种方式做我想做的事。从这个角度来看,Instance::select(TypeLiteral) 仅适用于编译时可解析类型。能够在运行时进行选择也很好。那好吧。如果您写下您的评论作为答案,我会接受。
  • 也许您可以让调用者将 TypeLiteral 传递给您的类/方法,以便在代码中创建 TypeLiteral 的位置已知类型,但您的类仍然可以是通用的并且不知道确切的类型.例如,这应该可以工作:Converter&lt;T&gt; getConverter(TypeLiteral&lt;Converter&lt;T&gt;&gt; typeLiteral) { Instance&lt;Converter&lt;T&gt;&gt; subInstance = converters.select(typeLiteral); Converter&lt;T&gt; converter = subInstance.get(); return converter; },前提是调用者在编译时知道他们想要的转换器类型。

标签: java cdi


【解决方案1】:

创建TypeLiteral 来捕获泛型参数仅在这些参数在编译时已知的情况下才有效,因此new TypeLiteral&lt;Converter&lt;Integer&gt;&gt;(){}

如果在编译时类型参数未知,则 TypeLiteral 无法捕获参数信息,因为该信息已因类型擦除而被删除。所以创建一个new TypeLiteral&lt;Converter&lt;T&gt;&gt;(){} 实际上只是创建一个new TypeLiteral&lt;Converter&lt;object&gt;&gt;(){}

这意味着您的select(typeLiteral) 将无法按预期工作,因为它将接收Converter&lt;object&gt; 的类型文字。

【讨论】:

    【解决方案2】:

    CDI 似乎没有发现您的 Converter 接口。您可以通过向接口添加注释范围或通过 beans.xml 配置文件发现它来实现。

    这个WELD-001408: Unsatisfied dependencies for type Customer with qualifiers @Default 有更好的解释。

    【讨论】:

    • 谢谢,但是当我迭代 converters 对象时,如上所述,我可以看到我所有的转换器。
    猜你喜欢
    • 2014-07-06
    • 2013-01-20
    • 2012-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多