Как программно искать и внедрять управляемый компонент 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 для каждой команды, чтобы они могли быть решены.

Другие вопросы по тегам