Dagger SPI

The Dagger SPI is a mechanism to hook into Dagger’s annotation processor and access the same binding graph model that Dagger uses. With the SPI, you can write a plugin that

  • adds project-specific errors and warnings, e.g. Bindings for android.content.Context must have a @Qualifier or Bindings that implement DatabaseRelated must be scoped
  • generates extra Java source files
  • serializes the Dagger model to a resource file
  • builds visualizations of the Dagger model
  • and more!

The opportunities are endless, which is why the SPI is open for anyone to use!

Note: The APIs for implementing an SPI plugin are experimental and are free to change.All changes will be documented in our GitHub releases. We encourage you to reach out when you find rough edges so we can make the APIs easier to use.

Declaring your SPI plugin

SPI plugins are classes that implement BindingGraphPlugin and are loaded using Java’s ServiceLoader, which is easily done by using @AutoService. Your BindingGraphPlugin should be available alongside Dagger on the annotation processor path during compilation so that it can be loaded. In Bazel that is done with a java_plugin; in Gradle declare a dependency with annotationProcessor scope.

When Dagger detects an SPI plugin on the classpath, it will call its visitGraph(BindingGraph, DiagnosticReporter) method for each valid @Component that Dagger compiles. If full binding graph validation is turned on, Dagger will also call visitGraph() for each module, component, and subcomponent that has no errors when considering their full binding graph. (See isFullBindingGraph().)In that case, the BindingGraph may contain MissingBinding nodes.

The BindingGraph is implemented as a Network that has nodes for components, bindings, and missing bindings. Edges in the graph represent dependencies as well as parent-child component relationships. For more, please refer to the javadoc.

Adding Errors and Warnings

Plugins can use DiagnosticReporter to report project-specific errors and warnings. These diagnostics will be passed to the Messager with additional information to help users debug the issue. For example, an invalid DependencyEdge will also print a dependency trace from a component to the dependency, similar to regular Dagger errors. In fact, for those that are familiar with writing annotation processors, the DiagnosticReporter methods will look familiar to those on Messager except that they take BindingGraph nodes and edges instead of Elements.

All reported diagnostics will be prefixed with [<plugin name>] so that users can easily identify the source/category of the diagnostic. The plugin name defaults the fully qualified class name of the BindingGraphPlugin, but can be configured by returning a value for pluginName().

Generating files

If you’d like to generate files based on the binding graph, you can obtain an instance of a Filer from the initFiler() method. The filer can be used within visitGraph() to generate files just like a normal annotation processor would.

One common use case for generating files is to serialize the binding graph model to JSON/proto for a UI to use later to help users visualize the binding graph. (P.S.: If you write a really awesome visualization tool, let us know so we can promote it!)

Types and Elements

Annotation processors are given an instance of [Types] in order to simplify code that interfaces with Java’s type system, as well as an instance of [Elements] for code that interfaces with source code elements. SPI plugins can obtain references to these types via the initTypes() and initElements() methods.

Command line options

SPI plugins may declare a set of supported command line options with the supportedOptions() method. If any of these are passed to javac, Dagger will forward the values to the initOptions() method.