IntelliJ IDEA Plugin Structure

Skip to end of metadata
Go to start of metadata

This document is a work in progress.

Plugins are the only supported way to extend IDEA functionality. A plugin uses API exposed by IDEA or other plugins to implement its functionality. This document is focused on the plugin system structure and plugin lifecycle. It doesn't specify any other APIs that may be used by plugins.
The following subjects are covered:

Plugin Content

There are 3 ways how to organize plugin content:

1. A plugin consists of one .jar file placed in the plugins directory. The archive should contain the configuration file (META-INF/plugin.xml) and classes that implement the plugin functionality. The configuration file specifies the plugin name, description, version, vendor, the supported IDEA version, plugin components, actions and action groups, action user interface placement.

2. Plugin files are located in a folder:

The 'classes' folder and all jars located in the 'lib' folder are automatically added to the classpath.

3. Plugin files are located in a jar-file that is placed to the lib folder:

All the jars from the 'lib' folder are automatically added to the classpath.

Plugin Class Loaders

To load classes of each plugin, IDEA uses a separate class loader. This allows each plugin to use a different version of a library, even if the same library is used by IDEA itself or by another plugin.

By default, the main IDEA class loader loads classes that were not found in the plugin class loader. However, in the plugin.xml file, one can use the <depends> element to specify that a plugin depends on one or more other plugins. In this case, the class loaders of those plugins will be used for classes not found in the current plugin. This allows a plugin to reference classes from other plugins.

Plugin Components

Components are the fundamental concept of plugins integration. There are three kinds of components: application-level, project-level and module-level.

Application-level components are created and initialized on IDEA start-up. They can be acquired from the Application instance with the getComponent(Class) method.

Project-level components are created for each Project instance in IDEA (please note that components might be created for even unopened projects). They can be acquired from the Project instance with the getComponent(Class) method.

Module-level components are created for each Module in every project loaded in IDEA. Module-level component can be acquired from Module instance with the same method.

Every component should have interface and implementation classes specified in the configuration file. The interface class will be used for retrieving the component from other components and the implementation class will be used for component instantiation. Note that two components of the same level (Application, Project or Module) cannot have the same interface class. Interface and implementation classes can be the same.

Each component has the unique name which is used for its externalization and other internal needs. The name of a component is returned by its getComponentName() method.

Components Naming Notation

It's recommended to name components in <plugin_name>.<component_name> form.

Application Level Components

Optionally, application-level component's implementation class may implement the ApplicationComponent interface. An application component that has no dependencies should have a constructor with no parameters which will be used for its instantiation. If an application component depends on other application components, it can specify these components as constructor parameters, and IDEA will ensure that the components are instantiated in correct order to satisfy the dependencies.
Note that application-level components must be registered in the <application-components> section of the plugin.xml file (see Plugin Configuration File below).

Quick creation of application components

IntelliJ IDEA suggests a simplified way of creating application components, with all the required infrastructure. The IDEA interface will help you declare the application component's implementation class and automatically makes appropriate changes to the <application-components> section of the plugin.xml file.

To create and register an application component

  1. In your project, on the context menu of the destination package click New or press ALT + INSERT.
  2. On the New menu, click Application Component.
  3. In the New Application Component dialog box that opens, enter the application component name, and then click OK.

IntelliJ IDEA generates a new Java class that implements the ApplicationComponent interface, registers the newly created component in the plugin.xml file, adds a node to the module tree view, and opens the created application component class file in the editor.

Project Level Components

Project-level component's implementation class may implement the ProjectComponent interface. The constructor of a project-level component can have a parameter of the Project type, if it needs the project instance. It can also specify other application-level or project-level components as parameters, if it depends on those components.

Note that project-level components must be registered in the <project-components> section of the plugin.xml file (see Plugin Configuration File below).

Quick creation of project components

IntelliJ IDEA suggests a simplified way of creating project components, with all the required infrastructure. The IDEA interface will help you declare the project component's implementation class and automatically makes appropriate changes to the <project-components> section of the plugin.xml file.

To create and register a project component

  1. In your project, on the context menu of the destination package click New or press ALT + INSERT.
  2. On the New menu, click Project Component.
  3. In the New Project Component dialog box that opens, enter the project component name, and then click OK.

IntelliJ IDEA generates a new Java class that implements the ProjectComponent interface, registers the newly created component in the plugin.xml file, adds a node to the module tree view, and opens the created application component class file in the editor.

Module Level Components

Optionally, Module-level component's implementation class may implement the ModuleComponent interface. The constructor of a module-level component can have a parameter of the Module type, if it needs the module instance. It can also specify other application-level, project-level or module-level components as parameters, if it depends on those components.

Note that module-level components must be registered in the <module-components> section of the plugin.xml file (see Plugin Configuration File below).

Quick creation of module components

IntelliJ IDEA suggests a simplified way of creating module components, with all the required infrastructure. The IDEA interface will help you declare the module component's implementation class and automatically makes appropriate changes to the <module-components> section of the plugin.xml file.

To create and register a module component

  1. In your project, on the context menu of the destination package click New or press ALT + INSERT.
  2. On the New menu, click Module Component.
  3. In the New Module Component dialog box that opens, enter the module component name, and then click OK.

IntelliJ IDEA generates a new Java class that implements the ModuleComponent interface, registers the newly created component in the plugin.xml file, adds a node to the module tree view, and opens the created application component class file in the editor.

Persisting State of Components

The state of every component will be automatically saved and loaded if the component's class implements the JDOMExternalizable (deprecated) or PersistentStateComponent interface.

When the component's class implements the PersistentStateComponent interface, the component state is saved in an XML file that you can specify using the @State and @Storage annotations in your Java code.

When the component's class implements the JDOMExternalizable interface, the components save their state in the following files:

  • Project-level components save their state to the project (.ipr) file. However, if the workspace option in the plugin.xml file is set to true, the component saves its configuration to the workspace (.iws) file instead.
  • Module-level components save their state to the module (.iml) file.

For more information and samples, refer to Persisting State of Components.

Defaults

Defaults (components' predefined settings) should be placed in the <component_name>.xml file. Put this file in the plugin's classpath in the folder corresponding to the default package. The readExternal() method will be called on the <component> root tag. If a component has defaults, the readExternal() method is called twice: the first time for defaults and the second time for saved configuration.

Plugin Components Lifecycle

The components are loaded in the following order:

  • Creation - constructor is invoked.
  • Initialization - the initComponent method is invoked (if the component implements the ApplicationComponent interface).
  • Configuration - the readExternal method is invoked (if the component implements JDOMExternalizable interface), or the loadState method is invoked (if the component implements PersistentStateComponent and has non-default persisted state).
  • For module components, the moduleAdded method of the ModuleComponent interface is invoked to notify that a module has been added to the project.
  • For project components, the projectOpened method of the ProjectComponent interface is invoked to notify that a project has been loaded.

The components are unloaded in the following order:

  • Saving configuration - the writeExternal method is invoked (if the component implements the JDOMExternalizable interface), or the getState method is invoked (if the component implements PersistentStateComponent).
  • Disposal - the disposeComponent method is invoked.

Note that you should not request any other components using the getComponent( method in the constructor of your component, otherwise you'll get an assertion. If you need access to other components when initializing your component, you can specify them as constructor parameters or access them in the initComponent method.

Sample Plugin

A sample plugin that illustrates how to create a plugin with the application level and project level components is available in the <%IDEA project directory%>/community/samples/plugin directory.

To open sample plugin

  • Run IntelliJ IDEA and open the <%IDEA project directory%>/community/samples/plugin/plugin.ipr file.

Plugin Extensions and Extension Points

Intellij IDEA provides the concept of extensions and extension points that allows a plugin to interact with other plugins or with the IDEA core.

Extension Points

If you want your plugin to allow other plugins to extend its functionality, in the plugin, you must declare one or several extension points. Each extension point defines a class or an interface that is allowed to access this point.

Extensions

If you want your plugin to extend the functionality of other plugins or the IDEA core, in the plugin, you must declare one or several extensions.

How to Declare Extensions and 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 an extension point

  • In the <extensionPoints> section, 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.

To clarify this procedure, consider the following sample section of the plugin.xml file:

The interface attribute sets an interface the plugin that contributes to the extension point must implement.

The beanClass attribute sets a bean class that specifies one or several properties annotated with the "@Attribute" annotation. The plugin that contributes to the extension point will read those properties from the plugin.xml file. To clarify this, consider the following sample MyBeanClass1 bean class used in the above plugin.xml file:

Note that to declare an extension designed to access the MyExtensionPoint1 extension point, your plugin.xml file must contain the <MyExtensionPoint1> tag with the "key" and "implementationClass" attributes set to appropriate values (see the sample plugin.xml file below).

To declare an extension

  1. For the <extensions> element, set the xmlns (deprecated) or defaultExtensionNs attribute to one of the following values:
    • "com.intellij", if your plugin extends the IDEA core functionality.
    • <ID of a plugin>, if your plugin extends a functionality of another plugin.
  2. Add a new child element to the <extensions> element.
    The child element name must match the name of the extension point you want the extension to access.
  3. Depending on the type of the extension point, do one of the following:
    • If the extension point was declared using the interface attribute, for newly added child element, set the implementation attribute to the name of the class that implements the specified interface.
    • If the extension point was declared using the beanClass attribute, for newly added child element, set all attributes annotated with the "@Attribute" annotations in the specified bean class.

To clarify this procedure, consider the following sample section of the plugin.xml file that defines two extensions designed to access the appStarter and applicationConfigurable extension points in the IDEA core and one extension to access the MyExtensionPoint1 extension point in a test plugin:

How to Get the Extension Points List?

To get a list of extension points available in the IntelliJ IDEA core, consult the <extensionPoints> section of the following XML configuration files:

Additional Information and Samples

For samples plugins and detailed instructions on how to create your plugin that contributes to the IDEA core, refer to Customizing the IDEA Settings Dialog and Creation of Tool Windows.

Plugin Actions

Intellij IDEA provides the concept of actions. An action is a class, derived from the AnAction class, whose actionPerformed method is called when the menu item or toolbar button is selected. The system of actions allows plugins to add their own items to IDEA menus and toolbars.
Actions are organized into groups, which, in turn, can contain other groups. A group of actions can form a toolbar or a menu. Subgroups of the group can form submenus of the menu.
You can find detailed information on how to create and register your actions in IntelliJ IDEA Action System and in Creating an Action .

Plugin Services

IntelliJ IDEA provides the concept of services. A service is a plugin component loaded on demand, when your plugin calls the getService method of the ServiceManager class. IntelliJ IDEA ensures that only one instance of a service is loaded even though the service is called several times. A service must have the interface and implementation classes specified in the plugin.xml file.
The service implementation class is used for service instantiation.
IntelliJ IDEA offers three types of services: application level services, project level services and module level services.

How to Declare a Service?

To declare a service, you can use the following extension points in the IDEA core:

  • applicationService: designed to declare an application level service.
  • projectService: designed to declare a project level service.
  • moduleService: designed to declare a module level service.

To declare a service

  1. Add the appropriate child element (<applicationService>, <projectService> or <moduleService>) to the <extensions> section of the plugin.xml file.
  2. For the newly added child element, set the following attributes:
    • serviceInterface: specifies the service interface class.
    • serviceImplementation: specifies the service implementation class.

Note that the interface and implementation classes can be the same.

To clarify the service declaration procedure, consider the following fragment of the plugin.xml file:

How It Works?

To instantiate your service, in Java code, use the following syntax:

Sample Plugin

This section allows you to download and install a sample plugin illustrating how to create and use a plugin service.
This plugin has a project component implementing a service that counts a number of currently opened projects in IntelliJ IDEA. If this number exceeds the maximum allowed number of simultaneously opened projects, the plugin returns an error
message and closes the most recently opened project.

To install and run the sample plugin

  1. Click here to download the .Zip archive that contains the sample plugin project.
  2. Extract all files from the .Zip archive to a separate folder.
  3. Start IntelliJ IDEA, on the starting page, click Open Project, and then use the Open Project dialog box to open the downloaded project MaxOpenedProjects.
  4. On the main menu, choose Run | Run or press Shift + F10.
  5. If necessary, change the Run/Debug Configurations .

Plugin Configuration File (plugin.xml)

The following is a sample plugin configuration file. This sample showcases and describes all elements that can be used in the plugin.xml file.

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Sep 15, 2012

    Link to download zip is broken.. links instead to a Warning.html  page of some kind . HTH

    1. Nov 05, 2012

      Thanks, link has been fixed.

  2. Nov 04, 2012

    Please explain difference between component and service.

    1. Nov 05, 2012

  3. Aug 04, 2014

    I believe that "Plugin Services > How It Works?"
    should read
       MyServiceInterfaceClass service = (MyServiceInterfaceClass) ServiceManager.getService(MyServiceInterfaceClass.class);
    instead of
       MyServiceImplClass service = ServiceManager.getService(MyServiceImplClass.class);

    1) it makes more sense to request a service by interface and hide implementation details from clients of the API

    2) implementation class does not work in my experiments, but interface does