Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 5 Next »

Persisting State of IntelliJ IDEA Components

IntelliJ IDEA provides an API that allows components or services to persist their state between restarts of IntelliJ IDEA. You can use either a simple API to persist a few values, or persist the state of more complicated components using the PersistentStateComponent interface.

Using PropertiesComponent for Simple Persistence

If the only thing that your plugin needs to persist is a few simple values, the easiest way to do so is to use the com.intellij.ide.util.PropertiesComponent service. It can be used for saving both application-level values and project-level values (stored in the worspace file).

Use PropertiesComponent.getInstance() for storing application-level values, and PropertiesComponent.getInstance(Project) fro storing project-level values.

Using PersistentStateComponent

The PersistentStateComponent interface gives you the most flexibility for defining the values to be persisted, their format and storage location. In order to use it, you should mark a service or a component as implementing the PersistentStateComponent interface, define the state class, and specify the storage location using the @State annotation.

Note that instances of extensions cannot persist their state by implementing PersistentStateComponent. If your extension needs to have persistent state, you need to define a separate service responsible for managing that state.

Implementing the PersistentStateComponent Interface

The implementation of PersistentStateComponent needs to be parameterized with the type of the state class. The state class can either be a separate JavaBean class, or the class implementing PersistentStateComponent itself.

In the former case, the instance of the state class is typically stored as a field in the PersistentStateComponent class:

In the latter case, you can use the following pattern to implement getState() and loadState() methods:

Implementing the State Class

The implementation of PersistentStateComponent works by serializing public fields and bean properties into an XML format. The following types of values can be persisted:

  • numbers (both primitive types, such as int, and boxed types, such as Integer);
  • booleans;
  • strings;
  • collections;
  • maps;
  • enums.

In order to exclude a public field or bean property from serialization, you can annotate the field or getter with the @Transient annotation.

Note that the state class must have a default constructor. It should return the default state of the component (one used if there is nothing persisted in the XML files yet).

Defining the Storage Location

In order to specify where exactly the persisted values are stored, you need to add a @State annotation to the PersistentStateComponent class. It has the following fields:

  • Name (required) - specifies the name of the state (name of root tag in XML)
  • One or more of @Storage annotations (required) - specify the storage locations for .ipr and directory-based projects
  • Roaming type (optional) - specifies whether the state is synchronized between different IDEA installations when the IDEA Server plugin is used
  • Reloadable (optional) - if set to false, complete project reload is required when the XML file is changed externally and the state has changed.

The simplest ways of specifying the @Storage annotation are as follows:

  • @Storage(id="other", file = "$APP_CONFIG$/other.xml") for application-level values
  • @Storage(id="other", file = "$PROJECT_FILE$") for values stored in the project file
  • @Storage(id="other", file = "$WORKSPACE_FILE$") for values stored in the workspace file

The "id" parameter of the @Storage annotation can be used to exclude specific fields from serialization in specific formats. If you do not need to exclude anything, you can set the id to an arbitrary string value.

By specifying a different value for the file parameter, you can cause the state to be persisted in a different file.

If you need to customize where the values are stored when the directory-based project format is used, you need to add the second @Storage annotation with the scheme parameter set to StorageScheme.DIRECTORY_BASED, for example:

Customizing the XML Format of Persisted Values

If the state that you need to serialize doesn't map cleanly to a JavaBean, you can use org.jdom.Element as the state class. In that case, you can use getState() to build an XML element with an arbitrary structure, which will then be saved directly in the state XML file. In the loadState() method, you can deserialize the JDOM element tree using any custom logic.

If you want to use the default bean serialization but need to customize the storage format in XML (for example, for compatibility with previous versions of your plugin or externally defined XML formats), you can use the @Tag, @Attribute, @Property, @MapAnnotation, @AbstractCollection annotations for that. You can look at the source code (com.intellij.util.xmlb package) to get more information about the meaning of these annotations.

Persistent Component Lifecycle

The loadState() method is called after the component has been created (only if there is some non-default state persisted for the component), and after the XML file with the persisted state is changed externally (for example, if the project file was updated from the version control system). In the latter case, the component is responsible for updating the UI and other related components according to the changed state.

The getState() method is called every time the settings are saved (for example, on frame deactivation or when closing the IDE). If the state returned from getState() is equal to the default state (obtained by creating the state class with a default constructor), nothing is persisted in the XML. Otherwise, the returned state is serialized in XML and stored.

Legacy API (JDOMExternalizable)

move the information here

  • No labels