Spring Boots Gradle Plugin is ignoring applicationDefaultJvmArgs in the start scripts - spring-boot

The documentation of the gradle application plugin states that I can use applicationDefaultJvmArgs to configure the JVM startup parameters which are written in the start script. When using the Spring Boot Gradle plugin, I get a new distribution called boot, which also contains start scripts. Unfortunately they seem to ignore applicationDefaultJvmArgs. They contain this line:
# Add default JVM options here. You can also use JAVA_OPTS and POCKETKNIFE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
while my original distrubtion contains this line:
# Add default JVM options here. You can also use JAVA_OPTS and POCKETKNIFE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-XX:+UseSerialGC" "-XX:MaxHeapFreeRatio=10" "-XX:MinHeapFreeRatio=10" "-Xms32M" "-Xmx128M" "-Dfile.encoding=UTF-8"'
How can I set the JVM parameters in the Spring Boot distribution?

I think i figured it out: Add this to the build.gradle file:
bootStartScripts {
defaultJvmOpts = project.applicationDefaultJvmArgs
}
It still looks like a bug to me, especially since the bootRun task uses the applicationDefaultJvmArgs.

Related

How to pass spring.config.location="somepath" while building SpringBoot application with command-line Gradle (6.4) build

I have a SpringBoot application where I have application.properties file outside of project (it's not in usual place src/main/resources).
While building application with gradle clean build, it fails as code is not able to find properties files.
I have tried many command to pass vm args, gradle opts but its not working.
gradle clean build -Djvmargs="-Dspring.config.location=/users/home/dev/application.properties" //not working
It fails on test phase when it creates Spring application context and not able to substitute property placeholders. If I skip test as gradle clean build -x test it works.
Though I can run the app with java -jar api.jar --spring.config.location=file:/users/home/dev/application.properties
Please help how I can pass spring.config.location=/users/home/dev/application.properties in gradle build using command line so that build runs with all Junit tests
If I were you, I would not get involved the actual properties to junit test. So I would create a test properties for the project under src/test/resources/application-test.properties and in junit test I would load the test properties.
Example:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MyProperties.class)
#TestPropertySource("classpath:application-test.properties")
public class MyTestExample{
#Test
public void myTest() throws Exception {
...
}
}
System properties for running Gradle are not automatically passed on to the testing framework. I presume this is to isolate the tests as much as possible so differences in the environment will not lead to differences in the outcome, unless explicitly configured that way.
If you look at the Gradle API for the Test task, you can see that you can configure system properties through through the systemProperty method on the task (Groovy DSL):
test {
systemProperty "spring.config.location", "/path/to/my/configuration/repository/application.properties"
}
If you also want to read a system property from the Gradle command line and then pass that the test, you have to read it from Gradle first, e.g. as a project property, and then pass that value to the test:
test {
if (project.hasProperty('testconfig')) {
systemProperty 'spring.config.location', project.getProperty('testconfig')
}
}
Run it with gradle -Ptestconfig="/path/to/my/configuration/repository/application.properties" build
However, I would discourage using system properties on the build command line if you can avoid it. At the very least, it will annoy you greatly in the long run. If the configuration file can be in different locations on different machines (depending on where you have checkout out the repository and if it is not in the same relative path to your Spring Boot repository), you may want to specify it in a personal gradle.properties file instead.
I think there is a misunderstanding.
spring.config.location is used at runtime
As you validated:
java -jar api.jar --spring.config.location=file:/users/home/dev/application.properties
spring.config.location is used or required at runtime, not at build time.
When your spring boot app is building, an application.properties is required. An approach could be use an src/main/resources/application.properties with template values, but at runtime you will ignore it spring.config.location=file...
For unit tests
In this case as #nikos-bob said, you must use another properties, commonly inside of your src/test/resources
Environment variables instead external properties
We don't want to have hardcoded values in our main git repository src/main/resources/application.properties so the first idea is use an external properties. But this file must be stored in another git repository (equal to main repository ) or manually created.
Spring and other frameworks give us an alternative: Use environment variables.
So instead of manually external creation of application.properties or store it in our git repository, your spring boot app always must have an application.properties but with environment variables:
spring.datasource.url=jdbc:oracle:thin:#${DATABASE_HOST}:${DATABASE_PORT}:${DATABASE_SID}
spring.datasource.username=${DATABASE_USER}
spring.datasource.password=${DATABASE_PASSWORD}
spring.mail.host = ${MAIL_HOST}
spring.mail.username =${MAIL_USERNAME}
spring.mail.password =${MAIL_PASSWORD}
Advantages:
No manually creation of application.properties allowing us a more easy devops automations
No spring.config.location=file.. is required

How do you run micronaut from gradle with local properties

I want to run Micronaut server from Gradle command line with "local" environment variables.
The regular command
.\gradlew.bat run
will use default variables defined in application.yml file.
I want to override some of them with values for my local environment and therefore need to specify system property micronaut.environments=local to use overriding values from application-local.yml file.
.\gradlew.bat run -Dmicronaut.environments=local
The command above won't work as Gradle will take only -Dmicronaut for the system property and the rest ".environments=local" will be considered as another task name:
Task '.environments=local' not found in root project 'abc'
What would be the correct way to pass such system property to the java process?
Command below works for unix, probably it should work also for windows:
MICRONAUT_ENVIRONMENTS=local gradle run
or use gradle wrapper
MICRONAUT_ENVIRONMENTS=local .\gradlew.bat run
P.S. also, you can find the same approach for Spring Boot
My approach is to add a gradle task.
task runLocal(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = "dontdrive.Application"
jvmArgs '-Dmicronaut.environments=local'
}
then start with:
./gradlew runLocal

gradle.properties settings not considered

As a starter in gradle I am converting a project from maven to gradle. When running tests I get an OutOfMemoryError: Java heap space. If I add
tasks.withType(Test) {
jvmArgs = ['-Xmx2g']
}
to build.gradle then it works. However, if that is configured only in gradle.properties as org.gradle.jvmargs=-Xmx2g then it doesn't.
Same for the encoding. There is one test which is only running successful if GRADLE_OPTS=-Dfile.encoding=UTF-8 is set. But if I set systemProp.file.encoding=UTF-8 in gradle.properties it doesn't.
Why is that?
The answer is described in the Gradle DSL documentation for the Test task.
Test are always run in (one or more) separate JVMs.
Whatever you configure in gradle.properties environment variable applies to the Gradle JVM process only.
Maximum heap size is configured like you did via jvmArgs or, preferably, via maxHeapSize.
Regarding file encoding & GRADLE_OPTS, I don't have a definite answer. My best guess is that it has just not been implemented this way. You can set the file encoding on a per project basis for compilation tasks like this:
tasks.withType(Compile) {
options.encoding = 'UTF-8'
}
From: Gradle Goodness: Set Java Compiler Encoding

Running bootRun and use a different application.properties file

I'd like to be able to run bootRun for spring boot, but use a different application.properties file besides the one in src/main/resources/. Is that possible? I'd prefer to not overwrite the file in src/main/resources/, as it would dirty the file.
Is this possible?
You can use profile based configuration selection.
Just set a system environment property:
spring.profiles.active=dev
And now provide application-dev.properties in application resources(src/main/resources/)
By this way you can use different properties for different environment.
If you want to provide files at a different location the use this environment property
spring.config.location=<path>
If you wish to use different name then application in property file name the use this environment property:
spring.config.name=<new_name>
For more info check this link:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
Here is what my bootRun task looks like that does this
bootRun {
systemProperty "spring.config.location", "file:$projectDir/spring-config/"
main = springBootAppClass
}
Which specifies to use the spring-config directory in the project's root folder.
If using in conjunction with #PropertySource it looks like this
#PropertySource("${spring.config.location}/persistence.properties")
Try this command,
./gradlew bootRun --args='--spring.profiles.active=dev'
I too was looking for the solution, found it in official documentation
https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#running-your-application
I got it to work like this:
tasks.named("bootRun") {
systemProperty "spring.config.location", "file:$projectDir/myConfigFolder"
mainClass = "my.project.MyMainClass"
}

How to pass system properties to the tests in gradle in the smart way?

build.gradle
tasks.withType(Test){
systemProperties=System.properties
println systemProperties['param']
}
Now I can either pass parameters in the command line:
gradle test -Dparam=10
or put them in gradle.properties:
systemProp.param=15
Ideally I would like to put the defaults in the gradle.properties, and be able to overwrite them from the command line. Unfortunately if I do that, the gradle.properties has precedence, and -Dparam=10 is ignored.
Could you offer any solutions on that?
https://issues.gradle.org/browse/GRADLE-2122
It works since 2.12 or 2.13 "the smart way" already!
The example above is working, the command line -D option overdrives the defaults in gradle.properties
I am using gradle 2.12 and sharing how I used it:
test {
// support passing -Dsystem.property=value to bootRun task
systemProperties = System.properties
}
I have JUnit tests that I wanted to skip unless a property was used to include such tests. Using JUnit Assume for including the tests conditionally:
//first line of test
assumeThat(Boolean.parseBoolean(System.getProperty("deep.test.run","false"),true)
Doing this with gradle required that the system property provided at the time of running gradle build, shown here,
gradle build -Ddeep.test.run=true
was indeed passed through to the tests.
Hope this helps others trying out this approach for running tests conditionally.

Resources