Marcel
Marcel

Reputation: 4402

(Workaround for) Use of @ConditionalOnProperty on Entity

We have a Spring-Boot application with some database-entity-classes.

We use ddl-auto: validate to make sure the connected database has correct schema.

Now we are at the point where we add a feature which is toggle-able to match different environments, the NewFeatureService is annotated with @ConditionalOnProperty("newfeature.enabled").

Everything works fine until here.

The problem is that the feature requires a database entity.

@Entity
@ConditionalOnProperty("newfeature.enabled")  // <--- doesn't work
public class NewFeatureEnitity{...}

@ConditionalOnProperty will obviously not work but what is a good way to tell Hibernate only to validate this Entity against the database if a property is set.

What we don't want:

Upvotes: 6

Views: 3845

Answers (2)

Yannic B&#252;rgmann
Yannic B&#252;rgmann

Reputation: 6581

Just to be sure that it's not overseen i want to provide my suggestion as an answer.

It makes a bit more use of spring-boot than the answer provided by O.Badr.

You could configure your spring-boot application to only scan your core entities like this:

@SpringBootApplication
@EntityScan("my.application.core")
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

So you are able to provide your optional entities (and features) in a package like my.application.features (feel free to use any other structure but a package outside the previously specified base package).

@ConditionalOnProperty("newfeature.enabled")
@Configuration
@EntityScan("my.application.features.thefeature")
public class MyFeatureConfiguration {
  /*
  * No Configuration needed for scanning of entities. 
  * Do here whatever else should be configured for this feature.
  */
}

Upvotes: 8

O.Badr
O.Badr

Reputation: 3141

Hibernate will consider every @Entity class as an entity, as long as the class/package is included in Hibernate setting. But, Spring came up with handy (and simple) solutions, so as you mention, you can use @ConditionalOnProperty (I assume that you're using java configuration for Spring):

In your Hibernate configuration class :

@Configuration
......
public class HibernateConfig {

   @Bean
   @ConditionalOnProperty(name = "newfeature.enabled")
   public String newFeaturePackageToScan(){
        return "com.example.so.entity.newfeature";
   }

   @Bean
   public String commonPackageToScan(){
       return "com.example.so.entity.common";
   }

   @Bean
   public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Autowired DataSource dataSource, @Autowired  String[] packagesToScan){
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        Properties jpaProperties = new Properties();

        jpaProperties.put(AvailableSettings.HBM2DDL_AUTO, "validate");
        jpaProperties.put(...); // other properties

        emf.setDataSource(dataSource);
        emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

        emf.setJpaProperties(jpaProperties);
        emf.setPackagesToScan(packagesToScan);

        return emf;
   }

...
} 

@Autowired String[] packagesToScan will combine all defined string beans in this array (I assume that you do not define any other string bean), so you can add as much as String bean for other features, You can check documentation for more details.

The point is to separate a newfeature package from common package in a way that the common is not a parent package.

Upvotes: 1

Related Questions