Pass gradle command line arguments to application.properties - java

I have a Spring Boot Gradle application and many MySQL servers and databases.
In different scenarios, I want to start the application with different databases or create them if they do not exist. I want to use this mechanism with command line arguments.
The URL for database is stored in application.properties file of Spring:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb1?createDatabaseIfNotExist=true&useSSL=true
I want to run gradle with command line arguments that will apply to the application.properties file so in my head will be something like this.
application.properties :
spring.datasource.url=jdbc:mysql://${linkNewDB}?createDatabaseIfNotExist=true&useSSL=true
And to run the program as :
gradle bootRun -Pargs=--linkNewDB="someNewDB:3309"
Does anybody know how can I achieve this mechanism? I tried different options but none of them worked. Thanks!

How about changing the whole URL, like this:
gradle bootRun --args='--spring.datasource.url=jdbc:mysql://someNewDB:3309?createDatabaseIfNotExist=true&useSSL=true'
reference: https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/htmlsingle/#running-your-application.passing-arguments

Related

PropertiesLauncher command line arguments not working with Spring Boot executable Jar

So I have basic multi-module Spring Boot project. The goal, that I had was to build executable jar and pass additional properties with the help of -Dloader.path=....
For some reason (if I understand purpose of this argument) loader.path is being ignored completely.
My project structure is following:
\-
|--conf
|---default
|--pets-api
|--pets-app (this module contains the Main-Class)
|--pets-domain
|--pets-infrastructure
Since no custom active profile is being passed it uses "default". Jar contains application-default.propeties file, that has single configuration server.servlet.context-path=/v1.
/conf/default location has 2 properties files:
application.properties
random.properties - this is bind to #ConfigurationProperties(prefix = "...") inside application
When I run it normally everything is fine java -jar pets-app-0.0.1-SNAPSHOT.jar. It just uses application-default.properties file and that is it.
Now when I am trying to utilize -Dloader.path argument as in java -Dloader.path=PATH/TO/conf/default -jar pets-app-0.0.1-SNAPSHOT.jar it starts application same as before, as if I am not adding 2 more file to classpath.
What is used:
Java 17
Spring Boot 2.6.12
Gradle
Did anyone come across this as well? Any suggestion on how to resolve it?
PS. If there is need to see the code, I can upload it to GitHub.

Spring boot external properties file

I'm trying to run a java8 app using spring boot version 2.2.4. The app is then packed in a docker image.
The way I run my app as specified in a Dockerfile which ends liek this:
FROM openjdk:8
.....
CMD /usr/local/openjdk-8/bin/java -jar -Dspring.config.location=/opt/$APP/ /opt/$APP/$APP.jar
The problem I encounter is the loading of external properties files.
For example I have application.properties file similar to this, which is packaed inside the JAR:
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=db1
application.queue.sqs.queue_name=somesqs
In addition, I also inject the docker image an addition application.properties file located at /opt/myapp/. This external file is similar to this:
spring.data.mongodb.uri=mongodb://username:password#MONGO_URL:27017/db_name
application.queue.sqs.queue_name=another_sqs
Expected Behavior: the app will load both new another_sqs location, and external mongo connection.
However, Actual Behavior: when reading the logs I can see that t the new sqs url (i.e. another_sqs) is loaded properly, although the new value for mongo connection is discarded and is therefore using the local embedded mongo engine.
I consulted the following post on stackoverflow to try and understand what I am experiencing:
Spring Boot and multiple external configuration files
But for my understanding, when using spring 2.X and above, the -Dspring.config.location should override all other properties file.
Here is where I started debugging:
TRY 1 : I attached into the docker container, cd into /opt/$APP/ where both my app.jar and application.properties are located, executed the following command java -jar app.jar and viola - it works! A connection to the external mongo source is established. This may be explained by the priority of spring loading properties files as specified in spring's docs.
TRY 2 : Attach the container, cd into $HOME/, execute java -jar /opt/$APP/app.jar -Dspring.config.location=/opt/$APP/ - Do not connect to external mongo, however does connects to the another_sqs. Strange thing - only part of the application.properties values are loaded? Isn't it the way spring 1.X works by adding value from multiple files?
TRY 3 : Attach the container, cd into $HOME/, execute java -jar /opt/$APP/app.jar -Dspring.config.location=file:/opt/$APP/applicartion.properties - same behavior.
Try 4: Edited Dockerfile to include the following execution:
CMD usr/local/openjdk-8/bin/java -jar -Dspring.config.location=classpath:/application.properties,file:/opt/$APP/application.properties /opt/$APP/$APP-$VER.jar
And it works again. Both another_sqs and external mongo are loaded properly on "Try 4".
My question is therefore:
Why should I explicitly specify the classpath:/application.proeprties? Isn't -Dspring.config.location=/opt/$APP/ or -Dspring.config.location=file:/opt/$APP/application.properties should be enough?
When you specify -Dspring.config.location=file:/opt/$APP/application.properties you're overriding the default value of config.location with your application.properties. If you want to use another application.properties, but still using the default properties without declaring them you should use
-Dspring.config.additional-location=file:/opt/$APP/application.properties
In this way, config.location will still have the default value and you will load the external properties as an additional-location.
From the Spring Documentation:
You can also refer to an explicit location by using the spring.config.location environment property (which is a comma-separated list of directory locations or file paths).
When custom config locations are configured by using spring.config.location, they replace the default locations
Alternatively, when custom config locations are configured by using spring.config.additional-location, they are used in addition to the default locations.

Can I pass an internal Spring Boot variable to gradlew?

I have a question. In my app, I do have several configurations:
application-prod.properties
application-test.properties
application-dev.properties
and the main file:
application.properties
Containing one line:
spring.profiles.active=test
To build and run the app I am using ./gradlew buildNeeded
Can I somehow pass the properties suffix: test, prod, dev so it is used in the build process, so I can make different bash scripts to run the installation process on test and prod servers?
I am looking for something like ./gradlew buildNeeded --spring.profiles.active=test or anything that will work...
You can achieve that using spring-gradle-plugin.
From plugin documentation Passing arguments to your application
Like all JavaExec tasks, arguments can be passed into bootRun from the
command line using --args='' when using Gradle 4.9 or
later. For example, to run your application with a profile named dev
active the following command can be used:
./gradlew bootRun --args='--spring.profiles.active=dev'
You can use project properties:
task buildNeeded {
doLast {
def springProfile = project.properties.getOrDefault('spring.profiles.active', 'test')
println springProfile
}
}
Then you can run the project with
./gradlew buildNeeded -Pspring.profiles.active=test

Spring boot application.yml configuration bugging out

Ok, so, I've noticed a strange bug with spring boot's application.yml configuration.
I have a normal application.yml and take my values as
#Value("${path.to.value}")
private type myVal
This works fine in devel mode when I have my config inside my src/main/res dir however when I upload the jar to a server and run it like this:
java -Xms2024m -Xmx6564m -Dlog4j.configuration=/path/to/log4j2.xml -Dspring.profiles.active=dev -Dspring.config.location=/path/to/application.yml -jar myApp.jar
The configuration isn't read by Spring,
even worse, the parameters that I set in my previous config seem to be hard-coded at compilation O.o. So the application doesn't fail, rather, it runs with the parameter from the application.yml that was in the same directory as it during compilation, which seems like a very very dangerous bug if application.yml is indeed intended as a configuration file and I'm not misinterpreting the whole thing.
How am I supposed to specific the path to an application.yml ? How comes config values get hard-coded at compile time in my code ? Is there a way to stop this ?
Try using file://path/to/application.yml.

spring boot log4j file external to jar?

how to pass? The only way I can get this to work is to put log4j.xml on the classpath.
passing: -Dlog4j.configuration=file:///c:\log4j2.xml on the command line doesn't work (although it does in a non spring-boot test application just fine).
I also tried putting this as an environment variable/property in spring.
Try to put this line into your application.properties:
logging.config=file:log4j.xml
Second option is to pass system variable to -Dlogging.config=file:log4j.xml
In this case it is expected to be located in current directory outside of the JAR file.
you must put the "-Dlog4j" before the "-jar XXXX.jar".i try it my own .work for me.
If you are using gradle, and trying to run a test method you will have to add following to the build.gradle. This enables the test method to pick -Dlog4j.configurationFile= to be picked during the test run :
test {
systemProperty "log4j.configurationFile", System.getProperty("log4j.configurationFile")
}

Categories