Как программно искать и внедрять управляемый компонент CDI, где квалификатор содержит имя класса
Я пытаюсь программно искать и внедрять управляемый компонент CDI, где спецификатор содержит имя класса (а не класса, который я хочу внедрить), однако проблема в том, что код, который я использую для поиска правильного боб всегда возвращается с null
,
Бобы, которые я хочу добавить, помечаются пользовательской аннотацией под названием @CQRSCommandHandler
который содержит имя класса, используемого в качестве спецификатора, а бины также реализуют интерфейс, называемый CommandHandler
, Классы, которые я использую, описывают реализацию интерфейса. Command
,
Основываясь на моих немного ограниченных знаниях CDI, я считаю, что для того, чтобы программно найти правильный компонент, который был квалифицирован с @CQRSCommandHandler
аннотации, мне нужно продлить AnnotationLiteral
и тогда я могу использовать Instance
выбрать боб.
Код для @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, выглядит следующим образом:
@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;
}
Несмотря на многие часы поиска в Google, я не могу понять, почему commandHandlerInstance.select(new CQRSCommandHandlerQualifier(command.getClass())).get();
не возвращает экземпляр компонента, который был аннотирован @CQRSCommandHandler (command = MyCommand.class)
где боб реализует CommandHandler
интерфейс и MyCommand.class
реализует интерфейс Command
,
Является ли это правильным способом программного поиска и внедрения управляемого компонента CDI, в котором квалификатор содержит имя класса? Если да, то где я ошибаюсь с приведенным выше кодом? Если нет, то как лучше всего достичь того же конечного результата?
Обновить
Следующий код является примером реализации компонента, который я пытаюсь найти:
@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;
}
}
Следующий код является интерфейсом для CommandHandler
:
public interface CommandHandler {
public <R> Object handle(Command command);
}
Следующий код является примером класса, который я использую в качестве параметра в квалификаторе:
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, и кажется, что Instance
объект commandHandlerInstance
является null
,
Обновление 2
Как подсказывает @redge, я разделяю каждый шаг реализации на отдельной строке следующим образом:
private CommandHandler findCommandHandlerFor(Command command) {
CQRSCommandHandlerQualifier qualifier = new CQRSCommandHandlerQualifier(command.getClass());
Instance<CommandHandler> instance = commandHandlerInstance.select(qualifier);
CommandHandler commandHandler = instance.get();
return commandHandler;
}
Проблема, кажется, с этой строкой кода Instance<CommandHandler> instance = commandHandlerInstance.select(qualifier);
где NullPointerException
бросается предположительно, потому что Instance
объект commandHandlerInstance
является null
Я запускаю этот код на GlashFish 4, который поставляется с Weld 2.0.0 SP1, но я также только что попробовал запустить тот же код на GlashFish 4.1 и установил версию 2.2.10.SP1 Weld, которая является последней из Maven Central, но такая же проблема возникает.
1 ответ
У вас есть GlassFish 4.1. Я сомневаюсь, что у вас есть файл beans.xml, который, если вы делаете, должен быть помечен как bean-discovery-mode="all"
на основе ваших текущих настроек. Если вы этого не сделаете, или вы используете bean-discovery-mode="annotated"
тогда вам нужно будет добавить аннотацию, определяющую компонент, к каждой из ваших команд, например: @ApplicationScoped
для каждой команды, чтобы они могли быть решены.