Recently, when using a plugin of idea, it reports the NPE on the latest version and fail to work. Because the original author haven’t update the repo for a relative long time, we decide to fix this by ourselves.
Setup
In order to develop idea plugin, we first have to setup some environment. Here is the environment setting tutorial and following are some basic steps:
- Start IntelliJ IDEA.
- Configure the IntelliJ Platform Plugin SDK. (prefer to choose community version as SDK because we can have source code of community version to assist debug)
- Create a project for plugin development.
- Create the necessary source elements and write the source code.
- Run and debug your plugin.
- Prepare the plugin for publishing.
We come across some problems at step three because we are developing a plugin on the fork of other people’s repository and there is no option to choose plugin development project type when create project from existing source. So, on step three, we have to first create project then edit projectName.iml
like following as this answer said:
# change type from java_module to plugin_module
- type="JAVA_MODULE"
+ type="PLUGIN_MODULE"
Development
In the process of development, we come across some problems and we share here to help the future readers.
Examples: Debug Plugin NPE
In order to fix the problem, which resides in a not small code base (a plugin code and some idea source code), in a relative short time, the first thing is to understand how this plugin works and why it doesn’t work on newer version.
The first convenient tool, if exists, is the doc from plugin writer. It can give us a general idea of how his code works and help us reading source code.
The second tool is debugging. We can start the plugin from idea in debug mode. In this way, we can
- find the stack trace, in our cases, where NPE comes from
- follow the execution flow to understand the logic
By viewing the stack trace, we find the NPE is located in the source of idea when we create a file chooser dialog.
VirtualFile virtualFile =
FileChooser.chooseFile(descriptor, project, null);
public static VirtualFile chooseFile(@NotNull final FileChooserDescriptor descriptor,
@Nullable final Project project,
@Nullable final VirtualFile toSelect) {...}
Reading code more times, we understand that the NPE arises because the frame that dialog needed (only needed in newer version) disappeared (notice this conclusion can also get from running plugin in both old working version and newer NPE version, and compare the change.)
So the solution is either to make it not disappear, or choose another frame:
VirtualFile virtualFile =
FileChooser.chooseFile(descriptor, WindowManager.getInstance().findVisibleFrame(), project, null);
Here, we choose the idea’s largest frame to make sure it will still work in the future version.
// we get this frame by compare the init process of our file chooser dialog with idea the tip dialog
WindowManager.getInstance().findVisibleFrame()
In conclusion, in order to get familiar with many code and find the right way to do things, there exists some ways:
- debug and follow the execution to understand logic
- compare similar situation
Examples: Generate Getter/Setter
Then, we are going to implement a new feature in this plugin: generate getter and setter for a batch of model class.
When come across generation of getter and setter, we can recall that this a conenient method when using Intellij. So we think that there may be some public method/api also for pulgin to use.
So the question changes to how to find the needed api?
We first try to search the different terms like:
idea plugin openapi generate getter setter
idea plugin development getter setter generation
but found no useful resouces. Doesn’t want to give the road, we start to search in community edition code. And lucky enough, we found it like this link shows (thanks to the good naming convention of idea development team).
The following task is much easier:
- choose one of the utility function to generate getter/setter
- add the method abstraction
PsiMethod
to class abstractionPsiClass
PsiClass dist = dataSet.get(clsName);
...
PsiMethod getter = GenerateMembersUtil.generateGetterPrototype(field);
dist.add(getter);
Working example can be found here.
评论
发表评论