我想我可能是类型擦除的受害者,但我想先在这里与其他人核对。
我要求做这样的事情:
public interface FooFactory {
public <T extends Bar> Foo<T> createFoo( Class<T> clazz );
}
编写此代码完全有效。但是,我正在尝试使用Spring BeanFactory
来实现此功能,但我无法做到。
我想做的是......
public class FooFactoryImpl implements BeanFactoryAware {
private BeanFactory beanFactory;
public <T extends Bar> Foo<T> createFoo( Class<T> clazz ) {
return beanFactory.getBean( ????????? );
}
public void setBeanFactory( BeanFactory beanFactory ) {
this.beanFactory = beanFactory;
}
}
正如你所看到的,我已经投入了????????我想要检索Foo<T>
类型的bean,其中T扩展Bar。但是,不可能派生类型为Foo<T>
的Class对象,所以我假设我想做的事情是不可能的?
其他人看到了解决这个问题的方法,或者实现我正在尝试做的其他方式吗?
谢谢,
安德鲁
答案 0 :(得分:3)
是的,这是一种类型擦除情况。由于Class
无法获得Foo<T>
,因此您必须使用Foo
并禁止警告。
@SuppressWarnings("unchecked")
public <T extends Bar> Foo<T> createFoo( Class<T> clazz ) {
return (Foo<T>) beanFactory.getBean("Name of Bean", Foo.class);
}
您可能会发现this file很有趣 - 这是一个实用工具类,其中包含Apache CXF用于集中所有这些不幸事件的警告。
当然,所有这些都假定您的XML(或其他)配置将导致可用的Foo
。
答案 1 :(得分:1)
由于您无法在Spring上下文中使用专门的Foo<T>
定义类型T
的bean,我猜您实际上有Foo<T>
的子类:
abstract public class Foo<T> { ... }
public class FooString extends Foo<String> { ... }
public class FooInteger extends Foo<String> { ... }
-
<bean id = "fooInteger" class = "FooInteger" />
<bean id = "fooString" class = "FooString" />
在这种情况下,您可以使用类型参数不会从超类定义中删除的事实:
public class FooFactory implements ApplicationContextAware {
private Map<Class<?>, Foo<?>> beans = new HashMap<Class<?>, Foo<?>>();
@SuppressWarnings("unchecked")
public <T> Foo<T> createFoo(Class<T> c) {
return (Foo<T>) beans.get(c);
}
@SuppressWarnings("unchecked")
public void setApplicationContext(ApplicationContext ctx)
throws BeansException {
Collection<Foo> candidates = ctx.getBeansOfType(Foo.class).values();
for (Foo candidate: candidates) {
Type superclass = candidate.getClass().getGenericSuperclass();
if (superclass instanceof ParameterizedType) {
ParameterizedType t = (ParameterizedType) superclass;
Class<?> p = (Class<?>) t.getActualTypeArguments()[0];
beans.put(p, candidate);
}
}
}
}