Recommended way to programatically add task output in Gradle 3+

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)?

If you need a pure Java solution, reflection https://github.com/tbroyer/gradle-apt-plugin/blob/master/src/main/java/net/ltgt/gradle/apt/CompatibilityUtils.java

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

1 Like

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?

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.

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.

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).

1 Like

Thanks @sterling for your advises.