I would like to provide a library that adds JPA entities to the persistence context bootstrapped. Ideally I would like to achieve that without the user having to explicitly configure @EntityScan
to include the package of that library solely by registering some auto configuration.
I've tried both @EntityScan
on a configuration class and a BeanDefinitionRegistryPostProcessor
to trigger EntityScanPackages.register(…)
but EntityScanner
will only apply the autoconfiguration package as fallback if no entity package is configured at all.
I can see that the semantics of @EntityScan
are supposed to stay unchanged. I'd be fine with a programmatic approach, so maybe an explicit method EntityScanPackage.registerAdditional(…)
could populate an additional list that EntityScanner
adds on top of the defaulted base list?
Comment From: wilkinsona
See also #19024, #27549, and #28232.
@odrotbohm, does @AutoConfigurationPackage
come close to what you want?
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: odrotbohm
It does indeed. At least until someone explicitly uses @EntityScan
somewhere in their application configuration in which case the configuration would break. So some way of adding to the entity packages would still be appreciated. I think it'll also make the feature a bit more discoverable. The docs currently don't mention @ACP
and the Javadoc of both annotations don't mention that fallback mechanism either, and the sole presence of @EntityScan
makes it very likely that developers just try to use that if what they want to do is adding entities.
Comment From: wilkinsona
Thanks, @odrotbohm. I'm a bit concerned that providing a mechanism that's always additive will surprise users as it's not very Boot-like to have something that can't be switched off or overridden.
The documentation (both reference and javadoc) for @AutoConfigurationPackage
is definitely lacking at the moment. That's what https://github.com/spring-projects/spring-boot/issues/27549 will address. I wonder if that would be sufficient here? I would expect it to update the reference documentation and the javadoc for both @EntityScan
and @AutoConfigurationPackage
to make the purpose of the two more clear and to highlight that auto-configuration packages are the default packages used for entity scanning, with @EntityScan
being used to take complete control and override those defaults.
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
Comment From: odrotbohm
Apologies for the delayed response. I still wonder whether there's a middle ground here. My primary concern is that you cannot write robust autoconfiguration for a library that wouldn't break apart if the application starts using @EntityScan
. In particular, it would be hard for users to identify the root cause of the problem they start seeing as the app would just fail, claiming that a type is not known as entity, not leaving a clue at what might have caused this. Even if you do, you now have to scatter your @EntityScan
with library specific base packages, just because you might want to align to a slightly unusual package arrangement of your application.
In my particular case, there's no point in adding the JAR to the project unless you actually include those additional entity types because without them the functionality the JAR would like to provide doesn't work properly. Wouldn't it be okay to provide that way of unconditionally adding the type to the entities to bootstrap but then clearly advise autoconfiguration authors to potentially provide library specific means (e.g. a configuration property) to disable that particular aspect if it?
That said, I'd very much appreciate a strong hint in @EntityScan
on that it will disable automatic entity registration by library autoconfiguration in case you decide to go with the documentation-only approach.
Comment From: wilkinsona
In the short term, we're going to improve the documentation of @AutoConfigurationPackage
and @EntityScan
(https://github.com/spring-projects/spring-boot/issues/27549). We'll leave this issue open for consideration in the longer term. @odrotbohm, can you provide a bit more context about the nature of the entities in the library and try to give us a feel for how common you think it is for them to be shared between applications?
Comment From: Bwvolleyball
We have a very simple use case where this exact feature would be quite handy. Right now, we have a custom health indicator that we share across several services, and one of the functions of our health indicator is to insert records of status into the database (via JPA Entities) - each service has it's own database, but this common table in each database.
Right now, we've got the code responsible for this health indicator in a common library, but every consuming service that uses this needs to ensure it also does an @EntityScan
that includes these entities.
We'd like to convert this portion of our library into a proper autoconfigure library, but until the library can self declare/register those entities we can't really do that effectively.
Comment From: wilkinsona
@Bwvolleyball Assuming that the consuming services do not use @EntityScan
, you could use @AutoConfigurationPackage
in your library to add to the packages that are scanned.
Comment From: sterlp
you could use
@AutoConfigurationPackage
in your library to add to the packages
I have the same issue and I had the same solution - but it doesn't always work see: https://github.com/sterlp/spring-persistent-tasks/issues/17
Once any @EntityScan
or @EnableJpaRepositories
annotation is used anywhere in the application, the autoconfiguration mechanism is disabled, breaking any library auto-configuration.
Scenario 1 - happy case:
This works
App
@EnableWebSecurity
@SpringBootApplication
@EnableSpringPersistentTasks
public class ExampleApplication
Lib
@Configuration
@AutoConfigurationPackage(basePackageClasses = EnableSpringPersistentTasks.class)
@ComponentScan(basePackageClasses = EnableSpringPersistentTasks.class)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SpringPersistentTasksConfig
Scenario 2 - App has @EnableJpaRepositories
or envers or something:
Now the jpa repos aren't found anymore in the lib.
App
@EnableWebSecurity
@SpringBootApplication
@EnableJpaRepositories // this basically excludes the lib JPA repositories
@EnableSpringPersistentTasks
public class ExampleApplication
Lib
@Configuration
@AutoConfigurationPackage(basePackageClasses = EnableSpringPersistentTasks.class)
@ComponentScan(basePackageClasses = EnableSpringPersistentTasks.class)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SpringPersistentTasksConfig
Scenario 3 - use entity scan in Lib:
Now the JPA repos and Entities aren't found in the app anymore... .
App
@EnableWebSecurity
@SpringBootApplication
@EnableJpaRepositories // this basically excludes the lib JPA repositories
@EnableSpringPersistentTasks
public class ExampleApplication
Lib
@Configuration
@EnableJpaRepositories(basePackageClasses = EnableSpringPersistentTasks.class)
@EntityScan(basePackageClasses = EnableSpringPersistentTasks.class)
@ComponentScan(basePackageClasses = EnableSpringPersistentTasks.class)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SpringPersistentTasksConfig
Scenario 4 - use entity scan everywhere:
This works now too. But not a really clean solution.
App
@SpringBootApplication
@EnableJpaRepositories
@EntityScan
@EnableSpringPersistentTasks
public class ExampleApplication {
Lib
@Configuration
@EnableJpaRepositories(basePackageClasses = EnableSpringPersistentTasks.class)
@EntityScan(basePackageClasses = EnableSpringPersistentTasks.class)
@ComponentScan(basePackageClasses = EnableSpringPersistentTasks.class)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SpringPersistentTasksConfig
In short where is no real working scenario where I can add in a clean way Entities and JPA Spring Data Repositories to Spring, without messing with the hosting app
. Well non I currently know... .
Comment From: sterlp
I had the following idea - somehow hopping that it may work - and it doesn't:
public class SptEntityPackageRegistrar {
@Configuration
@ConditionalOnBean(annotation = EntityScan.class)
@EntityScan(basePackageClasses = EnableSpringPersistentTasks.class)
public static class AddJpaEntities {
// Activated when explicit @EntityScan is detected
}
@Configuration
@ConditionalOnBean(annotation = EnableJpaRepositories.class)
@EnableJpaRepositories(basePackageClasses = EnableSpringPersistentTasks.class)
public static class AddJpaRepositories {
// Activated when explicit @EnableJpaRepositories is detected
}
}
- I think it should have worked based on the spring java doc
- that at least how I would reason about it
- if any bean annotated with
EntityScan
exists - enableAddJpaEntities
config - if any bean annotated with
EnableJpaRepositories
exists - enableAddJpaRepositories
config
=> I would consider it a bug in spring, how do you guys feel about it?
I had the following idea too - not expecting that it may work - and it doesn't - just for reference:
public class SpringPersistentTasksConfig implements BeanDefinitionRegistryPostProcessor, Ordered {
@Override
public void postProcessBeanDefinitionRegistry(@NonNull BeanDefinitionRegistry registry) {
EntityScanPackages.register(registry, EnableSpringPersistentTasks.class.getName());
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
Comment From: philwebb
I think it should have worked based on the spring java doc
Hard to say from the snippets, but it doesn't look like those @Configuration
classes are auto-configuration. If they're not, then @ConditionalOnBean
won't work.
From the javadoc:
The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only. If a candidate bean may be created by another auto-configuration, make sure that the one using this condition runs after.