#EnableJpaRepositories looking for which package? - spring

I am learning how to build JSF and Spring integrated webapp. I am using java config to configure. The problem is #EnableJpaRepositories, which package should I put in this annotation? the package contains entity classes? or configuration class? or? and can I just put my root package into it and let it search by itself?

EnableJpaRepositories - use only for repositories and not for entity or config. Main goal for this annotation is to find all repositories.
you can configure jpa repositories in couple ways (dependent on package structure in your peoject),
#EnableJpaRepositories -- in this case spring parse all packages to find repositories.
#EnableJpaRepositories(basePackages="root package") -- same as
#EnableJpaRepositories
#EnableJpaRepositories(basePackages="path.to.repositories.package") -- in this case spring parse only 'path.to.repositories.package' package and sub packages to find repositories.
If you have package structure like com.some.path.repositories or com.some.path.dao you can #EnableJpaRepositories(basePackages="com.some.path.dao or repositories")
If you have more complex structure like com.some.path.domain1.repositories , com.some.path.domain2.repositories .... com.some.path.domainN.repositories
you can use configuration #EnableJpaRepositories(basePackages="com.some.path") or use multi-group configuration values configuretion (next section) , as you have different separate packages you need to find top package for all sub-packages and use it as basePackages. To find top common basePackages for all repositories in many cases might be the same as just use default/root package #EnableJpaRepositories
Or wit multi-group configuration values #EnableJpaRepositories ({ "com.some.path.domain1.repositories", "com.some.path.domain2.repositories"}) if you have couple packages . In this don't need use common root package but if you have 10- 20 -30 separate packages probably better use common package.
PS : #EnableJpaRepositories has alias for the basePackages() attribute. Allows for more concise annotation declarations e.g.: #EnableJpaRepositories("org.my.pkg") instead of #EnableJpaRepositories(basePackages="org.my.pkg").

Related

Spring JPA multi module project

I am trying to create a Spring multi module project.
Module 1, handles the application startup and basic web MVC services.
Module 2, is for MultiTentanted Jpa
Module 2, runs fines fine as stand alone application, but when I include it as a dependency in module 1, I get the following error, Caused by: org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class uk.rteksoft.tenantservices.tenant.model.Role!
I am assuming that I am missing something in a configuration bean somewhere, but haven't been able to find out what I need to do to make this work.
I have a parent pom that contains both module 1 and module 2.
Please say if I need to post any configs or other files.
Thanks
John
You need to scan base package from injected module else spring will not create any bean for injected module and you will face dependency errors.
Use scanBasePackages value in SpringBootApplication annotation in main application (you can scan array of packages based on your requirement)
ex:
#SpringBootApplication(scanBasePackages = "com.example.multimodule")
Here is example link of sample app based on multiple
ComponentScan is another way to scan multimodule packages;
#ComponentScan(value = "com.example.multimodule")
also Use below annotations for scan your entities and repositories
#EntityScan("your entity base packages")
#EnableJpaRepositories("your repositories base packages")

Autowire a Bean from dependent library jar

I have a Spring Boot application (main-app) which users Library jar client-app.jar and mentioned as a dependency in of the application main-app.
Now I want to use #Autowire to inject bean from client-app. For this i have to add #ComponentScan on my main-app application.
But is there a way that i don't have to anything on my main-app by changing code on client-app.
Yes, you can create a sub-package by following the main-app let's say main-app has the following root of package com.example.main-app then on your client-app you should create something like com.example.main-app.client-app then the main application will scan its base package and will look the client-app as well.

Wiring a bean from dependency module

I have created a configuration project which essentially creates couple of beans with configuration stereotype. Then, I want this project to be reused across by my clients.
I have added this config project as a maven dependency, but my client project is not having those beans i have created as part of configuration project.
Could someone help
Ok, the answer is the following: you should place
#ComponentScan("you.configurations.base.package")
on one of your configuration (in the current application, one that #SpringBootApplication sees) or on the class with #SpringBootApplication annotation.
The explanation is as follows: #SpringBootApplication under the hood contains #ComponentScan without specifying a base package. That means that it says to Spring to scan the package where the class annotated with #SpringBootApplication resides and all the packages recursively. And that's it. If you place you #Configuration somewhere there - it will create it during startup, otherwise not.
We can resolve this by enabling spring-boot autoconfiguration
Create classpath->resources->META-INF->spring.factories file
org.springframework.boot.autoconfigure.EnableAutoConfiguration=[add your class with you need to be loaded during application load time]

Import by name in Spring Java configs

Say I have 3 Spring/Maven projects:
api-spec: Contains interface MyService.
api-impl: Contains class MyServiceImpl which implements MyService. Also contains class MyServiceConfiguration which is a Spring #Configuration, that defines a bean of type MyServiceImpl.
main: Contains a Spring application setup with Spring JavaConfig (e.g. a #SpringBootApplication). It has a bean with an #Autowired MyService myService field, which works as its configuration class is annotated with #Import(MyServiceConfiguration.class).
I would like the main-project to have api-spec as a Maven compile dependency and to have api-impl as a runtime dependency (to prevent us from making "hard" dependencies from the main project to the api-impl project by mistake). This is not possible, because #Import takes an array of Classes - e.g.: #Import(MyServiceConfiguration.class). I would like something like #Import("my.package.MyServiceConfiguration") instead.
Using class path scanning is not an option (we have seen too many beans getting picked up by accident), and I would prefer not having to use XML files. We could use SpringApplicationBuilder.source(..) as it accepts a class name as a String - but I can't find a way to use that in my tests...
Compile time check is one of the advantages of java config, so I don't think that it's possible to do such thinks with Java. As for me you should use XML to handle this. It doesn't mean that you should do all your configuration in XML, most of the beans of your api-impl module can be in Java and just imported to XML where will be only beans that you are going to change in runtime.
If you don't want to use XML maybe you should consider to use Groovy config instead:
https://spring.io/blog/2014/03/03/groovy-bean-configuration-in-spring-framework-4

Define particular repository classes with EnableJpaRepositories

I've been using #EnableJpaRepositories and I'm interested in opportunity of defining particular classes rather than packages. The reason behind this is the fact that I'm using multi-module project and at the moment have a core module which contains all repository definitions in a separate package:
core/repository/ - Here all repository definitions are stored
In other modules, which have dependency on core module, I use the following definition for fetching repositories:
#EnableJpaRepositories(basePackages ="core.repository")
Apparently using this means fetching definitions for all the repositories which are under core/repository package. However, in some of the packages I need only some of the repositories, not all of them. For now I've moved every single repository definition to a separate package like:
core/repository/user
However I'm interested - is it really possible to define concrete repository classes, but not packages, something like that:
#EnableJpaRepositories(baseClasses ="core.repository.UserRepository")
You can customize loaded repositories by using includeFilters / excludeFilters param.
For example, you can define filters in your EnableJpaRepositories configuration:
#EnableJpaRepositories(basePackages = "core.repository", includeFilters = #ComponentScan.Filter(MyModuleJpaRepo.Class))
and then mark every module repository with appropriate annotation:
#MyModuleJpaRepo
public interface TestRepository extends JpaRepository<Test, Long> { … }
Here you can find example from spring-data author:
https://stackoverflow.com/a/22744045/1545775

Resources