Sorry for replying so late, I didn't notice this comment until now.
You could do this in many different ways. The main idea is that whenever you register a new command handler, you need to somehow also specify which commands the handler is able to handle. You could do this manually, like registerCommandHandler(myHandler, MyCommand.class), use introspection to fetch the command class from the generic parameters or just add a supportsCommand(Object) method to the handler itself.
The findHandlerFor method would then just loop through all the registered command handlers and look for a handler that supports the command in question.
Hey Petter! No worries! Thanks for replying. My solution ended up looking like this :)
/**
* Common interface that must be implemented by all command handlers.
*
* @param <C> The type of the command to handle
* @param <R> The type of the result returned from handling the command
*/publicinterfaceCommandHandler<CextendsCommand<R>,R>{RhandleCommand(Ccommand);}
/**
* Registry of all command handlers in the application. Any implementation of {@link CommandHandler} is
* added to the registry at application start.
*/@ComponentpublicclassCommandHandlerRegistry{privatefinalMap<Class<?extendsCommand<?>>,CommandHandler<?extendsCommand<?>,?>>handlers=newHashMap<>();publicCommandHandlerRegistry(ApplicationContextctx){Map<String,CommandHandler>commandHandlers=ctx.getBeansOfType(CommandHandler.class);for(CommandHandlercommandHandler:commandHandlers.values()){register(commandHandler);}}/**
* Get the command handler for a given command class.
*
* @param commandClass the class of the command to lookup
* @return the corresponding command handler for a command class
*/publicCommandHandler<?extendsCommand<?>,?>get(Class<?>commandClass){returnOptional.ofNullable(handlers.get(commandClass)).orElseThrow(()->newIllegalArgumentException("No command handler found for "+commandClass.getSimpleName()));}privatevoidregister(CommandHandler<?extendsCommand<?>,?>commandHandler){// The generics of the command handler are used to create the key/value entry in the handlers mapClass<?>[]generics=GenericTypeResolver.resolveTypeArguments(commandHandler.getClass(),CommandHandler.class);// The type of command is the first generic, and is used to create the keyClass<?extendsCommand<?>>commandType=(Class<?extendsCommand<?>>)Objects.requireNonNull(generics)[0];handlers.put(commandType,commandHandler);}}
@ComponentpublicclassCommandGateway{privatefinalCommandHandlerRegistryregistry;publicCommandGateway(CommandHandlerRegistryregistry){this.registry=registry;}/**
* Delegates command handling to the registered handler for a command in {@link CommandHandlerRegistry}.
*
* @param command the command to handle
* @param <C> command type
* @param <R> result type
* @return the result of the command
*/@SuppressWarnings("unchecked")public<CextendsCommand<R>,R>RhandleCommand(Ccommand){CommandHandler<C,R>handler=(CommandHandler<C,R>)registry.get(command.getClass());returnhandler.handleCommand(command);}}
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Sorry for replying so late, I didn't notice this comment until now.
You could do this in many different ways. The main idea is that whenever you register a new command handler, you need to somehow also specify which commands the handler is able to handle. You could do this manually, like
registerCommandHandler(myHandler, MyCommand.class)
, use introspection to fetch the command class from the generic parameters or just add asupportsCommand(Object)
method to the handler itself.The
findHandlerFor
method would then just loop through all the registered command handlers and look for a handler that supports the command in question.Hey Petter! No worries! Thanks for replying. My solution ended up looking like this :)