Search code examples
javajava-8java-11java-17

Class registry in Java with Micronaut


I am trying to do the class registry in java using the below code

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

public interface IRequestHandler<C , R> {
    R handler(C c);
    default Class<C> getCmdType(){
        return (Class<C>) this.getClass();
    };

}

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

controller

public Mono<MutableHttpResponse<?>> getById(@NotBlank String id) {
        var item = _iserviceBus.<CreateProductCommand, CreateProductCommand>send(new CreateProductCommand());
        return null;
    }

On

handlerMap = handlers.stream()
                .collect(toMap(
                        IRequestHandler::getCmdType,
                        Function.identity()
                ));

The return of getCmdType is not correct and not sure about Function.identity(). Threfore IRequestHandler<C, R> handler = (IRequestHandler<C, R>) handlerMap.get(c.getClass()); is always null

What is the best way to get the command and register with the handler


Solution

  • There are several things about your design that can't work and I am not sure what the real requirements are given what is in the question but the project at github.com/jeffbrown/sanjaisyinterfaces should help.

    src/main/java/sanjaisyinterfaces/SomeReturnType.java

    package sanjaisyinterfaces;
    
    public class SomeReturnType {
    }
    

    src/main/java/sanjaisyinterfaces/SomeOtherReturnType.java

    package sanjaisyinterfaces;
    
    public class SomeOtherReturnType {
    }
    

    src/main/java/sanjaisyinterfaces/CommandType.java

    package sanjaisyinterfaces;
    
    public interface CommandType {
    }
    

    src/main/java/sanjaisyinterfaces/SomeCommandType.java

    package sanjaisyinterfaces;
    
    public class SomeCommandType implements CommandType {
    }
    

    src/main/java/sanjaisyinterfaces/SomeOtherCommandType.java

    package sanjaisyinterfaces;
    
    public class SomeOtherCommandType implements CommandType {
    }
    

    src/main/java/sanjaisyinterfaces/IRequestHandler.java

    package sanjaisyinterfaces;

    public interface IRequestHandler<C extends CommandType, R> {
        R handler(C c);
        Class<C> getCmdType();
    }
    

    src/main/java/sanjaisyinterfaces/SomeRequestHandler.java

    package sanjaisyinterfaces;
    
    import jakarta.inject.Singleton;
    
    @Singleton
    public class SomeRequestHandler implements IRequestHandler<SomeCommandType, SomeReturnType> {
    
        @Override
        public SomeReturnType handler(SomeCommandType someCommandType) {
            System.out.println("SomeRequestHandler is handling a request for SomeCommandType");
            // do whatever needs to be done here
            return null;
        }
    
        @Override
        public Class getCmdType() {
            return SomeCommandType.class;
        }
    }
    

    src/main/java/sanjaisyinterfaces/SomeOtherRequestHandler.java

    package sanjaisyinterfaces;
    
    import jakarta.inject.Singleton;
    
    @Singleton
    public class SomeOtherRequestHandler implements IRequestHandler<SomeOtherCommandType, SomeOtherReturnType> {
    
        @Override
        public SomeOtherReturnType handler(SomeOtherCommandType someCommandType) {
            System.out.println("SomeOtherRequestHandler is handling a request for SomeOtherCommandType");
            // do whatever needs to be done here
            return null;
        }
    
        @Override
        public Class getCmdType() {
            return SomeOtherCommandType.class;
        }
    }
    

    src/main/java/sanjaisyinterfaces/IServiceBus.java

    package sanjaisyinterfaces;
    
    public interface IServiceBus {
        Object send(CommandType c);
    }
    

    src/main/java/sanjaisyinterfaces/ServiceBus.java

    package sanjaisyinterfaces;
    
    import jakarta.inject.Singleton;
    
    import java.util.List;
    import java.util.Map;
    import java.util.function.Function;
    
    import static java.util.stream.Collectors.toMap;
    
    @Singleton
    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 Object send(CommandType c) {
            IRequestHandler handler = handlerMap.get(c.getClass());
            if (handler == null)
                throw new UnsupportedOperationException("Unsupported command: " + c.getClass());
            return handler.handler(c);
        }
    }
    

    src/main/java/sanjaisyinterfaces/SanjaisyinterfacesCommand.java

    package sanjaisyinterfaces;
    
    import io.micronaut.configuration.picocli.PicocliRunner;
    import io.micronaut.context.ApplicationContext;
    
    import jakarta.inject.Inject;
    import picocli.CommandLine;
    import picocli.CommandLine.Command;
    import picocli.CommandLine.Option;
    import picocli.CommandLine.Parameters;
    
    @Command(name = "sanjaisyinterfaces", description = "...",
            mixinStandardHelpOptions = true)
    public class SanjaisyinterfacesCommand implements Runnable {
    
        @Inject
        ServiceBus serviceBus;
    
        public static void main(String[] args) throws Exception {
            PicocliRunner.run(SanjaisyinterfacesCommand.class, args);
        }
    
        public void run() {
            CommandType firstCommand = new SomeCommandType();
            CommandType secondCommand = new SomeOtherCommandType();
            serviceBus.send(firstCommand);
            serviceBus.send(secondCommand);
        }
    }
    

    Running that project indicates that the relationships are being recognized as intended:

    ~ $ mkdir example
    ~ $ cd example
    example $ git clone [email protected]:jeffbrown/sanjaisyinterfaces.git
    Cloning into 'sanjaisyinterfaces'...
    remote: Enumerating objects: 47, done.
    remote: Counting objects: 100% (47/47), done.
    remote: Compressing objects: 100% (35/35), done.
    remote: Total 47 (delta 8), reused 44 (delta 5), pack-reused 0
    Receiving objects: 100% (47/47), 63.88 KiB | 838.00 KiB/s, done.
    Resolving deltas: 100% (8/8), done.
    example $ 
    example $ cd sanjaisyinterfaces 
    sanjaisyinterfaces (main)$ ./gradlew run
    
    > Task :run
    09:10:39.377 [main] INFO  i.m.context.env.DefaultEnvironment - Established active environments: [cli]
    SomeRequestHandler is handling a request for SomeCommandType
    SomeOtherRequestHandler is handling a request for SomeOtherCommandType
    
    sanjaisyinterfaces (main)$