How to programmatically lookup and inject a CDI managed bean where the qualifier contains the name of a class

血红的双手。 提交于 2019-12-11 03:59:25

问题


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.

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.

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.

The code for the @CQRSCommandHandler annotation is as follows:

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

The code for extending AnnotationLiteral is as follows:

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

}

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

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.

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?


Update

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

The following code is the interface for 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;
    }

}

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


Update 2

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

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

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.


回答1:


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.



来源:https://stackoverflow.com/questions/29527308/how-to-programmatically-lookup-and-inject-a-cdi-managed-bean-where-the-qualifier

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!