IntelliJ Plugin Development introduction: PersistStateComponent

This post explains IntelliJ IDEA Plugin development.

The source code explained here is uploaded in official repository as a CLion plugin, please check Single File Execution Plugin on github.

Save value for IntelliJ Plugin

If your plugin want to keep some configuration value and you want to save the values in storage, PersistentStateComponent can be used in IntelliJ IDEA plugin development.

Ref

Make a class implments PersistentStateComponent

Create new Java class, and add implements PersistentStateComponent<T>.

Following hands on example, I will introduce easy quick implementation for this class. I made SingleFileExecutionConfig class which implements PersistentStateComponent<SingleFileExecutionConfig>. So the State type T is same with created class.

To implement this interface PersistentStateComponent<T>, we need to override

  • getState()
    called every time the settings are saved. If the state returned from getState() is different from the default state obtained by default constructor, the returned state is serialized in XML and stored.
  • loadState(T)
    called when the component has been created, and after the XML file with the persisted state is changed externally.

and it is nice to implement getInstance method.

For the implementation of these 3 methods, you don’t need to remember about above behavior. Just implement as following template. 

/**
 * PersistentStateComponent keeps project config values.
 */
@State(
 name="SingleFileExecutionConfig",
 storages = {
 @Storage("SingleFileExecutionConfig.xml")}
)
public class SingleFileExecutionConfig implements PersistentStateComponent<SingleFileExecutionConfig> {

    @Nullable
    @Override
    public SingleFileExecutionConfig getState() {
        return this;
    }

    @Override
    public void loadState(SingleFileExecutionConfig singleFileExecutionConfig) {
        XmlSerializerUtil.copyBean(singleFileExecutionConfig, this);
    }

    @Nullable
    public static SingleFileExecutionConfig getInstance(Project project) {
        return ServiceManager.getService(project, SingleFileExecutionConfig.class);
    }
}

Note that  for the getService method in getInstanceproject variable is necessary when your PersistentStateComponent is project level. If your service is application level, project instance is not necessary.

See 

@State annotation – specify the storage location to be saved

As you may notice, @State annotation is written at the top. This is to specify where the persisted values will be stored. For the fields,

  • name (required) – specifies the name of the state.
  • storages – specify the storage locations
    Example,
    @Storage("yourName.xml") If component is project-level
    @Storage(StoragePathMacros.WORKSPACE_FILE) for values stored in the workspace file.

See official doc’s “Defining the storage location” for more details.

After that, you can just declare variables which will be saved, and the Getter and Setter of these variables. For example, to declare one String variable executableName, add below code to this class.

    String executableName;

    public String getExecutableName() {
        return executableName;
    }

    public void setExecutableName(String executableName) {
        this.executableName = executableName;
    }

Declaring PersistentStateComponent in plugin.xml

To use this PersistentStateComponent, declaration in plugin.xml is necessary.

  <extensions defaultExtensionNs="com.intellij">
    ...
    <projectService serviceInterface="SingleFileExecutionConfig" serviceImplementation="SingleFileExecutionConfig"/>
  </extensions>

Using PersistentStateComponent from the other module

Let’s consider a case that you want to use created SingleFileExecutionConfig class from Configurable class (see IntelliJ Plugin Development introduction: ApplicationConfigurable, ProjectConfigurable for explanation of Configurable).

The instance can be obtained by calling getInstance method. For example,

    private final SingleFileExecutionConfig mConfig;

    @SuppressWarnings("FieldCanBeLocal")
    private final Project mProject;

    public SingleFileExecutionConfigurable(@NotNull Project project) {
        mProject = project;
        mConfig = SingleFileExecutionConfig.getInstance(project);
    }

To update the value, you can just directly update the field variable of this instance (mConfig). No explicit “save” method call is needed! The value is automatically saved when you get the value in next time.

Below code is an example for the variable updating part. this apply() method is called when user change the configuration in Settings dialog.

    public void apply() {
        mConfig.setExecutableName(exeNameTextField.getText());
        mConfig.notShowOverwriteConfirmDialog = notShowDialogCheckBox.isSelected();
    }

Check the source code for more detail.

Leave a Comment

Your email address will not be published. Required fields are marked *