maxiangelo
maxiangelo

Reputation: 155

Spring choose bean implementation at runtime from properties

I'm Aware that this issue is almost the same as solved in this answer but it's not working for me and my setup is also a bit different.

I want to choose between two implementations of the FooRepository interface. For this, I created the RepositoryManager Configuration. In theory, only one bean should exist at runtime because of the excluding conditions.

In all cases, the "postgres.active" property is set to false.

@Configuration
public class RepositoryManager {

   @Bean(name = "repositoryQualifier")
   @ConditionalOnProperty(
           value="postgres.active",
           havingValue = "true")
   public FooRepository managedRepository(PostgresRepository postgresRepository){
       return postgresRepository;
   }

   @Bean(name = "repositoryQualifier")
   @ConditionalOnProperty(
           value="postgres.active",
           havingValue = "false")
   public FooRepository managedRepository(RedisRepository redisRepository){
       return  redisRepository;
   }
}
@RestController
public class BarService{

    private final FooRepository repository;


    @Autowired
    public BarService(
            @Qualifier("repositoryQualifier") final FooRepository repository,
    ) {
        this.repository = repository;
    }
}

When I try to run this example Spring throws this error:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying
bean of type 'org.test.FooRepository' available: expected 
at least 1 bean which qualifies as autowire candidate. Dependency annotations: 
{@org.springframework.beans.factory.annotation.Qualifier(value="repositoryQualifier")

If I comment one of the Beans and remove the condition from the not commented one it finds the bean so it shouldn't be an issue with locating the package or the bean. I'm desperate, I'm already struggling with this for 6h now

Upvotes: 1

Views: 3133

Answers (2)

Tommy Brettschneider
Tommy Brettschneider

Reputation: 1490

PostgresRepository and RedisRepository are subclasses of or implement FooRepository, right? please try out if it works without specifying an explicit bean name in the @Bean annotations - also it might also be an option to use @ConditionalOnExpression instead but ofc your way should basically also work just fine, e.g. as follows:

@Configuration
public class RepositoryManager {

   @Bean
   @ConditionalOnExpression("${postgres.active}")
   public FooRepository managedRepository(PostgresRepository postgresRepository){
       return postgresRepository;
   }

   @Bean
   @ConditionalOnExpression("!${postgres.active}")
   public FooRepository managedRepository(RedisRepository redisRepository){
       return  redisRepository;
   }
}

@RestController
public class BarService{

    private final FooRepository repository;

    @Autowired
    public BarService(final FooRepository repository,
    ) {
        this.repository = repository;
    }
}

Upvotes: 2

epushor
epushor

Reputation: 66

Maybe try using the Bean name:

@Autowired
    public BarService(@Qualifier("repositoryQualifier") FooRepository managedRepository) {
repository = managedRepository;
}

Also, why are you using the same Qualifier name for both methods ? Try also to change the name of the second method.

Upvotes: 0

Related Questions