Spring: how to get a bean from an application context implementing a generic interface?

I have an interface:

public interface CommandHandler<T extends Command> {
    void handle(T command);
}

      

There are commands that implement the Command marker interface

public class CreateCategoryCommand implements Command {
}

public class CreateCategoryCommand implements Command {
}

      

For each team I have a suitable CommandHandler implementation :

@Component
public class CreateProductCommandHandler implements CommandHandler<CreateProductCommand> {
    @Override
    public void handle(CreateProductCommand command) {
        System.out.println("Command handled");
    }
}

@Component
public class CreateCategoryCommandHandler implements CommandHandler<CreateCategoryCommand> {

    @Override
    public void handle(CreateCategoryCommand command) {

    }
}

      

Question: I have a command bus

@Component
public class SimpleCommandBus implements CommandBus {

    @Autowired
    private ApplicationContext context;

    @Override
    public void send(Command command) {
        // OF COURSE, THIS NOT COMPILED, BUT I NEED SOMETHING LIKE THIS
        CommandHandler commandHandler = context.getBean(CommandHandler<command.getClass()>)
    }
}

      

How do I get a bean from an application context that implements a generic interface with a specific type?

+3


source to share


1 answer


I solved this:



@Component
public class SimpleCommandBus {

    private final Logger logger;
    private final Set<CommandHandler<?>> handlers;
    private final Map<Class<?>, CommandHandler<?>> commandHandlersCache = new WeakHashMap<>();

    public SimpleCommandBus(Logger logger, Set<CommandHandler<?>> handlers) {
        this.logger = logger;
        this.handlers = handlers;
    }

    public void send(Command command) {
        CommandHandler<Command> commandHandler = getCommandHandler(command);

        if (commandHandler != null)
            commandHandler.handle(command);
        else
            logger.error("Can't handle command " + command);

    }

    @SuppressWarnings("unchecked")
    private <C extends Command> CommandHandler<C> getCommandHandler(C command) {
        Class<?> commandType = command.getClass();

        if (commandHandlersCache.containsKey(commandType))
            return (CommandHandler<C>) commandHandlersCache.get(commandType);

        for (CommandHandler<?> haandler : handlers) {
            Class<?> supportedCommandType = resolveTypeArgument(haandler.getClass(), CommandHandler.class);

            if (commandType.isAssignableFrom(supportedCommandType)) {
                commandHandlersCache.put(commandType, haandler);
                return (CommandHandler<C>) haandler;
            }
        }

        commandHandlersCache.put(commandType, null);
        return null;
    }


}

      

0


source







All Articles