我正在使用Spring 4.3.7.RELEASE并且我正在尝试实现一个通用工厂,它使用作为参数提供的值来装饰它生成的对象。以前使用Spring时,我不会尝试下面的内容,因为它会明显遇到类型擦除问题。但是,since Spring 4 已经为实例化泛型类型提供了适当的(几乎是神奇的)支持。
所以,这是代码。这是一个人为的例子来说明这一点,而不是我正在使用的实际代码。
首先,这是通用接口,它是我希望随工厂生成的对象层次结构的根目录:
public interface Nameable {
String getName();
void setName(String name);
}
接下来,有2个实现接口的简单(相同的示例)类:
@Component
@Scope("prototype")
public class Foo implements Nameable {
public Foo(){
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
}
@Component
@Scope("prototype")
public class Widget implements Nameable {
public Widget(){
super();
}
public Widget(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
}
最后,这是所有内容的关键所在,这是Nameable
实例的通用工厂:
@Component
public class NameableFactory<T extends Nameable> {
@Autowired
private ObjectFactory<T> objectFactory;
public <T extends Nameable> T getObject(String name){
T newObject = (T) this.objectFactory.getObject();
newObject.setName(name);
return newObject;
}
}
我还省略了一些额外的客户端类等。
在运行时,当调用getObject()
或NameableFactory<Foo>
的{{1}}方法时,出现以下错误:
NameableFactory<Widget>
我也尝试使用org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'java.lang.Object' available:
expected single matching bean but found 2: foo, widget
代替FactoryBean
,结果相同。
我很确定这个问题的答案是:你不能这样做因为类型擦除,可能是因为Spring 4无法处理另一个泛型中包含的泛型(它不是魔法,只是聪明的错觉)。但是我想在放弃并手工实施20多家工厂之前,我会问社区。
此外,我对完全实现相同目标的不同方法持开放态度,因此感谢各种建议和指针。
编辑:
ObjectFactory
答案 0 :(得分:2)
我认为问题是,如果你根本没有指明它,那么spring无法找出你的NameableFactory的泛型类型
我对这家工厂有另一个想法:
public class NameableFactory {
private Map<Class<? extends Nameable>, Supplier<Nameable>> map;
public NameableFactory(Map<Class<? extends Nameable>, Supplier<Nameable>> map) {
this.map = map;
}
public Nameable get(Class<? extends Nameable> type, String name) {
Nameable nameable = map.get(type)
.get();
nameable.setName(name);
return nameable;
}
}
并以这种方式配置。
@Configuration
public class FactoryConfig implements ApplicationContextAware {
private ApplicationContext ctx;
@Bean
public NameableFactory nameableFactory() {
Map<Class<? extends Nameable>, Supplier<Nameable>> map = new HashMap<>();
map.put(Foo.class, () -> ctx.getBean(Foo.class));
map.put(Widget.class, () -> ctx.getBean(Widget.class));
return new NameableFactory(map);
}
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.ctx = ctx;
}
}
答案 1 :(得分:0)
我不得不退后一步,然后愚蠢(最后期限......)。
基本上,我已经采取了澳大利亚答案的一部分(并因此得到了支持)。在我需要$("#formname").on('submit',function(){
$.ajax({
url: "xxxxxxxxxx/xxxxx/xxxx/xxxx.php",
type: "POST",
data: new FormData(this),
contentType: false,
cache: false,
processData:false,
success: function(data){
}
});
});
或Widget
的所有课程中,我添加了:
Foo
所以我可以利用Spring实例化bean及其依赖项,但是我失去了命名的抽象。这也是很多冗余打字,但它在概念上很简单并且有效。
非常感谢那些提出建议的人,非常感谢。