0

I am trying to complete this class which will allow me to switch between repositories. I am not sure how to do it. I want to use default instances via Spring Boot Injection! I know that I am doing it wrong, I cannot pass null value to those class init.

@Configuration
public class ApiRepositoryConfig {

    @Bean
    @ConditionalOnProperty(name = "db.dialect", havingValue = "postgres", matchIfMissing = true)
    public ApiRepository apiJpaRepository() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.tw.api");
        return new ApiJpaRepository(ApiApplication.class, emf.createEntityManager());
    }

    @Bean
    @ConditionalOnProperty(name = "db.dialect", havingValue = "mongo")
    public ApiRepository apiMongoRepository() {
        return new ApiMongoRepository(null, null);
    }
}

ApiJpaRepository class

@NoRepositoryBean
public class ApiJpaRepository<T, Id>
        extends SimpleJpaRepository<T, Id> implements ApiRepository<T, Id> {

    public ApiJpaRepository(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
    }
}

ApiMongoRepository class

public class ApiMongoRepository<T, Id> extends SimpleMongoRepository<T, Id> implements ApiRepository<T, Id> {

    public ApiMongoRepository(MongoEntityInformation<T, Id> metadata, MongoOperations mongoOperations) {
        super(metadata, mongoOperations);
    }
}

Base Interface Class

public interface ApiRepository<T, Id> extends CrudRepository<T, Id> {
}

Here is the project link if anyone wants to have a full picture, https://github.com/er310/boot-camp/tree/master/api

Ehasan
  • 3
  • 4
  • 1
    https://medium.com/swlh/multi-tenancy-implementation-using-spring-boot-hibernate-6a8e3ecb251a try to check this post as example, i think it's good enough for start research – Ishikawa Yoshi Apr 01 '20 at 16:09
  • @Ishikawa Yoshi - thanks for the reply, I looked into the blog. It's bigger picture but I want something simple like just defining spring.db.dialact=mongodb in application.properties. Then the conf class set the dependency accordingly. – Ehasan Apr 01 '20 at 23:17
  • when i understand right, [this question](https://stackoverflow.com/q/34350865/5923559) is similar/promising – xerx593 Apr 04 '20 at 21:03
  • ..and in the current situation, you can (at least) try to "auto wire" the needed parameters (instead of`null, null` ? ..as the EntityManagerFactory! (don't create it, "auto wire" it)) – xerx593 Apr 04 '20 at 21:10
  • you can also: move the `@ConditionalOn..` annotations onto the implementing (*Repository) classes(, ensure component scan for these, omit them from @Configuration) and then (if the conditions are correct and exclusive) spring will wire the rest ;) – xerx593 Apr 04 '20 at 21:18

2 Answers2

0

I managed to fix the issue by implementing factory bean for each of the datasource and configuration pointing to them. Additionally, I had to exclude spring jpa & mongo configuration from @SpringBootApplication.

Fixes are available here,

https://github.com/er310/boot-camp/tree/master/api

Ehasan
  • 3
  • 4
0

You were close.

  1. With ConditionalOn..
//matchIfMissing = true for primary datasource
@Bean
@ConditionalOnProperty(value = "db.dialect.postgres.enabled", havingValue = "true", matchIfMissing = true)
...
@Bean
@ConditionalOnProperty(value = "db.dialect.mongo.enabled", havingValue = "true")

Risks: if some one puts enable for several datasource application will crash, eventually

  1. Spring profiles approach
@Configuration
@Profile("mongo")
public class MongoConfiguration {
    ... all the mongo beans
}

Same for any other datasource
Usage:

#application.yml

spring:
  profiles:
    active: mongo

I'd suggest using profiles, cause it is more consciously to see what is enabled or not.
Like you or code reviewer will definitely see that you activate several database profiles at the same time

Artem Ptushkin
  • 1,151
  • 9
  • 17