Gradle: Fail on adding systemProperty - gradle

I'm trying to add a .dll file to the "java.library.path" system property via gradle on my Spring Boot project. I'm using Gradle 2.1 on STS.
This is the small piece of groove code within my build.gradle:
tasks.withType(JavaCompile) {
systemProperty "java.library.path", file("./src/main/resources/META-INF/opencv-2.4.9/windows_bin/x64")
}
And I'm getting the following error:
Could not find method systemProperty() for arguments [java.library.path, D:\GitHub\TFG_1\GuiaTV\src\main\resources\META-INF\opencv-2.4.9\windows_bin\x64] on root project 'GuiaTV'
That path does exists, so I don't know where the problem is.
Any help? Thank you!
UPDATE 1:
#Amnon Shochot
What I try to do is to add a native library (.dll) to the project. I took the idea from some sites (for example, http://zouxifeng.github.io/2014/07/17/add-system-property-to-spring-boot.html, https://github.com/cjstehno/coffeaelectronica/wiki/Going-Native-with-Gradle).
The first one is using what you suggested:
tasks.withType(JavaExec) {
systemProperty "java.library.path", file("./libs")
}
The second one is using:
run {
systemProperty 'java.library.path', file( 'build/natives/windows' )
}
None of them are working for me.
The first one (with JavaExec) is failing gradle test throwing:
java.lang.UnsatisfiedLinkError: no opencv_java249 in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1865)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
If you follow the trace, it's crashing at runtime in sentence: System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
And the second one is failing on gradle build with the following message:
Could not find method run() for arguments [build_24sfpo0st6dokeq7fn3ad7r34$_run_closure7#2652c3da] on root project 'GuiaTV'.
Luckily you know exactly what I try to achieve and you can solve my problem.
Thank you for your interest!
UPDATE 2:
Finally, I ended up adding these lines to my build.gradle script:
// The following makes "gradle build", "gradle test" work
test {
jvmArgs = ['-Djava.library.path=./src/main/resources/META-INF/opencv-2.4.9/windows_bin/x64']
}
// Thw following makes "gradle run" work
run {
jvmArgs = ['-Djava.library.path=./src/main/resources/META-INF/opencv-2.4.9/windows_bin/x64']
}
By the way, I'm also using "spring-boot" gradle plugin. That's where the run task comes from.
So, I can execute "gradle build", "gradle test" and "gradle run" sucessfully. This is, that native library is correctly added.
However, since I'm also using "eclipse" gradle plugin, I would like to add the native library simply by executing "gradle eclipse". Instead, I must create the library on Eclipse manually, and add it to my project.
Thank you #Amnon for your collaboration. I'll be posting a new solution in the case I found it.

The problem is that you do not set the context for the systemProperty method thus Gradle tries to locate it in the project object where it does not exist which is the reason for the error you got.
If you wanted to apply this configuration for all tasks of type JavaCompile your code should have been looked like:
tasks.withType(JavaCompile) { JavaCompile t ->
t.systemProperty "java.library.path", file("./src/main/resources/META-INF/opencv-2.4.9/windows_bin/x64")
}
However, the JavaCompile task type also does not contain a systemProperty so this code wouldn't work either.
You can define CompileOptions for a JavaCompile task using its options property, i.e.:
tasks.withType(JavaCompile) { JavaCompile t ->
t.options "java.library.path", file("./src/main/resources/META-INF/opencv-2.4.9/windows_bin/x64")
}
However, I'm not sure whether you can define this specific system property.
One last note - the systemProperty method does exist for tasks of type JavaExec in case that this is what you intended to do.

Related

How to avoid copy'n'paste in gradle?

I have a build.gradle file for my spring-boot application. I have a few environment details I wish to change for some of the gradle tasks. Specifically for the gradle tasks 'test', 'runSmokeTest' and 'bootRun'. In all the tasks I have to make the same calls, so I would prefer if I could extract a method out of that. Or a task. But whenever I do that, suddendly gradle no longer finds the functions that I require.
These are the calls I need to make:
systemProperties System.properties
systemProperty "spring.cloud.config.failFast", "false"
if (project.hasProperty("TEAM_ENCRYPT_KEY"))
environment "ENCRYPT_KEY", "$TEAM_ENCRYPT_KEY"
The code works perfectly fine when included directly in the bootRun task, the test task and the runSmokeTest task via copy'n'paste. I would prefer not to duplicate the code. I tried the following approach to extract them from the bootRun task, but Gradle keeps complaining that he does not find the functions systemProperty and environment. Similarly if I use the Intellij integrated feature 'extract Method':
task specialConfiguration() {
systemProperties System.properties
systemProperty "spring.cloud.config.failFast", "false"
if (project.hasProperty("TEAM_ENCRYPT_KEY"))
environment "ENCRYPT_KEY", "$TEAM_ENCRYPT_KEY"
}
bootRun {
dependsOn 'specialConfiguration'
}
How can I extract this short piece of code from the 3 tasks to avoid duplicate code?
Gradle keeps complaining that he does not find the functions systemProperty and environment
This is a prime example where the Kotlin DSL would shine. You would know exactly what methods/properties are available at any given time because it's a strongly type language unlike Groovy.
With that said, when you do the following:
task specialConfiguration() {
systemProperties System.properties
systemProperty "spring.cloud.config.failFast", "false"
if (project.hasProperty("TEAM_ENCRYPT_KEY"))
environment "ENCRYPT_KEY", "$TEAM_ENCRYPT_KEY"
}
bootRun {
dependsOn 'specialConfiguration'
}
You are:
Declaring a task named specialConfiguration.
No type was specified so the type is DefaultTask.
Configure bootRun task to depend on specialConfiguration
I think you are assuming that dependsOn is like "configuring" a task when really it's just adding a dependency to the task. See Adding dependencies to a task.
I am assuming that runSmokeTest is of type Test. So tasks test, runSmokeTest, and bootRun all implement the JavaForkOptions interface which is where the systemProperties(..), systemProperty(.., ..) and environment(.., ..) methods come from.
With that said, since you know the three tasks you want to configure, and they all implement JavaForkOptions and in some fashion, you can do (Kotlin DSL):
import org.springframework.boot.gradle.tasks.run.BootRun
// Assuming this is a Test task type
tasks.register("runSmokeTest", Test::class)
// Define a new Action (configuration)
val taskConfig = Action<JavaForkOptions> {
systemProperties(System.getProperties() as Map<String, Any>)
systemProperty("spring.cloud.config.failFast", false)
if (project.hasProperty("TEAM_ENCRYPT_KEY")) {
environment("ENCRYPT_KEY", project.property("TEAM_ENCRYPT_KEY")!!)
}
}
// Configure all three tasks
tasks.named("test", Test::class, taskConfig)
tasks.named("runSmokeTest", Test::class, taskConfig)
tasks.named("bootRun", BootRun::class, taskConfig)
The Groovy version of Francisco Mateo's answer, in case anyone needs that.:
Closure<JavaForkOptions> configAction = {
systemProperties System.properties
systemProperty "spring.cloud.config.failFast", "false"
if (project.hasProperty("MOBTECH_ENCRYPT_KEY"))
it.environment "ENCRYPT_KEY", "$MOBTECH_ENCRYPT_KEY"
}
# Configure the tasks with it
bootRun (configAction)

How to execute gradle task during project import in Intellij Idea

Let's assume my build.gradle file contains task generateSources which as name suggests generates additional java files. It's easy to ensure that generateSources is executed before compileJava: compileJava.dependsOn generateSources. How can I make sure generateSources is called when importing project into Intellij Idea as well?
To elaborate on #vladimir-sitnikov's answer: I added the idea-ext-plugin to my root project:
apply plugin: 'org.jetbrains.gradle.plugin.idea-ext'
// ...
buildscript {
dependencies {
classpath "org.jetbrains.gradle.plugin.idea-ext:org.jetbrains.gradle.plugin.idea-ext.gradle.plugin:0.7"
}
}
Because without that I wasn't able to use it in my sub project, but now it works like this:
idea.project.settings.taskTriggers {
beforeSync tasks.getByName("generateSources")
}
Adding the plugin to the sub-project only didn't do it.
Note: The plugin's documentation is kind of limited, but in "DSL spec v. 0.2" is stated
beforeSync - before each Gradle project sync. Will NOT be executed on initial import
Didn't try that, but it works with existing projects.
This can be done via id("org.jetbrains.gradle.plugin.idea-ext") plugin (https://github.com/JetBrains/gradle-idea-ext-plugin).
See sample code in Gradle sources: https://github.com/gradle/gradle/blob/135fb4751faf2736c231636e8a2a92d47706a3b9/buildSrc/subprojects/ide/src/main/kotlin/org/gradle/gradlebuild/ide/IdePlugin.kt#L147
You can set the task in Gradle tool window: Execute Before Sync:

Creating a post build copy task with Gradle

I am struggling with the Gradle build lifecycle; specifically with the split between the configuration and execution phases. I have read a number of sections in the Gradle manual and have seen a number of ideas online, but have not found a solution to the following problem:
I want to run a specific task to produce an artifact at the end of my java-library-distribution build that is a flattened version of the runtime configuration jars. That is, I only want to produce the artifact when I run the specific task to create the artifact.
I have created the following task:
task packageSamplerTask(type: Tar, dependsOn: distTar) {
description "Packages the build jars including dependencies as a flattened tar file. Artifact: ${distsDir}/${archivesBaseName}-${version}.tar"
from tarTree("${distsDir}/${archivesBaseName}-${version}.tar").files
classifier = 'dist'
into "${distsDir}/${archivesBaseName}-dist-${version}.tar"
}
Although this task does produce the required artifact, the task runs during gradle's configuration phase. This behavior has the following consequences:
Irrespective of which task I run from the command line, this packageSamplerTask task is always run, often unnecessarily; and
If I clean the project, then the build fails on the next run because $distsDir doesn't exist during the configuration phase (obviously).
It appears that if I extend the Copy task in this manner I'm always going to get this kind of premature behavior.
Is there a way to use the << closure / doLast declarations to get what I want? Or is there something else I'm missing / should be doing?
Update
After further work I have clarified my requirements, and resolved my question as follows (specifically):
"I want to package my code and my code's dependencies as a flat archive of jars that can be deployed as a jMeter plugin. The package can then be installed by unpacking into the jMeter lib/ext directory, as is. The package, therefore, must not include the jMeter jars (and their dependencies) which are used for building and testing"
Because Gradle doesn't appear to support the Maven-like provided dependency management, I created a new configuration for my package which excludes the jMeter jars.
configurations {
jmpackage {
extendsFrom runtime
exclude group: 'org.apache.jmeter', name: 'ApacheJMeter_core', version: '2.11'
exclude group: 'org.apache.jmeter', name: 'ApacheJMeter_java', version: '2.11'
}
}
And then created the following task (using the closure recommendation from Peter Niederwieser):
task packageSamplerTask(type: Tar, dependsOn: assemble) {
from { libsDir }
from { configurations.jmpackage.getAsFileTree() }
classifier = 'dist'
}
This solution appears to work, and it allows me to use just theGradle java plugin, too.
The task declaration is fine, but the flattening needs to be deferred too:
...
from { tarTree("${distsDir}/${archivesBaseName}-${version}.tar").files }
Also, the Tar file should be referred to in a more abstract way. For example:
from { tarTree(distTar.archivePath).files }
First your task isn't executed in the configuration phase but like EVERY task it is configured in that phase. And your closure is just a configuration of your task (a Configuration closure, not an Action closure). That is why your code is "executed" in the configuration phase".
If you want your code to be executed in the execution phase have to write it in a doLastclosure or doFirst. But in your case it is better to keep it in a configuration closure, because you are configuring your task.
To make sure your build doesn't fail because of the missing folder, you can create it with distsDir.mkdirs().

How to pass system property to Gradle task

I'm using Gradle spring-boot plugin and I need to select a spring active profile for the test run.
How do I pass spring.profiles.active system property to the bootRun plugin's task?
What has already failed:
task bootRunLocal {
systemProperty "spring.profiles.active", "local"
System.setProperty("spring.profiles.active", "local")
tasks.bootRun.execute() // I suspect that this task is executed in a separate JVM
}
and some command line magic also fails:
./gradle -Dspring.profiles.active=local bootRun
Could someone kindly help me solve my troubles?
Update from the answers and comments:
I'm able to set the systemProperty and pass it to the spring container by doing :
run {
systemProperty "spring.profiles.active", "local"
}
However, when I do this, the local profile is being set for both bootRun task and bootRunLocal task. I need a way to set this property for bootRunLocal task and call booRun task from bootRunLocal.
That might sound very simple, but I come with peace from the structured world of Maven.
I know I'm late here... but I recently faced this exact issue. I was trying to launch bootRun with spring.profiles.active and spring.config.location set as system properties on the command line.
So, to get your command line "magic" to work, simply add this to your build.gradle
bootRun {
systemProperties System.properties
}
Then running from the command line...
gradle -Dspring.profiles.active=local bootRun
Will set local as the active profile, without needing to define a separate task simply to add the env variable.
task local {
run { systemProperty "spring.profiles.active", "local" }
}
bootRun.mustRunAfter local
Then run gradle command as:
gradle bootRun local
There is no generic way to pass system properties to a task. In a nutshell, it's only supported for tasks that fork a separate JVM.
The bootRunLocal task (as defined above) will not execute in a separate JVM, and calling execute() on a task isn't supported (and would have to happen in the execution phase in any case). Tests, on the other hand, are always executed in a separate JVM (if executed by a Test task). To set system properties for test execution, you need to configure the corresponding Test task(s). For example:
test {
systemProperty "spring.profiles.active", "local"
}
For more information, see Test in the Gradle Build Language Reference.
SPRING_PROFILES_ACTIVE=local gradle clean bootRun
This is according to this and this and it works.
According to the spring-boot-gradle-plugin documentation you should be able to pass arguments like this
./gradlew bootRun --args='--spring.profiles.active=dev'
Seems like this is a new gradle feature since 4.9. I used it in my project and it worked out of the box.
For gradle 2.14 below example works.
I have added as below.
When System.properties['spring.profiles.active'] is null then default profile is set.
bootRun {
systemProperty 'spring.profiles.active', System.properties['spring.profiles.active']
}
command line example
gradle bootRun -Dspring.profiles.active=dev
Just for reference if anyone will have this issue:
Vlad answer didn't quite worked for me but this one works great with 2.4,
task local <<{
bootRun { systemProperty "spring.profiles.active", "local" }
}
local.finalizedBy bootRun
then gradle local
Responding to OP's exact request here ...
How do I pass spring.profiles.active system property to the bootRun plugin's task?
And assuming by "pass" the OP meant "pass from commandline" or "pass from IDE invocation" ... This is how I like to do it.
Add this to build.gradle:
/**
* Task from spring-boot-gradle-plugin, configured for easier development
*/
bootRun {
/* Lets you pick Spring Boot profile by system properties, e.g. gradle bootRun -Dspring.profiles.active=dev */
systemProperties = System.properties
}
Then when you invoke it, use the familiar Java flag for setting a system property
gradle bootRun -Dspring.profiles.active=local
There is one main advantage of sticking to system properties, over the environment variables option (SPRING_PROFILES_ACTIVE=local gradle bootRun) ... and that's easy portability between Linux/OS X (bash, etc.) and Windows (cmd.exe anyway).
I learned this way from this blog post.
(UPDATE: Ah somehow I had missed #Erich's response with same recommendation. Oops! I'm leaving my answer, because of the additional details about portability, etc.)
You can create a new task (in discussed case with name bootRunLocal), that would extend org.springframework.boot.gradle.run.BootRunTask and setup properties before task execution. You can create such a task with following code:
task bootRunLocal(type: org.springframework.boot.gradle.run.BootRunTask) {
doFirst() {
main = project.mainClassName
classpath = sourceSets.main.runtimeClasspath
systemProperty "spring.profiles.active", "local"
}
}
More details can be found here:
https://karolkalinski.github.io/gradle-task-that-runs-spring-boot-aplication-with-profile-activated/
Starting from SpringBoot 2.0.0-M5 setSystemProperties() is no longer a method of the task bootRun.
The build.gradle needs to be updated to
bootRun {
execSpec {
// System.properties["spring.profiles.active"]
systemProperties System.properties
}
}
This is as springBoot's run task uses org.gradle.process.JavaExecSpec
This works for me using Gradle 4.2
This works:
SPRING_PROFILES_ACTIVE=production ./gradlew app-service:bootRun
with run command you can add to build file run { systemProperties = System.properties } and start with gradle run -Dspring.profiles.active=local
Another way which doesn't require any support from the gradle task: Set the JAVA_TOOL_OPTIONS environment variable:
JAVA_TOOL_OPTIONS='-Dfoo=bar' gradle ...
Or if the variable might already contain anything useful:
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -Dfoo=bar" gradle ...
// defualt value
def profiles = 'dev'
bootRun {
args = ["--spring.profiles.active=" + profiles]
}
Then you can simply pick a specific version when starting a gradle task, like
./gradlew bootRun -P dev
"dev" is gonna to take place "prod"

How to compile single class dependency in gradle outside the main project

I have a gradle project that contains only Selenium/TestNG test classes. They are executed against a deployed war application. All works fine and now I'm adding a java utility that will query the test base and print list of tests that belong to a given TestNG group. The utility should be compiled and executed separate from the main project, as users may want to query the test base before test execution.
I added the following to build.gradle:
task listgroups(dependsOn:'buildUtil' ) <<{
ant.java(classname: 'util.TestGroupScanner', fork: true,
classpath: "src/test/java")
}
task buildUtil {
compile {
source = "src/test/java/util"
}
}
However, when calling listgroups task, I'm getting the following error:
C:\console-bg1>g listgroups
FAILURE: Build failed with an exception.
(...)
* What went wrong:
A problem occurred evaluating root project 'console-bg1'.
> Could not find method compile() for arguments [build_4emu7duna2isgubc1k8uts8k9
8$_run_closure6_closure11#d210ab] on root project 'console-bg1'.
I'm not sure how to resolve this issue and needless to say, haven't found an answer online so far. Any pointers appreciated.
The problem is in the buildUtil task, as the error suggests. The buildUtil declares a compile closure, but such closure does not exist for the default task.
Let me try to clarify what your setup is. The util.TestGroupScanner source is in the src/test/java/util directory, which you want to compile separately from other source (presumably src/main/java and src/test/java). The buildUtil task is supposed to compile sources in src/test/java/util, and the listgroups task executes the scanner utility on sources src/test/java folder.
In this case, I'd suggest you declare a new source set for your utility sources, like this:
sourceSets {
util {
java {
srcDir 'src/test/java/util'
}
}
}
This will automatically create a compile task called compileUtilJava for you, that will compile those sources. I also think you'll want to include utility classes in the classpath when executing your tool, which can be retrieved by sourceSets.util.output.classesDir. So now your listgroups task will look like:
task listgroups(dependsOn: 'compileUtilJava' ) <<{
ant.java(classname: 'util.TestGroupScanner', fork: true,
classpath: "src/test/java:" + sourceSets.util.output.classesDir)
}
One thing I have noticed about your setup, is that src/test/java/util source folder is nested under src/test/java. Gradle will assume src/test/java to be the default folder for your project test, and will therefore automatically include it, and all of its children when running tests. Since you want to keep your utility folder separate from the default setup, I would recommend you put it in src/testutil/java, to avoid any clashes. If you do, don't forget to update the sourceSets setup above with the correct source path.
To solve this with gradle, I suggest to create a specific sourceset for your util class and add a task of type JavaExec that executes this class for printing your testng groups. Have a look at the following snippet:
apply plugin:'java'
...
...
configurations{
testUtilCompile.extendsFrom testCompile
}
...
...
sourceSets{
testUtil{
java {
srcDir "src/test/java"
include "util/**"
}
}
}
task printGroups(type:JavaExec){
main = "util.TestGroupScanner"
classpath = sourceSets.testUtil.runtimeClasspath
}
regards,
René

Resources