When using @EntityScan
all entities in the specified basePackages are picked up by the scan. For certain reasons, we would like to avoid that.
We had the idea to replace the @EntityScan
annotation with manual configuration to include only specific entity classes, instead of every entity in the package, by calling factoryBean.setManagedTypes(managedTypes)
.
There is one baeldung post that goes into this direction, but the focus is not on setting single managedTypes.
Actually, we were surprised that we couldn't find any blogpost, stackoverflow question, etc. dealing with the question "Is it possible to configure @EntityScan or an alternative to only track single classes, not full packages?".
Are there any issues or drawbacks in doing so, in a Spring Boot application?
The javadoc of LocalContainerEntityManagerFactoryBean.setManagedTypes
even says:
Set the PersistenceManagedTypes to use to build the list of managed types as an alternative to entity scanning. -- https://docs.spring.io...orm/jpa/LocalContainerEntityManagerFactoryBean
I created an example project to demonstrate the idea: https://github.com/frankkriegl-zero/jpa-managed-types-sample/tree/stackoverflow-question-79541611
From the configuration class JpaConfig:
@Configuration
public class JpaConfig {
List<String> sharedManagedEntityClassNames = Stream.of(
external.model.Book.class // located in a 'remote' package, outside of org.example.bookstore
).map(Class::getName).toList();
List<String> managedEntityPackages = List.of(
"org.example.bookstore.model"
);
@Bean(name = "persistenceManagedTypes")
PersistenceManagedTypes persistenceManagedTypes(ResourceLoader resourceLoader) {
var scanResult = new PersistenceManagedTypesScanner(resourceLoader)
.scan(managedEntityPackages.toArray(new String[0]));
// merge the shared managed entity class names with the scanned ones
List<String> managedClassNames = new ArrayList<>();
managedClassNames.addAll(sharedManagedEntityClassNames);
managedClassNames.addAll(scanResult.getManagedClassNames());
return PersistenceManagedTypes.of(managedClassNames, Collections.emptyList());
}
// entityManagerFactoryBean
}
This is how we override the entityManagerFactory bean:
@Bean(name = "entityManagerFactory")
public EntityManagerFactory entityManagerFactory(DataSource dataSource,
PersistenceManagedTypes managedTypes) {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factoryBean.setManagedTypes(managedTypes); // alternative to @EntityScan and @EnableJpaRepositories
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
We do not feel too confident about creating our own emFactory bean, as this is the backbone of every JPA related logic in a JPA-based application:
Any advice or experience with using setManagedTypes(PersistenceManagedTypes)
instead of @EntityScan
?
Thanks!
If my memory serves me right that could be implemented using following way:
@Bean
public HibernatePropertiesCustomizer extraEntities() {
return map -> {
List<Class> extra = new ArrayList<>();
extra.add(MyEntity.class);
var existing = map.get(AvailableSettings.LOADED_CLASSES);
if (existing != null) {
extra.addAll((Collection<Class>) existing);
}
map.put(AvailableSettings.LOADED_CLASSES, extra);
};
}