configure dataSource for liquibase in spring boot - 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.

Related

Problems Configuring Spring boot multi-module Project

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

Disabling Spring Security leads to Failed to load application context

I am disabling Spring Security for the test profile as below:
spring:
config:
activate:
on-profile: test
autoconfigure:
exclude[0]: org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration
exclude[1]: org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration
Error:
Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientConfigurations$ReactiveOAuth2ClientConfiguration$SecurityWebFilterChainConfiguration.class]: Unsatisfied dependency expressed through method 'springSecurityFilterChain' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.config.web.server.ServerHttpSecurity' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
A small clarification that you are not disabling Spring Security, you are disabling the Spring Boot auto-configuration of Spring Security. You can read more about that in the Spring Boot reference documentation.
In your configuration you are disabling the ReactiveSecurityAutoConfiguration, but the ReactiveOAuth2ClientAutoConfiguration is still enabled, presumably because you have a dependency such as spring-boot-starter-oauth2-client.
As described in the error message, the ReactiveOAuth2ClientAutoConfiguration is attempting to create a SecurityWebFilterChain bean, but cannot inject the required ServerHttpSecurity bean, because the ReactiveSecurityAutoConfiguration is disabled.
To fix the error message, you can disable the OAuth 2.0 client auto-configuration as well.
spring:
autoconfigure:
exclude[0]: org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration
exclude[1]: org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration
exclude[2]: org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration
I am using the okta-spring-boot-starter and this worked for me:
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration
- org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
- org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration

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

spring boot to Tomcat deployment data source issue

I am building an application with Spring Boot, Neo4j and MongoDB. I have used #Configuration annotation to load database properties from application.properties like this:
#Bean(name = "neoDriver")
#Profile("local")
public Driver getNeoDriver() {
return GraphDatabase.driver(
env.getProperty("datasource.neo4j.uri"),
AuthTokens.basic(env.getProperty("datasource.neo4j.username"), env.getProperty("datasource.neo4j.password")),
Config.build().toConfig());
}
The autowire code is
#Autowired
#Qualifier("neoDriver")
private Driver neoDriver;
when I run the application from IntelliJ, it runs fine; but when I try deploy the war file on Tomcat 8.5, it gives error.
Field neoDriver in com......repository.PositionRepositoryImpl required a bean of type 'org.neo4j.driver.v1.Driver' that could not be found.
Caused by:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'Controller': Unsatisfied dependency expressed through field 'positionService'; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'Service': Unsatisfied dependency expressed through field 'positionRepository'; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'RepositoryImpl': Unsatisfied dependency expressed through field 'neoDriver'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.neo4j.driver.v1.Driver' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=neoDriver)}
Please let me know what did I do wrong when deploying this on Tomcat.
I bet you're not setting spring.profiles.active to local in your Tomcat deployment. Because your bean is marked with the #Profile annotation, so it will only be created if that profile is active.

Boot, OAuth2, Zuul Proxy and Versions

So, i've added in Zuul and to get the proxy working realised i needs to add in 'spring-cloud-security' which i did:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
<version>1.1.0.M2</version>
</dependency>
The trouble is that as soon as i do this i get this exception
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'loadBalancedOauth2RestTemplate' defined in class path resource [org/springframework/cloud/security/oauth2/client/ OAuth2LoadBalancerClientAutoConfiguration$LoadBalancedOauth2RestTemplateConfig.class]: Unsatisfied dependency expressed through constructor argument with index 2 of typ[org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails]: : No qualifying bean of type [org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
if i do make a bean i get this exception (i'm specifying the resource server info outside of props/yml):
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.security.oauth2.client.OAuth2RestTemplate] is defined: expected single matching bean but found 2: userInfoRestTemplate,loadBalancedOauth2RestTemplate
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1126) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
I've been through this previous post:
https://github.com/spring-cloud/spring-cloud-security/issues/73
I'm using Spring Boot 1.3.3.RELEASE. I've tried (form the above posting) adding in to dep management:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.M3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
but to no avail.
I expect this is a 'versions' issue; what is the most recent set of libs & versions to use? I've been through the 'oauth2-vanilla-ui' sample in the AngularJS/Security tutorial. Is it because i'm not using props in the resource file?
Ok, so i managed to figure it out. So i upped the version of 'spring-cloud-security' to '1.1.0.M4' as I noticed some of the autoconf had changed. Also, i left my 'OAuth2ProtectedResourceDetails' as a bean and added an 'OAuth2RestTemplate' bean but, crucially, marked it as primary:
#Primary
#Bean(name = "platformClientRestTemplate")
public OAuth2RestTemplate clientRestTemplate() {
return new OAuth2RestTemplate(platformOAuth2ProtectedResourceDetails(), oauth2ClientContext);
}
this means the problem of multiple RestTemplates goes away (and ensures the rest template i want gets used).
This means i'm using (for anyone with version issues):
Boot 1.3.3.RELEASE
spring-cloud-security 1.1.0.M4
spring-cloud-starter-zuul 1.1.0.M3

Resources