Search code examples
dependency-injectionjavabeansmicronaut

How to resolve NonUniqueBeanException: Multiple possible bean candidates found in micron


I am getting NonUniqueBeanException: Multiple possible bean candidates found: for the below Micronaut code:

@Context
@Slf4j
@AllArgsConstructor
public class RemoteService {
   private final Provider<Session> remoteSessionFactory;
}

I have 2 implementations for the Provider

@Slf4j
@Prototype
@AllArgsConstructor
public class RemoteSessionFactoryA implements Provider<Session> {
    //some code here
}

@Slf4j
@Prototype
@AllArgsConstructor
public class RemoteSessionFactoryB implements Provider<Session> {
    //some code here
}

I have even tried like this but still getting the same error:

private final @Named("remoteSessionFactoryA) Provider<Session> remoteSessionFactory;

Please suggest how to resolve this.

Regards


Solution

  • The Named annotation should be part of the constructor argument. Since let Lombok generating the constructor there is no way to set the @Named annotation by Lombok.

    I recommend to write the constructor yourself such as:

    @Context
    @Slf4j
    public class RemoteService {
       private final Provider<Session> remoteSessionFactory;
    
       public RemoteService(@Named("remoteSessionFactoryA") Provider<Session> remoteSessionFactory) {
           this.remoteSessionFactory = remoteSessionFactory;
       }
    }
    

    Micronaut can’t inject the bean because the name doesn’t match the naming convention. The Micronaut document states:

    Micronaut is capable of injecting V8Engine in the previous example, because: @Named qualifier value (v8) + type being injected simple name (Engine) == (case-insensitive) == The simple name of a bean of type Engine (V8Engine) You can also declare @Named at the class level of a bean to explicitly define the name of the bean.

    So if you put the names on the source beans Micronaut will pick up the name you defined.

    @Slf4j
    @Prototype
    @AllArgsConstructor
    @Named("remoteSessionFactoryA") 
    public class RemoteSessionFactoryA implements Provider<Session> {
        //some code here
    }
    
    @Slf4j
    @Prototype
    @AllArgsConstructor
    @Named("remoteSessionFactoryB") 
    public class RemoteSessionFactoryB implements Provider<Session> {
        //some code here
    }
    

    Alternatively create qualifier annotations.

    @Qualifier
    @Retention(RUNTIME)
    public @interface FactoryA {
    }
    
    @Qualifier
    @Retention(RUNTIME)
    public @interface FactoryB {
    }
    

    and then inject it like this

    @Context
    @Slf4j
    public class RemoteService {
       private final Provider<Session> remoteSessionFactory;
    
       public RemoteService(@FactoryA Provider<Session> remoteSessionFactory) {
           this.remoteSessionFactory = remoteSessionFactory;
       }
    }