CDI,多态性:是否可以根据在A的@PostConstruct期间初始化的字段将bean B的实现注入到bean A中?

时间:2017-06-26 12:36:06

标签: dependency-injection cdi

在我的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的课程BookPublicationType

到目前为止,非常好,但我希望typedStuff成为CDI bean,以便我可以在那里注入有用的资源。

我已阅读有关制作人方法的thisthis页面,以及this tutorialthis very related SO question,但他们都没有回答我的问题:我可以注入基于注入bean本身在运行时只知道的字段?

我已经让生产者方法工作了,但是我无法对它进行参数化,所以我无法让switch工作。

  • 如果我将生产者方法放在一个单独的类(或bean)中,那么我就无法访问type字段。

  • 如果我将注入bean注入生产者类,或者将生产者方法移动到注入类中,我会进行循环注入。

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

  • 另外(这可能就是那里的答案),生产者方法在我的注入bean的init方法之前执行,因此type甚至都没有设置。

    < / LI>

有没有人有更好的主意?

2 个答案:

答案 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;
        }
    }
}