Define particular repository classes with EnableJpaRepositories - spring

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

Related

#EnableJpaRepositories/#EntityScan annotations mandatory in spring data jpa configuration setup?

I was going through this tutorial where the instructor was configuring Spring Data JPA. He had created the Entity classes and Repository interfaces and then added the #EnableJpaRepositories and #EntityScan annotations on the main application as follows:
#SpringBootApplication
#ComponentScan({"com.test.controller", "com.test.services"})
#EnableJpaRepositories("com.test.repository")
#EntityScan("com.test.entity")
public class MainApplication{
public static void main(String args[]){
SpringApplication.run(MainApplication.class, args[]);
}
}
I was creating the same project on the side, which had the same Entity classes and Repository interfaces but my main application didn't have these annotations. Instead, I added only #SpringBootApplication. Despite the absence of the said annotations, I found the code to be working well and fetching data from the db without issues. So my question is, what is the advantage of adding these annotations to the code ? Is it just for specifying the package where you can find the corresponding files, or are there any other advantages ?
By default, Spring searches for entities and repos in package where you placed your main class (and below this package). For example having these packages:
java
-com
---pack1
-----AnyEntity.java
---pack2
-----Main.java
Spring won't be able to find AnyEntity automatically. In this situation you need to specify where the entity is using #EntityScan. When it comes to repositories, you deal with it similarly using #EnableJpaRepositories.

SpringBoot: #EnableJpaRepositories, basePackageClasses ... repositories not found?

I have a simple Spring Boot project, that depends on a Library where some entities and repositories (JpaRepository) are defined. Additionally, I defined some repositories inside the project. All the repositories should be used inside one service.
In the Application.class I use:
#SpringBootApplication
#EntityScan(basePackageClasses = DatabaseConnectorsCoreMarker.class)
#EnableJpaRepositories(basePackageClasses =
{ThisApplication.class, DatabaseConnectorsCoreMarker.class})
In other projects we used the same but with only one basePackageClasses. That worked out. However, in the present case we always get errors like:
Field field_associated_to_repository in service_name required a bean of type repository_class that could not be found.
Where repository_class are repository interfaces defined in ThisApplication.

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

Grails dependency injection with package private classes

Using Grails (3.x) I would like to make implementations unavailable for users of a certain plugin. Functionality provided with the plugin is made avaible with depenency injection/inversion of control.
I therefore define a public interface and a package private implementation of this interface.
Secondly I would like to register the bean through resources.groovy however this needs importing the class to use - and it's package private.
In Spring i would annotate the class itself with "#Service" making it available through dependency injection (and thus references to package private classes is avoided).
How would one overcome this in Grails (3)?
Apparently it is possible to use spring annotations: Spring - The foundation for grails

#EnableJpaRepositories looking for which package?

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").

Resources