Search code examples
javagenericsjava-8java-11micronaut

Generic class registry for command and handler in Java with Micronaut


Trying to do the dependency injection of java generics class in Micronaut

Interface

public interface IRequestHandler<C, R> {
    R handler(C c);
}

Dependency Injection

@Singleton
public record ServiceBus(IRequestHandler<C, R> iRequestHandler) implements IServiceBus{

    @Override
    public <C, R> R send(C c) {
        return iRequestHandler.handler(c);
    }
}

Interface

public interface IServiceBus {
    <C,R> R send(C c);
}

Implementation

public class ProductController {
    public ProductController(IServiceBus iRequestHandler){
        _iserviceBus= iRequestHandler;
    }
     public Mono<?> get(ProductSearchCriteriaCommand searchCriteria) {
            var item = _iserviceBus.<CreateProductCommand,CreateProductCommand>send(new CreateProductCommand());
            return null;
        }
}

Problem for me is on ServiceBus class, how can I pass the type for public record ServiceBus(IRequestHandler<C, R> iRequestHandler) and iRequestHandler.handler(c);

enter image description here

@Singleton
public class CreateProductCommandHandler implements IRequestHandler<CreateProductCommand, CreateProductCommand> {
    @Override
    public CreateProductCommand handler(CreateProductCommand createProductCommand) {
        return null;
    }
}

@Singleton
public record DeleteProductCommandHandler() implements IRequestHandler<DeleteProductCommand,DeleteProductCommand> {

    @Override
    public DeleteProductCommand handler(DeleteProductCommand deleteProductCommand) {
        return null;
    }
}

When I am calling _iserviceBus.<CreateProductCommand,CreateProductCommand>send(new CreateProductCommand()); in controller I am trying to invoke handler method in CreateProductCommandHandler class

Similarly if I call _iserviceBus.<CreateProductCommand,CreateProductCommand>send(new DeleteProductCommand()); the handler method of DeleteProductCommandHandler class should get invoke


Solution

  • You incorrectly defined IServiceBus interface:

    public interface IServiceBus {
        <C,R> R send(C c);
    }
    

    should be:

    public interface IServiceBus<C,R> {
        R send(C c);
    }
    

    UPD. Very basic example of registry.

    public interface IRequestHandler<C, R> {
    
        R handler(C c);
    
        Class<C> getCmdType();
        
    }
    
    public class ServiceBus implements IServiceBus {
    
        private final Map<Class<?>, IRequestHandler<?, ?>> handlerMap;
    
        public ServiceBus(List<IRequestHandler<?, ?>> handlers) {
            handlerMap = handlers.stream()
                    .collect(toMap(
                            IRequestHandler::getCmdType,
                            Function.identity()
                    ));
        }
    
        @Override
        public <C, R> R send(C c) {
            IRequestHandler<C, R> handler = (IRequestHandler<C, R>) handlerMap.get(c.getClass());
            if (handler == null) {
                throw new UnsupportedOperationException("Unsupported command: " + c.getClass());
            }
            return handler.handler(c);
        }
    
    }