A problem was found with the configuration of the Gradle 7 task
Tags: gradle
Published: 2021-06-02 13:36:47

Developers want builds to be fast, correct and reliable. In order to improve the reliability and correctness of Gradle builds, [Gradle 7](https://docs.gradle.org/7.0/release-notes.html) has introduced stricter validation checks for tasks. This means that [validation warnings in Gradle 6 have now turned in to errors in Gradle 7](https://docs.gradle.org/current/userguide/upgrading_version_6.html#task_validation_problems_are_now_errors).
When upgrading to Gradle 7, you may encounter an issue that some of your previously working plugins may not pass the validation and therefore fail your build. 

The error message in your build upon upgrading to Gradle 7 could look like this:

```
* What went wrong:
A problem was found with the configuration of task ':incompatibleTask' (type 'IncompatibleTask').
  - Type 'com.osacky.replace.example.IncompatibleTask' property 'foo' is missing an input or output annotation.
    
    Reason: A property without annotation isn't considered during up-to-date checking.
    
    Possible solutions:
      1. Add an input or output annotation.
      2. Mark it as @Internal.
    
    Please refer to https://docs.gradle.org/7.0.2/userguide/validation_problems.html#missing_annotation for more details about this problem.

```

# Fixing first party plugins
For tasks defined within your own build, the error message is actionable.

> To fix this problem, you need to annotate the property with the appropriate annotation, for example `@InputDirectory` for a property representing an input directory, or `@OutputDirectory` for a property representing an output directory.

> Alternatively, if the property is internal, that is to say that it shouldn’t participate in up-to-date checking (it’s not an input or an output), then you need to annotate it with `@Internal`. 

For tasks defined using the so-called ad-hoc api, [you can also add the input and output declarations](https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:runtime_api_for_adhoc).

# Fixing third party plugins
For third party plugins, [it isn't so clear what to do](https://github.com/gradle/gradle/issues/16580). First, check to see if there is an update to the Gradle plugin which makes the task compatible with Gradle 7.

## Get involved
If no such updated version exists, this is a great time to get involved in an open source project. You can file an issue for that third party plugin to add the proper annotation to the task definition.
Even better, you can also submit a pull request to add the proper annotations.

# Unmaintained third party plugins
For those unmaintained plugins, there is another option. You can redefine the task in your `buildSrc` directory and declare the proper annotations. Here is how to do this.

First, if you have not already done so, create a `buildSrc` directory in your project and configure the `build.gradle` file. [Here is a sample.](https://github.com/runningcode/replace-plugin-task/blob/master/buildSrc/build.gradle.kts)

Second, copy paste the task class in to your `buildSrc` project in your Gradle build. Make sure to paste it in to the proper package. Here [is a sample copy](https://github.com/runningcode/replace-plugin-task/tree/master/buildSrc/src/main/java/com/osacky/replace/example) and [the task's original definition](https://github.com/runningcode/replace-plugin-task/blob/master/plugin/src/main/java/com/osacky/replace/example/IncompatibleTask.kt).

Third, [add the missing annotation](https://github.com/runningcode/replace-plugin-task/blob/master/buildSrc/src/main/java/com/osacky/replace/example/IncompatibleTask.kt#L9) to the missing property defined in the task.

Finally, run your Gradle build and enjoy!

[Here is a sample Gradle project](https://github.com/runningcode/replace-plugin-task) demonstrating how to do this. The plugin is defined as a composite build in the [`plugin` project](https://github.com/runningcode/replace-plugin-task/blob/master/plugin/build.gradle.kts#L18). It is included in the main build and [applied in the `lib` project](https://github.com/runningcode/replace-plugin-task/blob/master/lib/build.gradle#L3).

To run the sample, `./gradlew :lib:incompatibleTask`.

To see the incompatible task fail the build in an integration test, run `./gradlew :plugin:test`.

## Further resources
If you are curious to understand more about how monkey patching classes with `buildSrc` works and classloader hierarchy in Java, I recommend [reading this post](https://dev.to/autonomousapps/abusing-gradle-s-class-loader-hierarchy-for-fun-and-profit-oca) by @autonomousapps.

Thanks to Tony (@autonomousapps) for proofreading this blog post.

> The opinions expressed in this post are the opinions of Nelson Osacky and not of his employer.