我必须使用什么类型的字面量才能使 CDI 的 Instance::select 方法正常工作?
What type literal must I use to have CDI's Instance::select method work properly?
假设我有这样一个界面:
public interface Converter<T> { /*...*/ }
假设在 CDI 环境中我已经成功地完成了这个:
@Inject
@Any
private Instance<Converter<?>> converters;
("successfully" 我的意思是我可以执行以下操作并在输出中看到多个转换器,因此可以正确发现和提供 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
"slot" 在运行时是 "filled" 和 Integer.class
,尽管, 公平地说,我确实提供了 new TypeLiteral<Converter<T>>(){}
,而不是 new TypeLiteral<Converter<Integer>>(){}
。
无论如何,所有这些告诉我 TypeLiteral<T>
正在使用 T
作为要查找的类型,而不是实际值 "filling" T
"slot",事实上,没有声明为 implements Converter<T>
的转换器,只有一个声明为 implements Converter<Integer>
的转换器,所以我担心我想在这里做的事情根本不可能。
看起来你的Converter接口还没有被CDI发现。您可以通过向接口添加注释范围或通过 beans.xml 配置文件发现它来实现。
这个 有更好的解释。
创建 TypeLiteral
以捕获通用参数只有在编译时已知这些参数时才有效,因此 new TypeLiteral<Converter<Integer>>(){}
.
如果类型参数在编译时未知,则 TypeLiteral 无法捕获参数信息,因为该信息已因类型擦除而被删除。所以创建一个 new TypeLiteral<Converter<T>>(){}
实际上只是创建一个 new TypeLiteral<Converter<object>>(){}
.
这意味着您的 select(typeLiteral)
将无法按预期工作,因为它将收到 Converter<object>
.
的类型文字
假设我有这样一个界面:
public interface Converter<T> { /*...*/ }
假设在 CDI 环境中我已经成功地完成了这个:
@Inject
@Any
private Instance<Converter<?>> converters;
("successfully" 我的意思是我可以执行以下操作并在输出中看到多个转换器,因此可以正确发现和提供 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
"slot" 在运行时是 "filled" 和 Integer.class
,尽管, 公平地说,我确实提供了 new TypeLiteral<Converter<T>>(){}
,而不是 new TypeLiteral<Converter<Integer>>(){}
。
无论如何,所有这些告诉我 TypeLiteral<T>
正在使用 T
作为要查找的类型,而不是实际值 "filling" T
"slot",事实上,没有声明为 implements Converter<T>
的转换器,只有一个声明为 implements Converter<Integer>
的转换器,所以我担心我想在这里做的事情根本不可能。
看起来你的Converter接口还没有被CDI发现。您可以通过向接口添加注释范围或通过 beans.xml 配置文件发现它来实现。
这个
创建 TypeLiteral
以捕获通用参数只有在编译时已知这些参数时才有效,因此 new TypeLiteral<Converter<Integer>>(){}
.
如果类型参数在编译时未知,则 TypeLiteral 无法捕获参数信息,因为该信息已因类型擦除而被删除。所以创建一个 new TypeLiteral<Converter<T>>(){}
实际上只是创建一个 new TypeLiteral<Converter<object>>(){}
.
这意味着您的 select(typeLiteral)
将无法按预期工作,因为它将收到 Converter<object>
.