Problems Configuring Spring boot multi-module Project - spring

I am having issues configuring spring boot multi module project!
This is my parent pom
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/>
</parent>
<modules>
<module>main-module</module>
<module>rabbit-mq-AOP</module>
</modules>
<dependencies>
common dependencies..
</dependencies>
In the module rabbit-mq-AOP I have only one configuration class for configuring rabbit MQ reading values from property file, AND I have added AOP for catching requests/responses of APIS.
It has no Repository or entity classes or controllers.
The configuration class looks like:
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
#Configuration
#Order(value = Ordered.LOWEST_PRECEDENCE)
public class RabbitMQConfig { .... }
Note I have added exclude DataSourceAutoConfiguration because, if I don't use this module in rabbit-mq-AOP it gives me Error when starting main-module
Caused by: java.lang.IllegalArgumentException: ExistingValue must be an instance of com.zaxxer.hikari.HikariDataSource
The base package in rabbit-mq-AOP is com.a.producer.
The base package in main-module is com.a.ds.
This is the main class of module main-module from which i am trying to run
#EnableSwagger2
#SpringBootApplication(scanBasePackages = "com.a")
public class MainApplication extends SpringBootServletInitializer { .... }
With Above configuration, application does not startup and start giving error of No qualifying bean of type on repository classes of this module.
If I change this above main class to #SpringBootApplication(scanBasePackages = "com.a.producer")
the application will start up but no Controllers will be listed in the swagger of main-module, also the Apis will not work in-fact The rest Controllers are not recognized. The swagger-ui is detecting actuator api's which should be hidden as configured in properties file
SWAGGER - UI
Note: With Spring logs as DEBUG Notice this specific line.
Exclusions:
-----------
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
I am relying on DataSource Auto configuration of Spring by just adding the Jpa properties in property file not custom configuration class.
Guide a way around this as I have to use the module rabbit-mq-AOP in multiple projects and it will read the properties from where it is integrated i.e in this case from main-module
Update:
If I add these annotations on main class.
#EnableJpaRepositories("com.a.ds.repository")
#EntityScan("com.a.ds.dto.entity")
#ComponentScan("com.a.ds.config")
Again I get this Error which should not come now.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: ExistingValue must be an instance of com.zaxxer.hikari.HikariDataSource

Solved the Problem in two steps
Added these annonations
#EnableAutoConfiguration
#ComponentScans({ #ComponentScan(basePackages = "com.a.ds.*")})
#Order(value = Ordered.HIGHEST_PRECEDENCE)
on Configuration class in main-module
Created Database Configuration Class with two beans dataSource and entityManagerFactory

Related

Runtime Error in SprinBoot project : unable to find SqlSessionFactory

I have a simple SpringBoot project in IntelliJ that I generated at http://start.spring.io. I added a dependency from the local repository and it was successfully imported. This library depends on the different local library.
I am able to Build my project successfully, however when I am trying to Run it I am getting runtime error. I added new dependency to my project that contains the class which was not found during the startup but it didn't resolve my issue and I am still having problems on the startup.
Here is the original dependency I added to my project :
<dependency>
<groupId>connect_mgr</groupId>
<artifactId>connect-mgr</artifactId>
<version>1</version>
Inside this "connect_mgr" project there is a dependency on the different library :
<dependency>
<groupId>services_core</groupId>
<artifactId>services-core</artifactId>
<version>1</version>
</dependency>
There is also an implementation in the "services_core" project :
#Bean
#DependsOn("sqlSessionFactory")
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
In my Project I also added a dependency to IBatis-Core that contains "SqlSessionFactory" class.
And still, on the startup of my project I am getting this error :
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/config/MyBatisMapperConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is java.io.FileNotFoundException: class path resource [null] cannot be opened because it does not exist
Main class in my projec resides in "services_core" project.

setting up path for a library jar for different environments to make compatible with CI-CD

I've a jar library that needs to be read as an argument to my class MyProject and a respective app property in application.properties my.customJar=/WEB-INF/lib/myJar.jar to use the jar in my local app run and it works well locally but it fail on the pcf cloud. I did some changes & respective to this property, I've tried adding an override in cloud environment application-dev.properties i.e. my.customJar=${project.basedir}/src/main/webapp/WEB-INF/lib/myJar.jar
I've also tried with relative path my.customJar=./src/main/webapp/WEB-INF/lib/myJar.jar but neither of them appear to have worked.
The problem arises specifically when I send this code to the pcf cloud I am getting FileNotFoundException. And it fails there with error mentioned below. Can anyone please guide me with how can I set the path for the other profiles. Also, please let me know if there is any more convenient way to do this as well?
Note: I am using multiple spring profiles.
Error I am getting
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myController' defined in file [/home/abc/app/BOOT-INF/classes/com/example/myController.class]: Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jarUserBean' defined in class path resource [com/example/configuration/CommonConfigs.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.myJar.api.MyProject]: Factory method 'jarUserBean' threw exception; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/lib/myJar.jar]
2021-08-27T07:53:53.647+01:00 [APP/PROC/WEB/0] [OUT]
Here, the jarUserBean is a bean created using the jar's insputStream i.e.
#Value("${my.customJar}")
private String pathToJar;
#Bean
#ConditionalOnProperty(prefix = "my", name = "customJar")
public MyProject jarUserBean() throws IOException, ProjectInvalidException, InterruptedException {
Resource resource = loader.getResource(pathToJar);
InputStream is = resource.getInputStream();
return new MyProject(is);
}
Adding this plugin in the pom helped me reading it from the classpath itself.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>jar</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>

How to use the default keycloak.json instead of spring properties

I was following this example to set up keycloak with springboot
https://www.baeldung.com/spring-boot-keycloak
I have used the bellow bean so I can use spring boot properties file.
which all worked fine.
But if I wanted to use the Keycloak.json file instead of spring boot properties, what I did was commented out the KeycloakSpringBootConfigResolver been and included the keycloak.json file in resources/WEB-INF/keycloak.json. but I keep getting the following error.
am I missing something? how do I use the keycloak.json file and where should this file go? or is there some configuration I missed? all the examples show using spring properties and not json file. Any ideas? or if you could point me to an example that uses the default keycloak.json
Initialization of bean failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.keycloak.adapters.springboot.KeycloakAutoConfiguration': Unsatisfied dependency expressed through method 'setKeycloakSpringBootProperties' parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
#Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
Add this to your configuration file:
keycloak:
configurationFile: "classpath:keycloak.json"
Put the keycloak.json directly into the resources directory.
Use only keycloak adapter as dependency: org.keycloak:keycloak-spring-security-adapter

Omitting Spring Data JPA autowiring during tests

I have a Spring Boot application that uses a library (my own), that has Spring Data JPA dependencies.
Within the library, I'm using JPA repository interfaces and a custom repository fragment that uses a JpaSpecificationExecutor interface.
I have a configuration inside the library to #EnableJpaRepositories, as below:
#EnableJpaRepositories(basePackages = "my.package.domain.jpa.repo", bootstrapMode= BootstrapMode.LAZY)
#EntityScan(basePackageClasses = {LookupConfig.class, LookupMapping.class})
#Configuration
public class LookupJpaConfiguration {}
I have also declared (not generated) the meta-models (with _ appended to the class name) for the entity classes in the same package as the entity classes.
The main application is also a #SpringBootApplication, with spring-boot-starter-parent:2.1.0 as parent. This application uses the library as a dependency, and #Autowire a class from the Library. The application itself does not have direct dependencies on Spring Data.
The problem is, I am unable to run Unit tests without adding properties for the datasource.
This is what the test class's declaration looks like:
#ExtendWith({SpringExtension.class, MockitoExtension.class})
public class OrderStatusProcessorTest {
// Uses the library with JPA dependency
#MockBean private LookupService lookupService;
// The class being tested; uses LookupService
private final OrderStatusProcessor orderStatusProcessor;
public OrderStatusProcessorTest() {
orderStatusProcessor = new OrderStatusProcessor(lookupService);
}
...
I have already tried #Mocking DataSource and EntityManagerFactory, but none of those worked either.
Library's pom file
<properties>
<spring-data-releasetrain.version>Lovelace-SR5</spring-data-releasetrain.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
With the current setup, the error I'm seeing is as below --
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unsatisfied dependency expressed through method 'entityManagerFactory' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactoryBuilder' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unsatisfied dependency expressed through method 'entityManagerFactoryBuilder' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaVendorAdapter' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
It does work if I provide the datasource properties correctly. But what I want is for the Tests to run without actually connecting to the database.
Let me know if I need to provide more information. Thanks in advance!

configure dataSource for liquibase in spring boot

I have a spring boot application and I want to add liquibase configuration change log for it.
I have created a LiquibaseConfig class for configuring liquibase:
#Configuration
public class LiquibaseConfiguration {
#Value("${com.foo.bar.liquibase.changelog}")
private String changelog;
#Autowired
MysqlDataSource dataSource;
#Bean
public SpringLiquibase liquibase() {
SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setDataSource(dataSource);
liquibase.setChangeLog(changelog);
return liquibase;
}
}
and I have configured the datasource information in properties file:
spring.datasource.url=jdbc:mysql://localhost:3306/dms
spring.datasource.username=root
spring.datasource.password=test
spring.datasource.testWhileIdle = true
spring.jpa.show-sql = true
#liquibase
com.foo.bar.liquibase.changelog=classpath:/db/changelog/db.changelog.xml
when I run my application I receive this error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'liquibaseConfiguration': Unsatisfied dependency expressed through field 'dataSource': No qualifying bean of type [com.mysql.jdbc.jdbc2.optional.MysqlDataSource] found for dependency [com.mysql.jdbc.jdbc2.optional.MysqlDataSource]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mysql.jdbc.jdbc2.optional.MysqlDataSource] found for dependency [com.mysql.jdbc.jdbc2.optional.MysqlDataSource]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Now I understood that this means the application cannot autowire the MysqlDataSource dataSource; but I need to pass the data source to liquibase bean. How can I do that?
Here's a simple step to integrate liquibase in spring boot
STEP 1
Add liquibase dependency
Gradle
runtime "org.liquibase:liquibase-core"
Maven
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<scope>runtime</scope>
</dependency>
STEP 2
Add liquibase changelog file path in application.yml
liquibase:
enabled: true #this is optional as enabled by default
change-log: classpath:/liquibase/db-changelog.xml
Notice property liquibase.change-log. I'm referring path as /liquibase/db-changelog.xml. so you should have a file name db-changelog.xml inside src/main/resources/liquibase/
STEP 3
Add your changesets on the file and when Spring-Boot application is started (spring-boot:run) your changeset will be loaded.
This will use default dataSource that your app uses.
More Info: http://docs.spring.io/spring-boot/docs/1.4.3.RELEASE/reference/htmlsingle/#howto-execute-liquibase-database-migrations-on-startup
Update
For Spring Boot 2.0 as #veben pointed out in comment use
spring:
liquibase:
change-log: #path
Rather than autowire the datasource, create a method in your Liquibase Configuration Object to create the datasource.
private DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUsername("user");
dataSource.setPassword("pswd");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/db");
dataSource.setSchema("dbName");
return dataSource;
}
then in your bean generation method
liquibase.setDataSource(dataSource());
This gives you a chance to specify the database parameters on the fly, I still had the changelog location in the applications.properties file along with the enablement of liquibase. I've tried it, and it works for me.
I had a similar construct for my application, have you tried injecting a more generic javax.sql.DataSource instead?
My guess is that Spring uses the non-specific type for this bean, on top of that you shouldn't even use a database-specific type if your application could be configured to use a totally different source, i.e. by just changing the datasource URL in the configuration file.

Resources