Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document @SpringBootApplication scanBasePackages restrictions #18109

Closed
behrangsa opened this issue Sep 3, 2019 · 4 comments

Comments

@behrangsa
Copy link

commented Sep 3, 2019

If I write an Application class in com.acme.app and annotate in such a way to drive Spring scan its parent package too:

package com.acme.app;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = {"com.acme"})
public class Application {
    // ...
}

Then if I have my entity and repository classes defined under sibling packages to com.acme.app:

  • com.acme.entities and
  • com.acme.repos

respectively, they won't be picked up by Spring Boot and in order to make them recognized I have to explicitly use EntityScan and EnableJpaRepositories:

package com.acme.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication(scanBasePackages = {"com.acme"})
@EnableJpaRepositories(basePackages = {"com.acme.repositories"})
@EntityScan(basePackages =  {"com.acme.entities"})
public class Application {
...

I was stepping through the Spring Boot code to see why is this happening and it boils down to @SpringBootApplication(scanBasePackages = {"com.acme"}) not adding com.acme to org.springframework.boot.autoconfigure.AutoConfigurationPackages.BasePackages#packages (it will only add the package of the Application class, com.acme.app to BasePackages#packages).

What is the thinking behind this logic? Wouldn't it make sense to make @SpringBootApplication(scanBasePackages = {"com.acme"}) add com.acme to BasePackages#packages too?

@philwebb

This comment has been minimized.

Copy link
Member

commented Sep 3, 2019

I agree that this is a little confusing, although at this point it's hard to see how we can change things without breaking existing code.

The main reason it ended up like this is that component scanning isn't directly implement by Spring Boot. We rely on @ComponentScan from the Spring Framework and the scanBasePackages is simply an alias for @ComponentScan.basePackages. The AutoConfigurationPackages functionality is implemented via @AutoConfigurationPackage (on @EnableAutoConfiguration).

All things considered, I don't think there's much we can do about this now. Any fix is likely to be quite involved and we'd need to add new attributes to @SpringBootApplication so we can keep back-compatibilty. I think new attributes are likely to add even more confusion.

Since most users appear to be following our recommended project structure, I think users needing to specify the three annotations (@SpringBootApplication, @EnableJpaRepositories and @EntityScan) themselves is the least bad option.

I'm sorry that it's a bit more verbose than we'd ideally like.

@philwebb philwebb closed this Sep 3, 2019
@philwebb philwebb changed the title @SpringBootApplication(scanBasePackages = {"com.acme"}) on a class defined in com.acme.app should probably pick up repositories and entities defned under com.acme.repos and com.acme.entities @SpringBootApplication.scanBasePackages on a class defined in com.acme.app should pick up repositories and entities Sep 3, 2019
@behrangsa

This comment has been minimized.

Copy link
Author

commented Sep 3, 2019

I think the least that can be done is updating the documentation and pointing this out. Yesterday one of my teammates spent an entire day trying to debug why his repository beans are not being found and injected... 😬

@behrangsa

This comment has been minimized.

Copy link
Author

commented Sep 3, 2019

Also regarding the project structure:

We have a multi module Spring project comprised of these modules (I am using dummy names here):

  • Authentication API in com.example.auth (i.e. the entry point class if com.example.auth.Application)
  • Booking API in com.example.booking (i.e. the entry point class if com.example.booking.Application)
  • Payment API in com.example.payment (i.e. the entry point class if com.example.payment.Application)

And we have some aux modules too:

  • com.example.repositories
  • com.example.entities
  • com.example.utils
  • etc.

I think a structure like this is probably quite common in multi module projects. And I think it is not a good idea to have all three Application classes defined in the same level at com.example.

It is not a big deal in general (we have a meta annotation @ExampleApplication that itself is annotated with @SpringBootApplication, @EntityScan, and @EnableJpaRepositories, but the issue described in the ticket has had me and a couple of my teammates confused and scratch our heads in surprise in the past couple of years or so. :)

So this might be worth mentioning in the docs...

@philwebb

This comment has been minimized.

Copy link
Member

commented Sep 3, 2019

Good points. I've reopened the issue as a documentation enhancement.

@philwebb philwebb changed the title @SpringBootApplication.scanBasePackages on a class defined in com.acme.app should pick up repositories and entities Document @SpringBootApplication scanBasePackages restrictions Sep 3, 2019
@philwebb philwebb modified the milestones: 2.1.x, 2.1.8 Sep 3, 2019
@philwebb philwebb closed this in 43108d5 Sep 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.