Jenkins : Dependencies among plugins

Mandatory dependencies

A plugin can declare dependencies to other plugins. When plugin X depends on Y, X can see all the classes in Y, as well as Y's libraries and dependencies. (That is, at runtime, Jenkins will set up classloaders in such a way that X classloader delegates to Y classloader.)

To declare a dependency, add the following entry to plugin pom.xml

<dependencies>
  <dependency>
    <groupId>org.jvnet.hudson.plugins</groupId>
    <artifactId>javanet-uploader</artifactId>
    <version>1.5</version>
  </dependency>
...
</dependencies>

The groupId, artifactId, version needs to be changed according to what you want to depend on. The maven mojos associated to the "hpi" packaging will use this information to put necessary information in the plugin manifest, which in turn is read by Jenkins at runtime.

Optional dependencies

By default, dependencies are mandatory — if any of the dependencies are unavailable then the plugin will be disabled and can not be used.

However, this is just the default. It is possible to declare dependencies to other plugins as optional. In this way, even if some of the optional dependencies are unavailable, the plugin will continue to be loaded and executed.

To declare an optional dependency, add the <optional/> tag to the declared dependency in the plugin pom.xml

<dependencies>
  <dependency>
    <groupId>org.jvnet.hudson.plugins</groupId>
    <artifactId>javanet-uploader</artifactId>
    <version>1.5</version>
    <optional>true</optional>
  </dependency>
...
</dependencies>

If any of the classes in the unavailable optional dependencies are used in the plugin a NoClassDefError will be thrown. It is still your responsibility to cope with these errors (although Jenkins itself does some of this handling. If your particular extension fails to load with LinkageError because of a missing dependency, it will gracefully disable just that extension and move on to try instantiating other extensions.

You can mark your extension as an optional extension by changing the @Extension annotation to @Extension(optional = true) and Jenkins don't log any class loading errors when reading it.

@Extension(optional = true)
public static class YourDescriptor extends Descriptor<YourDescribable> {
    @Override
    public String getDisplayName() {
        return "YourDisplayName";
    }
}

To determine if an optional dependency is installed, the Jenkins.getPlugin(String) method can be used.

if (Jenkins.getInstance().getPlugin("javanet-uploader") != null) {
    // use classes in the "javanet-uploader" plugin
}

Tips for optional dependencies

Tips for optional dependencies

Versions

At the moment there is no built-in mechanism for creating a dependency on a specified version of a plugin. (But it's on the TODO list) So you have to ask for yourself:

PluginWrapper requiredPlugin = Jenkins.getInstance().getPlugin("javanet-uploader");
if (requiredPlugin != null) {
    // We know we have a "javanet-uploader" plugin, but no knowledge of the version
    String reqVersion = requiredPlugin.getVersion();
    // now compare the version of that plugin to the values you can work with
}