Recommended way to programatically add task output in Gradle 3+

(Marcin Zajączkowski) #1

In the passed it was “common” to use task.outputs.file(someFile) to (conditionally) add output(s) to a task. However, the type returned by getOutputs() method changed around Gradle 3 to the internal TaskOutputsInternal class (in addition to the incompatible change in TaskOutputs.file() from TaskOutputs to TaskOutputFilePropertyBuilder which prevents plugins built with Gradle 4 to be run with Gradle 2).

What’s the recommended way of dealing with conditional task’s outputs (preferably the one which is compatible with both Gradle 4 and Gradle 2)?

(Sterling Greene) #2

If you need a pure Java solution, reflection

If you’re using Groovy, you can do this with some dynamic typing.

(Marcin Zajączkowski) #3

Nice, I didn’t know that class.

Update. At fist, I thought it is available in Gradle, especially for plugin developers. But I’ve got a point anyway :).

And in a situation that I don’t care about Gradle 2 compatibility is there any public API (as of Gradle 4) to add output to a task?

(Sterling Greene) #4

I think if you don’t care about Gradle 2 compatibility, you can use task.getOutputs() without any reflection tricks. Gradle 3 and 4 use the same types. It’s not an internal API (despite the internal type leakage).

I will say if you control the task implementation, you should just add the outputs as properties (with @OutputFile, @OutputDirectory, etc). That’ll work for all versions of Gradle and will be better in general.

(Marcin Zajączkowski) #5

Yup, however, in that particular case the file should or should not be an output based on one of the input parameters. Nevertheless, I’m not sure right now how would it impact caching to just keep that field null for preview mode. Maybe it would be just more simply to achieve the same result.

(Sterling Greene) #6

Depending on what you’re trying to do, you could always treat it as an output (and sometimes, the task just wouldn’t create anything) or you could do something more like the Test task and its reports.

It uses @OutputFiles with a Map<String, File> to provide a set of outputs that can have optional parts. I think this may only work with Gradle 3.x+ (I’m not sure when support for Map was added).

(Marcin Zajączkowski) #7

Thanks @sterling for your advises.