0

I'm working on an application we'll call MyApp. Previously each application at my workplace had its own set of standard services and repositories; what I'm trying to do is move those services and repositories to a JAR we'll call MyServices hosted on GitHub packages that applications can import, so that when changes are made to services, the parent applications can simply update the JAR version rather than each copying and pasting the changes in.

I created a test environment in MyServices that works fine. The problems come when I try to import MyServices into MyApp and run it. I just can't figure out how to correctly scan the services with Spring. I'm getting many errors for nearly all of my services such as:

Field userRepository in com.mycompany.myservices.backend.security.LoginSuccessHandler required a bean of type 'com.mycompany.myservices.backend.data.repositories.UserRepository' that could not be found., when UserRepository definitely is defined in the package, or:

Error creating bean with name 'com.mycompany.myApp.ui.views.admin.LoginView': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mycompany.myservices.backend.data.services.UserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} when UserService does 100% exist, or others claiming that:

Parameter 0 of constructor in com.mycompany.myservices.backend.data.AppDB required a bean of type 'org.springframework.data.mongodb.core.MongoTemplate' that could not be found., when I do actually have a MongoTemplate bean defined in the main myApp package. It seems like Spring isn't scanning things in the correct order, and I'm not sure how to fix it.

Here's my Application.java:

@SpringBootApplication(
        exclude = {ErrorMvcAutoConfiguration.class, SecurityAutoConfiguration.class,
                MongoAutoConfiguration.class, MongoDataAutoConfiguration.class},
        scanBasePackages = {"com.mycompany.myservices.backend"})
@EnableMongoRepositories(basePackageClasses = { PrimaryMongoConfig.class, SecondaryMongoConfig.class })
@EntityScan(basePackageClasses = { User.class })

public class  Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }
}

To reiterate, this setup works perfectly fine in applications that contain their own copies of the services. It just isn't scanning correctly when they're in the JAR dependency, and I'm not sure why, since it should be scanned via the scanBasePackages. Ideas?

allenfromspace
  • 120
  • 1
  • 13
  • So your `UserRepository` is properly annotated with `@Component` or `@Repository` or some such? It should work. You can turn up spring logging to see what beans it's finding. Also, be sure you've got all your duplicates out from when you removed the copy pasta classes. – Taylor Jun 03 '21 at 16:12
  • Yes, it is. When I list the beans using the method from this post: https://stackoverflow.com/questions/33348937/print-all-the-spring-beans-that-are-loaded-spring-boot - it shows all of my repositories, but none of my services, which are annotated with @Service – allenfromspace Jun 03 '21 at 17:10
  • Make sure it's the right `@Service`, you may have mixed spring version dependencies. – Taylor Jun 03 '21 at 17:25
  • They seem to be fine. BTW, I tried adding `@ComponentScan("com.mycompany.myservices")`, and it instead started failing on the MongoTemplate error I mentioned in my original post, seemingly because it tries to autowire a Bean depending on it before it's created (just my theory). Any idea why that would happen? I thought Spring handled scan order by itself. – allenfromspace Jun 03 '21 at 17:44
  • So if you're component scanning in `some.package.path` and stuff is in `some.package` it won't get picked up. So moving your component scan to a higher level package makes me think your services aren't in the package you're scanning. Spring works if configured properly, so you're missing something in your config. I'd suggest you may want to go back to basics and start layering things on. Start with the template and go from there. – Taylor Jun 04 '21 at 15:42

1 Answers1

0

try add annotation @EnableJpaRepositories to you Application class:

@EnableJpaRepositories(basePackages =
    "your.package.of.repository"
)
Li Ying
  • 2,261
  • 27
  • 17