Fork me on GitHub

About plugins

A plugin bundles Java classes and libraries (JAR files), that can be loaded / unloaded by PF4J at application runtime.

In case you don’t need to load / unload certain parts of Java code in your application at runtime, it is not strictly necessary to use plugins at all. You can also only make use of extensions and place the compiled classes into the application classpath (so called system extensions).

How plugins are defined

Create (it’s optional) a Plugin class if you are interested for plugin’s lifecycle events (start, stop, …):

import org.pf4j.Plugin;
import org.pf4j.PluginException;
import org.pf4j.PluginWrapper;

public class MyPlugin extends Plugin {

    public MyPlugin(PluginWrapper wrapper) {
        super(wrapper);
    }

    @Override
    public void start() throws PluginException {
        // This method is called by the application when the plugin is started.
    }

    @Override
    public void stop() throws PluginException {
        // This method is called by the application when the plugin is stopped.
    }

    @Override
    public void delete() throws PluginException {
        // This method is called by the application when the plugin is deleted.
    }

}

How plugin metadata is defined

In order to make the plugin loadable for PF4J you also have to provide some metadata.

  • The fully qualified class name of the plugin class (derived from org.pf4j.Plugin) (optional).
  • The unique identifier for the plugin.
  • The version of the plugin according to Semantic Versioning Specification.
  • The required application version according to Semantic Versioning Specification (optional).
  • Dependencies with other plugins (optional).
  • A description for the plugin (optional).
  • The name of the plugin provider / author (optional).
  • The license of the plugin (optional).

A plugin class name is optional. You could create a plugin class only if you want to be notified when your plugin is started, stopped or deleted.

There are multiple ways to provide metadata for a plugin.

Provide plugin metadata through MANIFEST.MF

Add the following contents to the META-INF/MANIFEST.MF file of the plugin:

Plugin-Class: org.pf4j.demo.welcome.WelcomePlugin
Plugin-Id: welcome-plugin
Plugin-Version: 0.0.1
Plugin-Requires: 1.0.0
Plugin-Dependencies: x, y, z
Plugin-Description: My example plugin
Plugin-Provider: Decebal Suiu
Plugin-License: Apache License 2.0

In case you’re using Maven, you might set these values within your pom.xml via maven-jar-plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
            <manifestEntries>
                <Plugin-Class>org.pf4j.demo.welcome.WelcomePlugin</Plugin-Class>
                <Plugin-Id>welcome-plugin</Plugin-Id>
                <Plugin-Version>0.0.1</Plugin-Version>
                <Plugin-Requires>1.0.0</Plugin-Requires>
                <Plugin-Dependencies>x, y, z</Plugin-Dependencies>
                <Plugin-Description>My example plugin</Plugin-Description>
                <Plugin-Provider>Decebal Suiu</Plugin-Provider>
                <Plugin-License>Apache License 2.0</Plugin-License>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

Or via maven-assembly-plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <finalName>${project.artifactId}-${project.version}-plugin</finalName>
        <appendAssemblyId>false</appendAssemblyId>
        <attach>false</attach>
        <archive>
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
            <manifestEntries>
                <Plugin-Class>org.pf4j.demo.welcome.WelcomePlugin</Plugin-Class>
                <Plugin-Id>welcome-plugin</Plugin-Id>
                <Plugin-Version>0.0.1</Plugin-Version>
                <Plugin-Requires>1.0.0</Plugin-Requires>
                <Plugin-Dependencies>x, y, z</Plugin-Dependencies>
                <Plugin-Description>My example plugin</Plugin-Description>
                <Plugin-Provider>Decebal Suiu</Plugin-Provider>
                <Plugin-License>Apache License 2.0</Plugin-License>
            </manifestEntries>
        </archive>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Provide plugin metadata through properties file

Create a file called plugin.properties in the root of your plugin folder (or ZIP archive):

plugin.class=org.pf4j.demo.welcome.WelcomePlugin
plugin.id=welcome-plugin
plugin.version=0.0.1
plugin.requires=1.0.0
plugin.dependencies=x, y, z
plugin.description=My example plugin
plugin.provider=Decebal Suiu
plugin.license=Apache License 2.0

Notes about plugin dependencies

Plugins may have dependencies on each other. Those dependencies are specified in the plugin metadata as described above. In order to reference a certain plugin as a dependency you need to provide its specified plugin id.

  • If pluginA depends on another pluginB you can set in the metadata of pluginA:

    Plugin-Dependencies: pluginB
    
  • If pluginA depends on another pluginB in version 1.0.0 you can set in the metadata of pluginA:

    Plugin-Dependencies: pluginB@1.0
    
  • If pluginA depends on another pluginB starting from version 1.0.0 you can set in the metadata of pluginA:

    Plugin-Dependencies: pluginB@>=1.0.0
    
  • If pluginA depends on another pluginB starting from version 1.0.0 up to 2.0.0 (excluding) you can set in the metadata of pluginA:

    Plugin-Dependencies: pluginB@>=1.0.0 & <2.0.0
    
  • If pluginA depends on another pluginB starting from version 1.0.0 up to 2.0.0 (including) you can set in the metadata of pluginA:

    Plugin-Dependencies: pluginB@>=1.0.0 & <=2.0.0
    
  • You can also define multiple plugin dependencies with the same pattern separated by a comma:

    Plugin-Dependencies: pluginB@>=1.0.0 & <=2.0.0, pluginC@>=0.0.1 & <=0.1.0
    

Those kind of dependencies are considered as required. The plugin manager will only make a plugin available at runtime, if all of its dependencies are accomplished.

Optional plugin dependencies

Alternatively you might also define optional dependencies between plugins by adding a question mark behind the plugin id - e.g.:

Plugin-Dependencies: pluginB?

or

Plugin-Dependencies: pluginB?@1.0

In this case pluginA is still being loaded, even if the dependency is not accomplished at runtime. A typical use case for this feature is described in the extensions section of this manual.