Dependency injection 多态性:是否可以基于在@PostConstruct期间初始化的字段将bean B的实现注入bean a?

Dependency injection 多态性:是否可以基于在@PostConstruct期间初始化的字段将bean B的实现注入bean a?,dependency-injection,cdi,Dependency Injection,Cdi,在我的JSF应用程序中,我使用@ViewScopedbeanPublication来显示/编辑来自数据库的数据。在这个bean中,有一个特定于子类型的数据对象的字段,也就是说,根据出版物是(比如)一本书还是一篇文章,包含一个不同的对象 @ViewScoped @Named public class Publication implements Serializable { @Inject DatabaseStorage storage; ... String

在我的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
成为CDIBean,这样我就可以在那里注入有用的资源。

我已经阅读并翻页了producer方法,以及and,但是没有一个方法能够准确地回答我的问题:我可以基于注入bean本身在运行时才知道的字段进行注入吗

我已经让producer方法正常工作了,但是我不能参数化它,所以我不能让
开关
正常工作

  • 如果我将producer方法放在一个单独的类(或bean)中,那么我就不能访问
    type
    字段

  • 如果我将注入bean注入到producer类中,或者将producer方法移动到注入类中,就会得到循环注入

  • 如果我将producer方法静态地放入injection类中,我也没有访问权限,因为
    type
    不能是静态的。(虽然,因为它只是暂时使用…?)

  • 另外(这可能就是答案所在),producer方法是在注入bean的init方法之前执行的,所以
    type
    甚至还没有设置


有人有更好的主意吗?

没有,您不能,但可以根据字段值选择一个bean。说:

public interface PublicationType {}

@PType("ARTICLE")
public class Article implements PublicationType{}

@PType("BOOK")
public class Book implements PublicationType {}
并定义一个限定符:

public @interface PType {
    String value();
}
并定义一个
注释文字

public class PTypeLiteral extends AnnotationLiteral<PType> implements PType {}
公共类PTypeLiteral扩展AnnotationLiteral实现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();
   }
}
公共类发布{
@任何
@注入
私有实例发布类型;
公共无效剂量测定法(){
PType PType=新的PTypeLiteral(类型);
//当然,您必须在这里处理所有类型的异常。
PublicationType PublicationType=publicationTypes.select(ptype.get();
}
}

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;
        }
    }
}
@ViewScoped
@命名
公共类发布实现了可序列化{
@注入
数据库存储;
@注入
提供者和提供者;
@注入
图书供应商;
字符串id;
字符串类型;
PublicationType-typedStuff;
@施工后
公共void init(){
//从请求中获取URL参数,
//相应地在数据库中查找行,初始化字符串“type”。
开关(类型){
案例“第条”:
typedStuff=articleProvider.get();
typedStuff.setId(id);
打破
案例“书”:
typedStuff=bookProvider.get();
typedStuff.setId(id);
打破
违约:
打破
}
}
}

如何获取
类型
?你不能用同样的方法得到它吗?另外,CDI是懒惰的,在您使用它生成的bean之前,它不会使用生产者(Weld就是这样做的,您可能正在使用OWB,我不知道它是如何工作的)。如果该场景适合您,那么您的
@ViewScoped
bean的init将根据您触摸生产者的类型结束,这意味着它应该可以工作。自己设置id不会有问题。我可以很容易地为构造后调用的init方法切换构造函数。我要试试看@Antares请看一看我回答中的修复,因为我之前写过,提供者是一个注释,而实际上它是一个接口。是的,我直接进入了这个陷阱,谢谢你的纠正。一切都像你说的那样安排好了,一切都完美无缺。不过,它将有很多提供者,因为在现实世界中,我将有十几个(或更多)子类型。我也要看看@maress的答案。好吧,我花了一段时间搜索注释和
AnnotationLiteral
的缺失细节,但我最终还是让它工作了(尽管Eclipse抱怨我不应该在
实现PType
位中使用注释作为超级接口)。这是一个非常通用的解决方案,我喜欢它。