I have a spring-boot project A which can run on its own, or, alternatively can run "embedded" as a dependency of another spring-boot project B. In the later case, project B which wants to use project A loads the configuration of A with a custom annotation @EnableProjectA. (Which basically just @Imports the embedded @Configuration so both coexist in the same application context.)

Since both projects have JPA repositories and entities, both require @EnableJpaRepositories / @EntityScan - which spring boot usually automatically provides. This fails however, since one @EntityScan/@EnableJpaRepositories apparently overwrites the packages to scan. So the entities/repositories of one project are not found.

breaks:

@SpringBootApplication
@EnableProjectA 
public class ProjectB {
   // Not working because repos/entities are not found/scanned in this project
}

Workaround

However, I have found a workaround. If the embedded configuration specifies the scanned packages of itself explicitly, and the consuming project redefines the @EnableJpaRepositories / @EntityScan it works.

Project A Embedded Config

@Configuration
@ConditionalOnProperty(value = "projectA.embedded.enabled", matchIfMissing = true)
@ComponentScan("com.projectA")
@EntityScan("com.projectA")
@EnableJpaRepositories("com.projectA")
public class EmbeddedConfigurationA {
}

Project B

@SpringBootApplication
@EnableJpaRepositories  // Required because of @EnableProjectA
@EntityScan             // Required because of @EnableProjectA
@EnableProjectA 
public class ProjectB {
}

Is this a bug? (Or more likely just a special case not supported?)

Comment From: snicoll

I am actually quite surprised that the workaround B works. The documentation has an explicit note about it so I am not sure what you'd like Spring Boot to do. Combining two spring boot applications is probably a smell and you should try to avoid doing that if you can. Separating the configuration and importing it explicitly is the way to go.

Comment From: philwebb

I think the problem is that auto-configuration is backing off when it sees @EnableJpaRepositories in any form. If you look at JpaRepositoriesAutoConfiguration you'll see it's got the following condition:

@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class,
        JpaRepositoryConfigExtension.class })

JpaRepositoryFactoryBean is added by @EnableJpaRepositories.

Usually this behavior is exactly what the user wants; if they take control of JPA repositories themselves they don't want any auto-configuration involved. In your case, the @Import of Project A's configuration is triggering the condition.

One option that might work for you is to use the AutoConfigurationPackages class to register the base packages and drop @EnableJpaRepositories and @EntityScan entirely from project A.

Comment From: philwebb

I was too slow typing my response. I agree with @snicoll that the approach in general isn't ideal.

Comment From: IsNull

Thank you both for your detailed answers.

Combining two spring boot applications is probably a smell and you should try to avoid doing that if you can. Separating the configuration and importing it explicitly is the way to go.

Well it is indeed a bit unlucky to have to include a boot project into another one. The reason is that the projects are actually designed as Microservices but i try also to bundle them for a desktop like deployment scenario.

Anyway, if I get you correctly, you are saying I should not use any kind of package scanning in a library project. Instead all beans should be introduced using configuration classes? If so, then I have to find a way to register entities manually with code since they are not beans.

Comment From: fjbeli

There is a valid case where you have a library (depends on spring auto configuration capability) to serve common stuff for other spring boot applications. This is proposed already here https://github.com/spring-projects/spring-boot/issues/30064.