如何以编程方式查找和注入CDI托管bean,其中限定符包含类的名称 [英] How to programmatically lookup and inject a CDI managed bean where the qualifier contains the name of a class

查看:151
本文介绍了如何以编程方式查找和注入CDI托管bean,其中限定符包含类的名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试以编程方式查找并注入CDI托管bean,其中限定符包含类的名称(不是我要注入的类),但是我遇到的问题是我正在使用的代码查找正确的bean总是返回 null

I am trying to programmatically lookup and inject a CDI managed bean where the qualifier contains the name of a class (not the class I want to inject), however the problem I've got is that the code I'm using to lookup the correct bean always returns with null.

我要注入的bean使用调用的自定义注释进行注释 @CQRSCommandHandler 其中包含用作限定符的类的名称,bean还实现了一个名为 CommandHandler 的接口。我正在使用限定符的类实现接口命令

The beans I want to inject are annotated with a custom annotation called @CQRSCommandHandler which contains the name of a class being used as a qualifier and the beans also implement an interface called CommandHandler. The classes I'm using qualifier implement the interface Command.

基于我对CDI的知识有限,我相信为了以编程方式查找已使用 @CQRSCommandHandler 注释限定的正确bean,我需要扩展 AnnotationLiteral 然后我可以使用 Instance 来选择bean。

Based on my somewhat limited knowledge of CDI, I believe that in order to programmatically lookup the correct bean which has been qualified with the @CQRSCommandHandler annotation, I need to extend AnnotationLiteral and I can then use Instance to select the bean.

的代码@CQRSCommandHandler 注释如下:

@Qualifier
@Documented
@Retention(value= RetentionPolicy.RUNTIME)
public @interface CQRSCommandHandler {
    Class<? extends Command> command();
}

扩展 AnnotationLiteral 如下:

public class CQRSCommandHandlerQualifier extends AnnotationLiteral<CQRSCommandHandler> implements CQRSCommandHandler {

    private static final long serialVersionUID = 1L;
    private final Class<? extends Command> command;

    public CQRSCommandHandlerQualifier(Class<? extends Command> command) {
        this.command = command;
    }

    @Override
    public Class<? extends Command> command() {
        return command;
    }

}

我用的代码使用CDI查找正确的bean如下:

The code I'm using to lookup the correct bean using CDI is as follows:

@Inject
@Any
private Instance<CommandHandler> commandHandlerInstance;

private CommandHandler findCommandHandlerFor(Command command) {

    CommandHandler commandHandler = commandHandlerInstance.select(new CQRSCommandHandlerQualifier(command.getClass())).get();  //This always returns null
    return commandHandler;
}

尽管谷歌搜索了很多小时但我无法理解为什么 commandHandlerInstance.select(new CQRSCommandHandlerQualifier(command.getClass()))。get(); 不返回已使用 @CQRSCommandHandler注释的bean实例(command = MyCommand.class)其中bean实现 CommandHandler 接口和 MyCommand.class 实现接口命令

Despite many hours of google searching I can't work out why commandHandlerInstance.select(new CQRSCommandHandlerQualifier(command.getClass())).get(); does not return an instance of a bean which has been annotated with @CQRSCommandHandler (command = MyCommand.class) where the bean implements the CommandHandler interface and MyCommand.class implements the interface Command.

这是以编程方式查找和注入CDI托管bean的正确方法吗?限定符包含类的名称?如果是的话,上面的代码我哪里出错?如果没有,获得相同最终结果的最佳方法是什么?

Is this the correct way to programmatically lookup and inject a CDI managed bean where the qualifier contains the name of a class? If so, where am I going wrong with the above code? If not, what is the best way to achieve the same end result?

更新

以下代码是我正在尝试查找的bean的示例实现:

The following code is an example implementation of a bean that I'm trying to lookup:

@CQRSCommandHandler(command = CreateToDoItemCommand.class)
public class CreateToDoItemCommandHandler implements CommandHandler {

    @Override
    public <R> Object handle(Command command) {
        System.out.println("This is the CreateToDoItemCommandHandler");
        return null;
    }
}

以下代码是<$ c $的界面c> CommandHandler

public interface CommandHandler {

    public <R> Object handle(Command command);

}

以下代码是我上课的一个例子在限定符中用作参数:

The following code is an example of the class I'm using as a parameter in the qualifier:

public class CreateToDoItemCommand implements Command {

    private String todoId;
    private String description;

    public CreateToDoItemCommand(String todoId, String description) {
        this.todoId = todoId;
        this.description = description;
    }

    public String getTodoId() {
        return todoId;
    }

    public String getDescription() {
        return description;
    }

}

我已经完成了代码在Eclipse中,似乎 commandHandlerInstance Instance 对象是 null

I've stepped through the code in Eclipse and it seems that the Instance object of commandHandlerInstance is null.

更新2

正如@redge所建议的那样,我将实例化的每一步分成如下一行:

As suggested by @redge I've separate each step of the instantiation onto a separate line as follows:

private CommandHandler findCommandHandlerFor(Command command) {
    CQRSCommandHandlerQualifier qualifier = new CQRSCommandHandlerQualifier(command.getClass());
    Instance<CommandHandler> instance = commandHandlerInstance.select(qualifier);
    CommandHandler commandHandler = instance.get();
    return commandHandler;
}

问题似乎是这行代码实例< CommandHandler> instance = commandHandlerInstance.select(qualifier); 其中 NullPointerException 被抛出大概是因为 Instance object commandHandlerInstance null

The issue seems to be with this line of code Instance<CommandHandler> instance = commandHandlerInstance.select(qualifier); where NullPointerException is thrown presumably because the Instance object commandHandlerInstance is null

我正在运行这个与Weld 2.0.0 SP1一起提供的GlashFish 4上的代码,但我也尝试在GlashFish 4.1上运行相同的代码并安装了Weld版本2.2.10.SP1,这是Maven Central的最新版本,但同样的问题也出现了。

I'm running this code on GlashFish 4 which ships with Weld 2.0.0 SP1, but I've also just tried running the same code on GlashFish 4.1 and have installed Weld version 2.2.10.SP1 which is the latest from Maven Central but the same issue occurs.

推荐答案

您有GlassFish 4.1。我怀疑你有一个beans.xml文件,如果你这样做,应根据你当前的设置标记为 bean-discovery-mode =all。如果不这样做,或者你使用 bean-discovery-mode =annotated,那么你需要为每个命令添加一个定义注释的bean,例如:每个命令的 @ApplicationScoped ,以便可以解析它们。

You have GlassFish 4.1. I doubt you have a beans.xml file, which if you do should be marked as bean-discovery-mode="all" based on your current setup. If you don't, or you use bean-discovery-mode="annotated" then you'll need to add a bean defining annotation to each of your commands, e.g. @ApplicationScoped for each command so that they can be resolved.

这篇关于如何以编程方式查找和注入CDI托管bean,其中限定符包含类的名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆