Do tasks of the same custom task types using file parameters conflict with each-other?

Hello,

I’m not sure whether this is a bug or if I’m doing something wrong.

The real scenario I want to achieve is to download several files from several remote flat (simple filesystem) repositories into different target folders. There would be a single task type, with parameters for the repositories, the files to download and target directories. Executing the tasks separately is OK, but the tasks fail (conflict?) when executing with a single command

Below is a simple example reproducing the same issue.

There is a custom task type taking a single file parameter:

package example;

import java.io.File;

import org.gradle.api.DefaultTask;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.options.Option;

public class ExampleTask extends DefaultTask {

   private Property<File> fileParam;

   public ExampleTask() {
      fileParam = getProject().getObjects().property( File.class );
   }

   @Option ( option = "fileParam", description = "A file parameter" )
   public void setFileParam( File fp ) {
      fileParam.set( fp );
   }

   @TaskAction
   public void run() {
      if ( !fileParam.isPresent() ) {
         throw new IllegalArgumentException( "Missing file param" );
      }

      System.out.println( "File parameter: " + fileParam.get() );
   }
}

In build.gradle there are two tasks using the same task type:

plugins {
   id 'java'
}

task taskA(type: example.ExampleTask) {
   fileParam = file( "${project.buildDir}/A" )
}

task taskB(type: example.ExampleTask) {
   fileParam = file( "${project.buildDir}/B" )
}

When I execute the tasks one by one, each is working fine:

$ ./gradlew taskA 

> Task :taskA
File parameter: /home/.../testtask/build/A

BUILD SUCCESSFUL in 657ms
1 actionable task: 1 executed

$ ./gradlew taskB

> Task :taskB
File parameter: /home/.../testtask/build/B

BUILD SUCCESSFUL in 505ms
1 actionable task: 1 executed

However when I try to execute both tasks in a single command it fails with the following error, even when running in non parallel mode:

$ ./gradlew --no-parallel taskA taskB                 

FAILURE: Build failed with an exception.

* What went wrong:
Option 'fileParam' cannot be cast to type 'java.io.File' in class 'example.ExampleTask'.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

I’ve tried the same using simple File instead of Property as the field type, but got the same result.

The Gradle versions I checked are 6.2, 6.1.1 and 5.1.1. Both behave the same way.

There is a workaround: adding taskB.dependsOn( ‘taskA’ ) dependency rule to build.gradle and calling taskB executes both tasks without any issue.

$ ./gradlew taskB

> Task :taskA
File parameter: /home/.../testtask/build/A

> Task :taskB
File parameter: /home/.../testtask/build/B

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

But I’m still curious why executing both tasks without a dependency rule fails.

It may not be the task that has the issue. Can you post the output with --stacktrace?

Well, I’ve figured it out.

The issue was caused by the @Option annotation on the fileParam.

@Option ( option = "fileParam", description = "A file parameter" )

Removing it solved the issue.
I’ve just learned that @Option is for exposing the parameter to a command line option. I don’t need it.