"java.lang.IllegalStateException: Cannot load driver class" in Spring Boot application - spring

I am using to configure spring boot with an external YAML configuration and CMD.
-> application.yml file
spring:
profiles: integration-test
datasource:
driverClassName: ${SPRING_DATASOURCE_DRIVER_CLASS_NAME}
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
-> cmd
mvn clean install
-> Result
Caused by: java.lang.IllegalStateException: Cannot load driver class: ${SPRING_DATASOURCE_DRIVER_CLASS_NAME}
Can anyone explain this to me?

When you use the syntax ${}, you are actually telling Spring Boot to use the value of the property whose name is between brackets. In your case, Spring Boot tries to resolve the property SPRING_DATASOURCE_DRIVER_CLASS_NAME. When it fails, it uses the string as is, which leads to the error you mentioned, since no driver exists under the name ${SPRING_DATASOURCE_DRIVER_CLASS_NAME}.
To solve the issue, you can either :
replace the ${} by the real values, e.g. driverClassName: org.postgresql.Driver and do the same for the other properties (url, username and password)
provide properties SPRING_DATASOURCE_DRIVER_CLASS_NAME,SPRING_DATASOURCE_URL and the two others. These can passed in the command line with -D options (e.g. -DSPRING_DATASOURCE_DRIVER_CLASS_NAME=org.postgresql.Driver) or through environment variables. You can look at spring Boot documentation for more details.

Pass those variables in your launch configuration of your program or at commandline when you run your app with java YourMainClass, e.g.
java -DSPRING_DATASOURCE_DRIVER_CLASS_NAME=<full_qualified_name_of_your_jdbc_driver_class> -DSPRING_DATASOURCE_URL=<jdbc_url> YourMainClass
also pass the other two variables the same way, username & password!
your can even set those enviroment variables on OS level, so you don't have to set them each time you start your application...
if your using Spring Boot also have a look at this one: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

Related

getting Could not resolve placeholder while reading yml values in spring boot

I'm using spring boot and using this value in my application.yml
config:
username: abc
password: xyz
In my class, I'm utilizing it this way -
#Value("${config.username}")
private String username;
I'm getting the following error -
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'config.username' in value "${config.username}"
However if I use this in my application.yml file, it works. Can you please tell me what I'm doing wrong here?
config.username: abc
config.password: xyz
check your placeholder is Tab or Space ? make sure no Tab in your yml file.
was facing the same problem when trying to read from application.yml file instead of application.properties file. maven clean & then maven install resolved the issue for me.

how can spring boot get spring datasource config value from os environment variable?

this is my spring datasource config
spring:
datasource:
driver-class-name: org.mariadb.jdbc.Driver
url: ex.com
username: exId
password: exPw
and we know we can use os environment variable for spring datasource config like this
# export SPRING_DARASOURCE_URL=ex.com
But we can not export SPRING_DARASOURCE_DRIVER-CLASS-NAME because of '-' like this
# export SPRING_DARASOURCE_DRIVER-CLASS-NAME=org.mariadb.jdbc.Driver
So if i wanna get spring.datasource.driver-class-name via os environment variable,
what i have to do?
In most cases, any punctuation like those hyphens can be converted to underscores for the system environment variable, e.g. SPRING_DATASOURCE_DRIVER_CLASS_NAME. In some earlier versions of Spring this wasn't exactly standardized yet and some properties might drop the hyphens entirely, e.g. SPRING_DATASOURCE_DRIVERCLASSNAME.
Another approach: set the system env var, JAVA_TOOL_OPTIONS, with any desired Java/JVM options like:
JAVA_TOOL_OPTIONS=-server -Xmx1g -Dspring.datasource.driver-class-name=com.mysql.jdbc.Driver

Spring spring.profiles.include: doesn't read profile-related properties

There are several ways present to define "active profiles" for a Spring Boot application.
The default one is to pass it through a command line, like this:
java -Dspring.profiles.active=dev,local -jar myapp.jar
it works just fine (as expected): All three sets of profile-related properties will be loaded in proper order:
application.yaml
application-dev.yaml will override the previous one
application-local.yaml will override the previous one as well (these properties will have the most priority)
Based on the idea, that my "local" profile should always "use and overrides" properties from the "dev", let's "hardcode" such behavior.
Let's use the 'spring.profiles.include' feature for this. So, the following lines are added to the 'application-local.yaml':
spring.profiles:
include:
- dev
I expect, now I can pass the "local" profile only in the command line, and the "dev" profile will be applied automatically (with his properties, of course):
java -Dspring.profiles.active=local -jar myapp.jar
But ooop!*: properties from the 'application-dev.yaml' are ignored.
Why? Is it a bug? Is it a feature that forces me to list all profiles in a command line directly?
I'm sure that the behavior around profiles activation should be the same without any difference in how the active-profiles list was passed to Spring Boot framework.
The application:
#SpringBootApplication #EnableConfigurationProperties( MyProps::class )
class SpringApp4
#ConfigurationProperties("my.db") #ConstructorBinding
data class MyProps(val name: String, val url: String, val user: String)
#Component
class MyRunner(val myProps: MyProps, val env: Environment) : CommandLineRunner {
override fun run(vararg args: String) {
println("myProps = $myProps")
println("activeProfiles = ${env.activeProfiles.joinToString()}")
exitProcess(0)
}
}
fun main() { runApplication<SpringApp4>() }
application.yaml:
my.db:
name: "default-name"
url: "default-url"
user: "default-user"
application-dev.yaml:
my.db:
url: "dev-url"
user: "dev-user"
application-local.yaml:
spring.profiles.include:
- dev
my.db:
user: "local-user"
Run1: java -Dspring.profiles.active=dev,local -jar myapp.jar
Correct output:
myProps = MyProps(name=default-name, url=dev-url, user=local-user)
activeProfiles = dev, local
it's correct because the url=dev-url
Run2: java -Dspring.profiles.active=local -jar myapp.jar
Incorrect output:
myProps = MyProps(name=default-name, url=default-url, user=local-user)
activeProfiles = local
It's not correct because the url=default-url and the activeProfiles doesn't contain the "dev" at all.
Help me please to figure out how to use the spring.profiles.include feature in yaml to build a kind of top level profiles that will activate other automatically.
In Run2 You are giving profile as local
i.e
-Dspring.profiles.active=local
So spring will first load application.yml and then application-local.yml
I can see the output is expected.
Since some properties like name and url are not present in application-local.yml, so the values of these fields will be same as present in application.yml
FYI : application.yml is always called irrespective of profile, and then it gets overridden by the profile mentioned in -Dspring.profiles.active property
spring.profiles.include deprecated in Spring Boot 2.4 and no longer works: https://spring.io/blog/2020/08/14/config-file-processing-in-spring-boot-2-4
It caused recursive resource loading; that broke Kubernates ConfigMap so they removed recursion.
Use spring.profiles.active or spring.profiles.group.

Environment VM arg passed to bootRun not being picked up by Spring Boot application

I am trying to set the environment of my Spring Boot (1.5.4.RELEASE) application at runtime, but it appears I have something out of alignment.
My application.yml is defined like this:
spring:
profiles.active: ${env:local}
---
spring:
profiles: local
foo: bar
---
spring:
profiles: dev
foo: bar
In a class that I have annotated as #Configuration, I have a method that does the following just so I can show the environment that is being used:
#Value('${spring.profiles.active}')
String activeProfile
#PostConstruct
def bootComplete() {
println "App started with profile: $activeProfile"
}
Under this configuration, when my application starts, I see this in the console:
App started with profile: local
If I modify ${env:local} to be ${env:dev} in my application.yml and I start the application, I see this in the console:
App started with profile: dev
My goal is to start the application with VM arguments to set the active profile at runtime. I am adding the argument: -Denv=dev but it appears that it has no effect on the starting of the application. Can anyone suggest what I might be overlooking here?
I found the solution to my problem. The issue was that I was starting the application using Gradle bootRun. My assumption was that the VM args set there would be used. I am now running the application by calling the class directly, and the VM args are working (both -Denv and -Dspring.profiles.active)
Doing -Denv=env will not make any effect since env is not a property key.
This is how you can do it:
-Dspring.profiles.active=dev

Unable to detect database type

I'm trying to create a Spring Boot application using sqljdbc4 driver with this config:
spring:
datasource:
url: "jdbc:sqlserver://dbhost:1433;databaseName=test"
username: dbuser
password: dbuser
tomcat:
test-on-borrow: true
validation-query: select 1
But, when I run, I get this error: Unable to detect database type
I was debugging BatchDatabaseInitializer, where error came from, and when it calls JdbcUtils.commonDatabaseName(...), "Microsoft SQL Server" is returned as product name that doesn't match with any DatabaseDriver's product name.
I tried other drivers but they all have the same problem.
Is it a bug?
I'm using Spring Boot 1.5.1-RELEASE.
You need to properly configure your spring.datasource config in application.properties file if you're using spring-batch to create batch jobs. Below is mine ->
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/batch_repo
spring.datasource.username=batch_username
spring.datasource.password=batch_password
spring.datasource.platform=mysql
spring.batch.initialize-schema=always
spring.batch.initialize-schema when configured to "always", will create the necessary spring batch related tables in your schema.
Alternatively, if you assign it to "never", it will refrain from creating the tables. In both these cases your error should get resolved.
Try spring.batch.jdbc.initialize-schema=never in props file. It worked for me in spring-boot v2.6.x
Add this in your Application file within the main function.
#SpringBootApplication(
exclude = {
BatchAutoConfiguration.class,
JmxAutoConfiguration.class
},
excludeName = {
"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration",
}
)
Put this in your application.properties.
spring.batch.schema=classpath:org/springframework/batch/core/schema-sqlserver.sql
Check your application.properties file like below.
Note: springbatch is my DB name
spring.datasource.url=jdbc:mysql://localhost:3306/springbatch
spring.datasource.username=root
spring.datasource.password=Vishal#123
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.batch.jdbc.initialize-schema=always

Resources