You can open this sample in an IDE that supports Gradle.

This sample shows how problems can be emitted via the Problems API and how those reports are consumed on the IDE-side. Visit the user manual to learn more about the Problems API.

Running the sample

To run the sample, execute the ./gradlew :sample-ide:importBuild command.

Project structure

The sample consists of multiple, individual builds composed into a composite build with the following layout

  • sample-project: A Gradle build with plugins that report problems

  • sample-ide: a project that simulates the IDE functionality. In other words, it uses the Gradle Tooling API to configure and run the sample-project build and prints the received problem reports received during the process.

  • reporters/standard-plugin shows the usage of the Problems API in a standard Gradle plugin.

  • reporters/model-builder-plugin shows how to use the Problems API to report problems when reading project configuration via the Tooling API.

  • reporters/script-plugin shows how to use the Problems API in a precompiled script plugin.

Emitting a problem

Problems can be emitted via an injected Problems service. Here’s an example on how to report a problem from a plugin, including adding custom additional data:

reporters/standard-plugin/src/main/java/reporters/StandardPlugin.java
ProblemId problemId = ProblemId.create("adhoc-plugin-deprecation", "Plugin is deprecated", PROBLEM_GROUP);
problems.getReporter().report(problemId, problem -> problem
        .contextualLabel("The 'standard-plugin' is deprecated")
        .documentedAt("https://github.com/gradle/gradle/README.md")
        .severity(Severity.WARNING)
        .solution("Please use a more recent plugin version")
        .additionalData(SomeAdditionalData.class, additionalData -> {
            additionalData.setName("Some name");
            additionalData.setNames(java.util.Arrays.asList("name1", "name2"));
        })
);

Receiving a problem report

Problems are emitted as Tooling API progress events. They can be processed by registering a ProgressListener:

sample-ide/src/main/java/org/gradle/sample/SampleIde.java
@Override
public void statusChanged(ProgressEvent progressEvent) {
    if (progressEvent instanceof SingleProblemEvent) {
        prettyPrint((SingleProblemEvent) progressEvent);
    } else if (progressEvent instanceof ProblemSummariesEvent) {
        prettyPrint((ProblemSummariesEvent) progressEvent);
    }
}

Receiving custom additional data

To read custom additional data on the Tooling API side, you need a view type.

A view type represents interface or class through which you want to access the underlying data. The API will return an implementation of this type that provides a specific "view" of the data, allowing for type-safe access to underlying data. The view type must be compatible with the actual data structure.

Your view type can include various properties based on the following rules:

  • Simple types (String, Integer, Boolean, etc.)

  • Collections (List, Set, Map)

  • Composite types made up of the above

  • Gradle Provider API types, which are automatically mapped to their corresponding types

Also see the CustomAdditionalData for more information.

This view type can be used to retrieve the additional data stored in the problem instance:

sample-ide/src/main/java/org/gradle/sample/SampleIde.java
interface SomeDataView {
    String getName();

    List<String> getNames();
}

This view type can be used to retrieve the additional data stored in the problem instance:

sample-ide/src/main/java/org/gradle/sample/SampleIde.java
AdditionalData data = problem.getAdditionalData();
if (data instanceof CustomAdditionalData) {
    System.out.println(" - additional data: " + ((CustomAdditionalData) data).get(SomeDataView.class).getName());
}