正如我上面的评论所述,我认为被认为正确的答案根本不正确,即使它使用高级 CDI api 来回答你。看起来正确,但实际上,我认为它不可能正确。
另一方面,标有减号的答案是正确的,但过于抽象而无济于事。
他的制作人有一个问题。当 CDI 生成您的 bean 时,不可能知道具体实例返回到注入点。
它缺少 WELD 实施者在编译时缺少的相同信息来解决您的神秘问题。
因为注入点没有指定编译类型所需的具体参数化类型。
并且 instance.get() api 也没有任何帮助,因为它没有传递任何源类型。大功告成。
所以这个答案在技术上看起来不错,但实际上它不起作用。
我相信您可以通过多种方式解决问题。
我现在至少能想到两个,我相信还有其他的。
您可以创建一个愚蠢的外观转换器,它唯一知道如何为输入类型找出合适的转换器。
比如:
pulblic class MyClassThatNeedsAConverter{
@Inject
MyAllMightyFacadeConverterThatKnowsAllConcreteConverters converter;
public void someMethodThatNeedsToConverSomethin(T someTypeThatCanBeConverted){
// now i need to convert this to string
String convertedString = converter.convert(someTypeThatCanBeConverted);
// contiue with my business logic
}
}
那就是程序员 API。
然而,您的框架将实现这个强大的转换器外观。
public class MyAllMightyFacadeConverterThatKnowsAllConcreteConverters {
@Inject
ConvertToStringInterface<String> stringToStringConverter;
@Inject
ConvertToStringInterface<Long> longToStringConverter;
// and on you go with different concreted converters
// CDI can resolve these just fine, just make sure you do not have more than
// one candidate bean
...
public <T> String convert(T whateverTypeThatComesISwallow){
if(whateverTypeThatComesISwallow instaceof Long){
return longToStringConverter.convert((Long) whateverTypeThatComesISwallow );
}
if(whateverTypeThatComesISwallow instaceof SomeOtherType){
// same old story
}
throw new RuntimeException("You are out of luck, this type i do not know off an will not convert" + whateverTypeThatComesISwallow.getClass().getCanonincalName() );
}
}
这是一条路线。
另一条路线是您可以拥有转换器缓存之类的东西。
所以你的框架可以提供类似的东西
@ApplicationScoped
public class MyConverterHolder{
@Inject
Instance<StringConverter<?>> allConverterInstancesKnownToTheSystem;
final Map<Class, StringConveter<?>> myCacheOfConveters = new HashMap<>();
@postConstruct
public postConstruct(){
// you do not want to this initialization all the time
// so you just do it once during construction
for(StringConveter<?> currentConverterInstance : allConverterInstancesKnownToTheSystem) {
myCacheOfConveters.put(currentConverterInstance .getSupportedInputType(), currentConverterInstance );
}
} // post construct ends here
public <T> String convert(T someTypedDataIcanSwallow){
Class<T> sourceType = someTypedDataIcanSwallow.getClass();
return myCacheOfConveters.get(sourceType).convert(someTypedDataIcanSwallow);
}
}
我更喜欢第二种方法。
当哈希映射可以为我完成这项工作并且我不必维护它时,我不喜欢使用 ifs 和 elses 发送垃圾邮件代码。
但重点是。
CDI 不能给你一个具体的实现来解决你的问题,除非你告诉它具体的类型。
如果你不给它具体的类型,CDI 可以给你所有符合某些类型标准的实例。但是接下来你必须解决挑选合适的问题。
所以你需要在转换之间创建这个外观对象。
关于参数化 tpye 注入的好读物当然是规范本身。
这描述了将 bean 解析为注入点的匹配规则,并在描述后给出了示例。
例如。请参阅“5.2.4. 原始类型和参数化类型的可分配性”部分。
For example, Dao is eligible for injection to any injection point of
type @Default Dao<Order>, @Default Dao<User>, @Default Dao<?>,
@Default Dao<? extends Persistent> or @Default Dao<X extends
Persistent> where X is a type variable.
而且这一段也很重要:
合法 bean 类型中定义的任何合法 bean 类型都可以是
所需的注入点类型。此外,所需的类型
注入点可能包含通配符类型参数。然而,一个
类型变量不是合法的注入点类型。
如果注入点类型是类型变量,则容器
自动检测问题并将其视为定义错误。
亲切的问候。