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

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.

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 FeignClient across maven Project

I have Projects built with Spring-boot, Maven and Kotlin.
I want to expose some Services and FeignClients in a maven Project, so others can use them.
For a class with Annotations like #Service that works well. But I need to expose also FeignClients, which are annotated with #FeignClient, but as it looks other Projects are not
able to inject those Clients. Do I have to configure something in my pom.xml?
Im using spring-cloud-starter-openfeign
Here is some Code.
My FeignClient looks like:
...
#FeignClient(name = "MyAPIClient", url = "\${url}", configuration = [MyApiClientConfiguration::class])
interface MyAPIClient {
...
And I try to inject that Client in another Project like this:
...
#Service
class MyService(val myAPIClient: MyAPIClient) {
...
The Error is pretty clear. It says, there is no bean with the name MyAPIClient. So it's not
visible or available. "Consider defining a bean of type 'com.mycomp.MyAPIClient' in your configuration."
Do I have to configure something explicitly to expose an OpenFeignClient to other projects in my pom.xml?
Thanks for your help
It would work automatically if you had the same package structure in both projects. See how the search for feign clients is performed by default.
In other cases, you need to specify basePackages of basePackageClasses attributes of #EnableFeignClients annotation (in the app where you need to inject your feign client). Note that if you do that, then the default behavior (scanning the current package where this annotation is placed) stops working, so you need to specify it manually too in this case.

Unit test in multi-module spring boot project

I have multi-module project with similar structure as below:
server (which includes Application Context Configuration) and other configurations
shared (Utility classes used by other modules)
service (module with various repository and services)
transaction (module which handles transaction)
I need to write test for the project but I cannot change the project structure. I created a test in my transaction module.
First I got
Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test
I solved it by Creating a #Configuration file in the test folder like so
#Configuration
#ComponentScan("com.mohen")
public class TestConfig {
}
And then I used it in the #SpringBootTest(TestConfig.class) .I was able to autowire, the IDE did not show any sign of error. But when I run my tests I get NoSuchBeanDefinitionException from a different class that is trying to autowire a dependency from the service module.
How to solve these issues?
The main configuration file of the application looks like
#SpringBootApplication(scanBasePackages = "com.mohen")
#EnableScheduling
#EnableAsync
#Import(value = {SSIpFilter.class, MainConfig.class})
public class Application extends SpringBootServletInitializer {...}
The MainConfig.class contains componentScan and Import annotation.
If I try to Import the MainConfig.class in my test I get a suggestion to add a dependency to the server module, which I would not want to do.
Also the entire application uses a single property file (yml). Where should I keep my property file for the test?
EDIT
I managed to run the tests, a dataJpaTest and an integration test, but it loads the entire application context.
Now the problem is, the tests that pass normally , fail when I build my project ./gradlew clean build
I get
java.lang.NoClassDefFoundError
in some classes and
Caused by: javassist.NotFoundException
in other.
I have tried adding the javaassist library but it doesn't work.
Any idea?
I found the solution to my question. Due to the project being multi module, the classes and the packages were not being recognized by other modules.
I made a few changes in my build.gradle files of the modules.
testRuntime project(':shared')
I added the above in the dependencies and also added
jar {
enabled = true
}
bootRepackage{
enabled = false
}
The jar creates a simple non executable jar file while the bootRepackage disables the creation of an executable jar which by default is its nature.

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

How to Autowire repository interface from a different package using Spring Boot?

I am new to Spring Boot and want to autowire a repository from a different package in a Rest Controller. It seems that when I place the interface and implementation in a different package the actual controller the autowire seems to fail.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.acme.repository.RawDataRepository] found for dependency:..
Controller:
package com.acme.controller;
import com.acme.repository.RawDataRepository;
// imports removed!
#RestController
#EnableAutoConfiguration
#ComponentScan("com.acme")
public class DataCollectionController {
#Autowired
private RawDataRepository repository;
// code removed!
}
I have tried to use the #ComponentScan annotation but this gives no solution.
Any idea what i am missing? Whenever i put the interface into the package in which the controller resides then all goes well.
If you have Spring Data #Repositories in a different package you have to explicitly #EnableJpaRepositories (or replace "Jpa" with your own flavour). Boot takes it's defaults from the package containing the #EnableAutoConfiguration so it might work to just move that class as well.
You have to use following two annotations
#EnableJpaRepositories(basePackages = "package-name")
#EntityScan(basePackages = "package-name")
EnableJpaRepositories will enable repository if main class is in some different package.
You need to use EntityScan as well to point to package where you have your entity beans or else it will fail with 'Bean is not of managed type' error.
Spring Boot Provides annotations for enabling Repositories.
So whenever someone uses any Repository (it can be JPARepository , CassandraReposotory) it should be enabled in Application Class itself.
Example:
#EnableCassandraRepositories("package name")
#EnableJpaRepositories("package name")
After providing the above annotations, the container takes care of injecting beans for repositories as well.

Resources