Home > Software design >  Generic class registry for command and handler in Java with Micronaut
Generic class registry for command and handler in Java with Micronaut

Time:12-12

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

CodePudding user response:

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);
    }

}
  • Related