I'm making some tests using custom starters for spring boot. I managed to configure everything except the entities. I've tryed using @Import
to load entities in the @AutoConfiguration
class but this does not work. Instead if we use @EntityScan
in the starter the entities are loaded, but if you import this starter and have entities in the project that depends on the starter you are forced to use @EntityScan
also in it, and in my opinion this breaks the autoconfiguration meaning of the starter because when you import a starter you should do nothing in order to use it, yes you can override the default configuration but not forced to do anything maybe to declare some properties.
Example of autoconfiguration class in the starter:
@AutoConfiguration(after = JpaRepositoriesAutoConfiguration.class)
//@AutoConfigureAfter(JpaRepositoriesAutoConfiguration.class)
@EnableJpaRepositories(basePackages = "com.example.springbootstarterexample.repository")
@Import({SomeServiceImpl.class, SomeEntityController.class /*, SomeEntity.class NOT WORKING*/})
@EntityScan(basePackages = "com.example.springbootstarterexample.domain")
public class ExampleAutoConfiguration {
}
and then if you have entities in the consumer of the starter you have to do this if you have entities in it:
@SpringBootApplication
@EntityScan(basePackages = "com.example.springbootconsumer.model")
public class SpringBootConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootConsumerApplication.class, args);
}
}
Otherwise we can remove @EntityScan
from the starter and do this in the consumer:
@SpringBootApplication
@EntityScan(basePackages = {"com.example.springbootconsumer.model", "com.example.springbootstarterexample.domain"})
public class SpringBootConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootConsumerApplication.class, args);
}
}
but this totaly brakes the autoconfiguration, because you have to know where the entities are in the starter in order to start the application. I've write an example if interested.
CodePudding user response:
You need to add @ComponentScan
to configuration bean.
@AutoConfiguration(after = JpaRepositoriesAutoConfiguration.class)
//@AutoConfigureAfter(JpaRepositoriesAutoConfiguration.class)
@EnableJpaRepositories(basePackages = "com.example.springbootstarterexample.repository")
@ComponentScan("com.example.springbootstarterexample")
@EntityScan(basePackages = "com.example.springbootstarterexample.domain")
public class ExampleAutoConfiguration {
}
CodePudding user response:
An interesting problem, but if you had an agreed way with consumers of your library on how to share information where their entities are, like for example they would provide a META-INF/entityscanforyouapp
file with a list of packages where they have their entities
Consumer 1 would create META-INF/entityscanforyouapp
com.consumerapp1.entities
Consumer 1 would create META-INF/entityscanforyouapp
com.consumerapp2.entities
You could discover all these files and then just create an EntityManagerFactory bean that would include all the discovered packages
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder, DataSource dataSource) {
Map<String, Object> vendorProperties = <... read the additional hibernate properties if you need...>;
String[] packagesWithEntities = discoverAllThePackages();
return factoryBuilder.dataSource(datasource).packages(packagesWithEntities).properties(vendorProperties).build();
}
This is kind of "rough and ready" but should provide a good starting point if you want to go that way.