Plugin Extension Points
By defining extension points in your plugin, you can allow other plugins to extend the functionality of your plugin. There are two types of extension points:
- Interface extension points allow other plugins to extend your plugins with code. When you define an interface extension point, you specify an interface, and other plugins will provide classes implementing that interface. You’ll then be able to invoke methods on those interfaces.
- Bean extension points allow other plugins to extend your plugins with data. You specify the fully qualified name of an extension class, and other plugins will provide data which will be turned into instances of that class.
How to declare extension points
You can declare extensions and extension points in the plugin configuration file plugin.xml
, within the <extensions>
and <extensionPoints>
sections, respectively.
To declare extension points in your plugin, add an <extensionPoints>
section to your plugin.xml
. Then insert a child element <extensionPoint>
that defines the extension point name and the name of a bean class or an interface that is allowed to extend the plugin functionality in the name
, beanClass
and interface
attributes, respectively.
myPlugin/META-INF/plugin.xml
<idea-plugin>
<id>my.plugin</id>
<extensionPoints>
<extensionPoint name="myExtensionPoint1" beanClass="com.myplugin.MyBeanClass"/>
<extensionPoint name="myExtensionPoint2" interface="com.myplugin.MyInterface" area="IDEA_PROJECT"/>
</extensionPoints>
</idea-plugin>
- The
name
attribute assigns a unique name for this extension point, it will be prefixed with the plugin’s<id>
automatically. - The
beanClass
attribute sets a bean class that specifies one or several properties annotated with the@Attribute
annotation. - The
interface
attribute sets an interface the plugin that contributes to the extension point must implement. - The
area
attribute determines the scope in which the extension will be instantiated. As extensions should be stateless, it is not recommended to use non-default.IDEA_APPLICATION
for Application (default)IDEA_PROJECT
for ProjectIDEA_MODULE
for Module
The plugin that contributes to the extension point will read those properties from the plugin.xml
file.
To clarify this, consider the following sample MyBeanClass
bean class used in the above plugin.xml
file:
myPlugin/src/com/myplugin/MyBeanClass.java
public class MyBeanClass extends AbstractExtensionPointBean {
@Attribute("key")
public String key;
@Attribute("implementationClass")
public String implementationClass;
public String getKey() {
return key;
}
public String getClass() {
return implementationClass;
}
}
For above extension points usage in anotherPlugin would look like this (see also Declaring Extensions):
anotherPlugin/META-INF/plugin.xml
<idea-plugin>
<id>another.plugin</id>
<!-- declare dependency on plugin defining extension point -->
<depends>my.plugin</depends>
<!-- use "my.plugin" namespace -->
<extensions defaultExtensionNs="my.plugin">
<myExtensionPoint1 key="someKey" implementationClass="another.some.implementation.class"/>
<myExtensionPoint2 implementation="another.MyInterfaceImpl"/>
</extension>
</idea-plugin>
Using extension points
To refer to all registered extension instances at runtime, declare an ExtensionPointName
passing in the fully-qualified name matching its declaration in plugin.xml
.
myPlugin/src/com/myplugin/MyExtensionUsingService.java
public class MyExtensionUsingService {
private static final ExtensionPointName<MyBeanClass> EP_NAME = ExtensionPointName.create("my.plugin.myExtensionPoint1");
public void useExtensions() {
for (MyBeanClass extension : EP_NAME.getExtensionList()) {
String key = extension.getKey();
String clazz = extension.getClass();
// ...
}
}
}
A gutter icon for the ExtensionPointName
declaration allows navigating to the corresponding <extensionPoint>
declaration in plugin.xml
.
Dynamic extension points
To support Dynamic Plugins (2020.1 and later), an extension point must adhere to specific usage rules:
- extensions are enumerated on every use and extensions instances are not stored anywhere
- alternatively, an
ExtensionPointChangeListener
can perform necessary updates of data structures (register viaExtensionPointName.addExtensionPointListener()
)
Extension points matching these conditions can then be marked as dynamic by adding dynamic="true"
in their declaration:
<extensionPoints>
<extensionPoint name="myDynamicExtensionPoint" beanClass="com.myplugin.MyBeanClass" dynamic="true" />
</extensionPoints>