官方文档
https://www.jetbrains.org/intellij/sdk/docs/basics/persisting_state_of_components.html
Github
https://github.com/kungyutucheng/my_gradle_plugin
运行环境
macOS 10.14.5
IntelliJ idea 2019.2.4
1、PropertiesComponent
主要用于临时性的且不可漫游的的简单配置关系的存储,适用于application
级别和project
级别,该存储共享命名空间,所以有必要添加前缀进行区分,这一点我们在后文的project
级别的Demo中可以看到
1.1、application级别
效果
初始效果PropertiesComponentApplicationSetting
package com.kungyu.persisting.state.component;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
/**
* @author wengyongcheng
* @since 2020/3/17 9:22 上午
* application 级别的properties Component
*/
public class PropertiesComponentApplicationSetting implements Configurable {
private JTextField textField;
private JPanel mainPanel;
private static final String APPLICATION_KEY = "applicationKey";
public PropertiesComponentApplicationSetting() {
textField.setText(PropertiesComponent.getInstance().getValue(APPLICATION_KEY));
}
@Nls(capitalization = Nls.Capitalization.Title)
@Override
public String getDisplayName() {
return "Application Level Properties Component";
}
@Nullable
@Override
public JComponent createComponent() {
return mainPanel;
}
@Override
public boolean isModified() {
return !StringUtils.equals(textField.getText(),PropertiesComponent.getInstance().getValue(APPLICATION_KEY));
}
@Override
public void apply() throws ConfigurationException {
PropertiesComponent.getInstance().setValue(APPLICATION_KEY, textField.getText());
}
}
注册application级配置
<extensions defaultExtensionNs="com.intellij">
<applicationConfigurable instance="com.kungyu.persisting.state.component.PropertiesComponentApplicationSetting" dynamic="true"/>
</extensions>
1.2、project级别
效果
入口 项目untitled效果 项目untitled2效果package com.kungyu.persisting.state.component;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
/**
* @author wengyongcheng
* @since 2020/3/17 10:00 上午
* project 级别的 properties component
*/
public class PropertiesComponentProjectSetting implements Configurable {
private JTextField textField;
private JPanel mainPanel;
private Project project;
private static final String PROJECT_KEY = "projectKey";
public PropertiesComponentProjectSetting() {
Project [] projects = ProjectManager.getInstance().getOpenProjects();
this.project = projects.length > 0 ? projects[0] : ProjectManager.getInstance().getDefaultProject();
textField.setText(PropertiesComponent.getInstance(project).getValue(getKey())) ;
}
@Nls(capitalization = Nls.Capitalization.Title)
@Override
public String getDisplayName() {
return "Project Level Properties Component";
}
@Nullable
@Override
public JComponent createComponent() {
return mainPanel;
}
@Override
public boolean isModified() {
return !StringUtils.equals(textField.getText(), PropertiesComponent.getInstance(project).getValue(getKey()));
}
@Override
public void apply() throws ConfigurationException {
PropertiesComponent.getInstance(project).setValue(getKey(), textField.getText());
}
private String getKey() {
return this.project.getName() + "-" + PROJECT_KEY;
}
}
注意项目untitled和untitled2不能同时打开,否则配置的内容将展示为第一个打开的项目的配置内容,原因是下面的获取项目工程的代码中,我们使用的是getOpenProjects方法,该方法将按项目打开顺序返回项目数组,如果同时打开多个项目,此时该段代码将获取到同一个项目,那么内容自然展示的也是同一个项目的配置数据
Project [] projects = ProjectManager.getInstance().getOpenProjects();
this.project = projects.length > 0 ? projects[0] : ProjectManager.getInstance().getDefaultProject();
注册project级配置
<extensions defaultExtensionNs="com.intellij">
<projectConfigurable instance="com.kungyu.persisting.state.component.PropertiesComponentProjectSetting" dynamic="true"/>
</extensions>
2、PersistentStateComponent
该类提供了更为灵活的持久化存储,思路如下:
- 创建实现
PersistentStateComponent
接口的service
- 定义
State
类 - 使用
@State
注解指定存储位置
2.1、实现PersistentStateComponent接口
PersistentStateComponent
接口需要指定State
类作为泛型参数,该State
类可以是:
- 实现
PersistentStateComponent
接口的类本身 - 一个
Java bean
类
2.1.1 类本身
@State(...)
class MyService implements PersistentStateComponent<MyService> {
public String stateValue;
public MyService getState() {
return this;
}
public void loadState(MyService state) {
XmlSerializerUtil.copyBean(state, this);
}
}
2.1.2 Java Bean
@State(...)
class MyService implements PersistentStateComponent<MyService.State> {
static class State {
public String value;
}
State myState;
public State getState() {
return myState;
}
public void loadState(State state) {
myState = state;
}
}
2.2 实现State类
该State将会被转化为xml文档,它支持以下数据类型:
-
numbers
:包括基本类型和包装类型 booleans
strings
collections
maps
enums
对于其他数据类型,需要继承com.intellij.util.xmlb.Converter
:
class LocalDateTimeConverter extends Converter<LocalDateTime> {
public LocalDateTime fromString(String value) {
final long epochMilli = Long.parseLong(value);
final ZoneId zoneId = ZoneId.systemDefault();
return Instant.ofEpochMilli(epochMilli).atZone(zoneId).toLocalDateTime();
}
public String toString(LocalDateTime value) {
final ZoneId zoneId = ZoneId.systemDefault();
final long toEpochMilli = value.atZone(zoneId).toInstant().toEpochMilli();
return Long.toString(toEpochMilli);
}
}
而后需要加上注解@com.intellij.util.xmlb.annotations.OptionTag
或者@com.intellij.util.xmlb.annotations.Attribute
:
class State {
@OptionTag(converter = LocalDateTimeConverter.class)
public LocalDateTime dateTime;
}
如果某个字段不想要被持久化,可以使用@com.intellij.util.xmlb.annotations.Transient
注意:该State必须要用一个默认构造函数,用于返回
component
的默认状态
2.3 指定存储位置
@State
主要有以下几个属性:
-
name
:指定state的名字,并将作为xml文档的根标签 -
storges
:支持一个或者多个@com.intellij.openapi.components.Storage
注解来指定具体位置,对于project级别的项目,可以不指定,这种情况下会自动使用.ipr
文件替代 -
reloadable
:可选,如果设置为false
,那么当存储文件被外部修改(比如通过版本控制系统update)或者state有所改变的时候,整个项目都将reload
@Storage注解可以通过以下俩种方式简单指定:
-
@Storage("yourName.xml")
:如果是project级别的文件,无需指定,会自动使用.ipr
文件替代 @Storage(StoragePathMacros.WORKSPACE_FILE)
网友评论