在我的JSF应用程序中,我使用@ViewScoped
bean Publication
来显示/编辑来自我的数据库的数据。在该bean中,存在一个特定于子类型的数据对象的字段,即根据该出版物是例如书籍还是文章而包含不同的对象。
@ViewScoped
@Named
public class Publication implements Serializable {
@Inject
DatabaseStorage storage;
...
String id;
String type;
PublicationType typedStuff;
@PostConstruct
public void init() {
// Get an URL parameter from the request,
// look up row in database accordingly, initialize String "type".
switch (type) {
case "ARTICLE":
typedStuff = new Article(id);
break;
case "BOOK":
typedStuff = new Book(id);
break;
default:
break;
}
}
}
...实施/扩展Article
的课程Book
和PublicationType
。
到目前为止,非常好,但我希望typedStuff
成为CDI bean,以便我可以在那里注入有用的资源。
我已阅读有关制作人方法的this和this页面,以及this tutorial和this very related SO question,但他们都没有回答我的问题:我可以注入基于注入bean本身在运行时只知道的字段?
我已经让生产者方法工作了,但是我无法对它进行参数化,所以我无法让switch
工作。
如果我将生产者方法放在一个单独的类(或bean)中,那么我就无法访问type
字段。
如果我将注入bean注入生产者类,或者将生产者方法移动到注入类中,我会进行循环注入。
如果我将生产者方法静态地放入注入类,我也没有访问权限,因为type
不能是静态的。 (虽然,因为它只是暂时使用......?)
另外(这可能就是那里的答案),生产者方法在我的注入bean的init方法之前执行,因此type
甚至都没有设置。
有没有人有更好的主意?
答案 0 :(得分:3)
不,你不能,但你可以根据字段值选择一个bean。说:
public interface PublicationType {}
@PType("ARTICLE")
public class Article implements PublicationType{}
@PType("BOOK")
public class Book implements PublicationType {}
定义限定符:
public @interface PType {
String value();
}
并定义AnnotationLiteral
:
public class PTypeLiteral extends AnnotationLiteral<PType> implements PType {}
然后你可以使用:
public class Publication {
@Any
@Inject
private Instance<PublicationType> publicationTypes;
public void doSomething() {
PType ptype = new PTypeLiteral(type);
// Of course you will have to handle all the kind of exceptions here.
PublicationType publicationType = publicationTypes.select(ptype).get();
}
}
答案 1 :(得分:2)
有javax.inject.Provider
界面(我认为您正在使用同一个包中的@Named
和@Inject
注释。
您可以使用它来实现您想要的效果。它将为您创建带有注入字段的实例。
一个缺点是您必须自己设置ID。
@ViewScoped
@Named
public class Publication implements Serializable {
@Inject
DatabaseStorage storage;
@Inject
Provider<Article> articleProvider;
@Inject
Provider<Book> bookProvider;
String id;
String type;
PublicationType typedStuff;
@PostConstruct
public void init() {
// Get an URL parameter from the request,
// look up row in database accordingly, initialize String "type".
switch (type) {
case "ARTICLE":
typedStuff = articleProvider.get();
typedStuff.setId(id);
break;
case "BOOK":
typedStuff = bookProvider.get();
typedStuff.setId(id);
break;
default:
break;
}
}
}