假设我有这样一个界面:
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<T>
的参数的值,所以我真正拥有的是:
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<T>
无法找到。这看起来很可疑:我本以为它会以 Converter<Integer>
的形式说话相反,由于 T
“插槽”正在被“填充”Integer.class
在运行时,尽管公平地说,我确实提供了一个 new TypeLiteral<Converter<T>>(){}
, 不是 new TypeLiteral<Converter<Integer>>(){}
.
无论如何,这一切告诉我 TypeLiteral<T>
正在使用 T
作为要查找的类型,而不是“填充” T
的实际值“插槽”,事实上,没有声明为 implements Converter<T>
的转换器, 只有一个转换器声明为 implements Converter<Integer>
,所以我担心我想在这里做的事情根本不可能。
最佳答案
创建 TypeLiteral
捕获通用参数只有在编译时已知这些参数时才有效,因此 new TypeLiteral<Converter<Integer>>(){}
.
如果类型参数在编译时未知,则 TypeLiteral 无法捕获参数信息,因为该信息已因类型删除而被删除。所以创建一个 new TypeLiteral<Converter<T>>(){}
实际上只是创建了一个 new TypeLiteral<Converter<object>>(){}
.
这意味着您的 select(typeLiteral)
不会按预期工作,因为它将收到 Converter<object>
的类型文字.
关于java - 我必须使用什么类型的文字才能使 CDI 的 Instance::select 方法正常工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40227804/