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.
get()
what returns null, or is theInstance
object null? The pattern you have here is a very standard pattern and does work well. Do you have a beans.xml? – John AmentInstance
object is null, so I guess that may be the root cause of the issue. I forgot to include it in the updated question but I do have a beans.xml file in the META-INF directory. – Paul H@Singleton @Startup
bean that calledfindCommandHandlerFor(command)
from a@PostConstruct
method and it works fine. I therefore suggest it must be something wrong with either your container or the packaging of the application. Do you have CDI working at all in your container? one thing to note is that for a web archive the beans.xml should be in WEB-INF not META_INF. – redge