Search code examples
javaspringhibernatespring-bootspring-el

Using spel with Hibernate Table and flyway


Given such a SPEL expression in application.yml file for a spring boot app -

database:
      schema: '#{"${ENV_VAR:}".equals("")?"DEMO":"DEMO_${ENV_VAR:}"}'

Following works in code and it prints substituted value like DEMO_XYZ / DEMO if ${ENV_VAR} = XYZ

@Value("${database.schema}")
private String schema;

But a Hibernate JPA entity with Table annotation is not able to take the SPEL enabled variable here as schema -

@Entity
@Table(name = "TABLE_A", schema="${database.schema}") // prints whole spel expression here 
public class TableA { ...

Even below is not able to use substituted value for SPEL using default-schema -

spring:  
  jpa:
    show-sql: true
    properties:
      hibernate:
        default_schema: ${database.schema} // prints whole value here as well

Seems like flyway is not able to use a SPEL variable as well defined already in application.yml

spring:  
  flyway:
    jdbc-url: ...
    schemas: ${database.schema}

Any way for hibernate.default_schema and flyway.schemas to accept a SPEL expression like ${database.schema} in same YML ?


Solution

  • Fixed it by programatically creating Hibernate JPA beans and Flyway beans like below instead of using YML since only @Value annotations is able to read SPEL

    database:
          schema: '#{"${ENV_VAR:}".equals("")?"DEMO":"DEMO_${ENV_VAR:}"}'
    

    Database config

    
    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(basePackages = {"com.xyz"})
    @EntityScan(basePackages = {"com.xyz"})
    public class DbConfig
    {
        @Value("${database.schema}")
        private String schema; 
    
        @Bean
        public EntityManager entityManager(SessionFactory sessionFactory)
        {
            return sessionFactory.createEntityManager();
        }
    
        @Bean
        public PlatformTransactionManager transactionManager()
        {
            return new JpaTransactionManager();
        }
    
        @Bean
        public HikariConfig hikariConfig()
        {
            HikariConfig hikariConfig = new HikariConfig();
            hikariConfig.setDriverClassName("net.client.jdbc.Driverx");
            hikariConfig.setJdbcUrl(url);
            Properties props = new Properties();
            props.put("user", user);
            props.put("password", password);
            props.put("db", db);
            props.put("schema", schema);  // SCHEMA is from SPEL
            hikariConfig.setDataSourceProperties(props);
            return hikariConfig;
        }
    
        @Bean
        public DataSource dataSource(HikariConfig hikariConfig)
        {
            HikariDataSource dataSource = new HikariDataSource(hikariConfig);
            return dataSource;
        }
    
        @Bean
        public LocalSessionFactoryBean entityManagerFactory(DataSource snowflakeDataSource)
        {
            LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
            localSessionFactoryBean.setDataSource(dataSource);
            localSessionFactoryBean.setPackagesToScan("com.xyz");
            Properties properties = new Properties();
            properties.setProperty("hibernate.default_schema", schema);
            properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
            properties.setProperty("hibernate.show_sql", "true");
            properties.setProperty("hibernate.format_sql", "true");
            localSessionFactoryBean.setHibernateProperties(properties);
            return localSessionFactoryBean;
        }
    

    Flyway Config

        @Value("${database.schema}")
        private String schema;
    
        @Bean
        public Flyway flyway(DataSource dataSource)
        {
            Flyway flyWay = Flyway.configure()
                .dataSource(dataSource)
                .locations("classpath:/somefolder/migrations")
                .schemas(schema)  // SCHEMA is from SPEL
                .baselineVersion("1.0")
                .sqlMigrationPrefix("V")
                .sqlMigrationSuffixes(".sql")
                .placeholders(Map.of("key1", value1,
                    "key2", value2))
                .placeholderReplacement(true)
                .placeholderPrefix("%")
                .placeholderSuffix("%")
                .load();
            flyWay.migrate();
            return flyWay;
        }