Using execution-time parameters to JavaExec tasks

A spin-off question from a previous one which led to the use of a custom build service to run Selenium tests. Short version, lets take an example from the JVM Test Suite Plugin docs:

testing { 
    suites {
        test {
            targets {
                all {
                    testTask.configure { 
                        // set a system property for the test JVM(s)
                        systemProperty 'applicationUrl', 'http://localhost:8080'

Basically, I need to pass the URL of the build service to the tests, and the obvious way to do that is with a system property — but the systemProperty used here (and in other JavaExec-based tasks) requires the value to be determined at configure time, and the URL isn’t going to be known until the build service has started. So in theory, what I want to do is something like:

systemProperty 'applicationUrl', ()->testServiceProvider.get().getApplicationUrl()

…or something in that general theme.

Now, I currently have this working by using the jvmArgumentProviders property to inject a -D parameter to the Java startup, since that mechanism does work the way I need… evaluating when the task runs, not when it’s configured. But is there a better way of doing this?


Actually systemProperty takes an Object as second argument.
But the code that evaluates it is not looking for callables.
But it uses toString().
So you can use some anonymous class that does the poor-man’s lazy calculation in its toString() method.

The other alternative is as you said a jvmArgumentProvider.
Those are especially then helpful when you have inputs or input files that influence the result / should make the task out of date.

Just that your systemProperty would have another value would not make the task out-of-date as they are not automatically considered as inputs. In jvmArgumentProviders you can define properties with input annotations though, that are then considered as inputs like all others.

I did consider the toString() hack, but decided it was probably unsafe… the kind of thing that ends up unintentionally starting a server as a side effect of a logging statement, or someone poking around with remote debugging. So if you don’t know of anything more robust, that’s okay… I’ll stick with the argument provider, since it works and isn’t too ugly.

As for tracking inputs, not a concern in this case… the build service is a transient resource, no state tracking needed (or wanted). But yes, I can see that could be important if I was passing in something like a reference to the output of another task.

Exactly, or maybe a changing dependency, like the snapshot version of JMockit and then generating the JVM argument to include it as Java Agent. If the file changes because a new snaphsot is published, the task should re-run.