How to customize JavaExec command line

Hello Everyone !

I have a project comprised of three java server apps. They need to run concurrently for me to use the application.

Gradle’s JavaExec waits for each java process to end (maybe that’s DefaultJavaExecAction:40) therefore only one JavaExec can run at a time.

I would like to customize JavaExec to build a different command line and instead of a myjava.exe -cp ... it would produce cmd /k start "myjava.exe -cp...". What would be the recommended approach to have such behavior ?

What we tried:

  • sneak in a change to commandLine but it’s read-only :wink:
  • use WorkerExecutor but it really doesn’t look right and seems to trigger multiple Gradle instances, eeeww
  • naively set executable to cmd /k start myjava.exe but javaexec seems to try to do a java -v first and is no longer to get its result :boom:
  • overriding JavaExec to leverage its classpath management…etc. work in progress but that proves to be trickier than I thought

Context:

  • Windows
  • Gradle 6.5.1
  • Java 8
  • can’t upload Gradle scan - company policy, sorry

Any pointer to a clean solution would be greatly appreciated.

Thank-you !

The three app are defined in distinct subprojects and --parallel should be able to have them all run concurrently but that would be nice to not have to use a flag every time (and enabling it by default is not currently an acceptable option in our build).

Ended up doing something like that below but it doesn’t work with Gradle 6.6 (worked with 6.5.1). Any idea why it doesn’t work with 6.6 ? looks like commandLine only contains the executable now.

@CompileStatic
class ServerJavaExec extends JavaExec {

    private final Property<ExecResult> serverJavaExecResult;

    def serverName

    ServerJavaExec() {
         super()
         serverJavaExecResult = objectFactory.property(ExecResult.class);
    }

    @Override
    @TaskAction
    public void exec() {
        // drop the first item in commandLine, it is the executable (java.exe)
        def javaCommandArgsLine = commandLine.drop(1).join(' ')
        def javaCommand = "cmd /k start \"$serverName\" \"$executable\" $javaCommandArgsLine"

        getLogger().info "Executing $javaCommand ..."
        // >> Here I execute javaCommand, it eventually goes to process builder <<

        // immediately return a success result
        serverJavaExecResult.set([
            exitValue: 0,
            assertNormalExitValue: this,
            rethrowFailure: this
        ] as ExecResult);
    }

    @Override
    public Provider<ExecResult> getExecutionResult() {
       return serverJavaExecResult;
    }
}