eclipse 插件教程
不幸的是,第一次在Eclipse中进行操作会非常耗时且令人沮丧。 Eclipse框架非常庞大,强大,有时甚至很复杂。 可能很难弄清楚哪些功能可用以及如何使用它们。
本教程介绍了自动化简单的Java重构任务所需的所有eclipse功能的基础。 它显示了如何在菜单中添加新项目以及如何分析,修改和格式化Java源代码。 它还显示了如何使用对话框与用户进行交流。
它分为两个部分。 这篇文章解释了所有需要的理论。 在本部分的最后,您将已经对Eclipse框架有了足够的了解,只需稍加搜索即可完成该插件。 实际上,我们将创建一个插件,该插件将新项目添加到菜单中并收集执行重构所需的所有信息。
本教程的下一部分将展示如何创建对话框以及如何从插件修改Java源代码。 它尚未发布。
样本插件
我们创建具有两个功能的示例插件:
- 检查非空参数–修改所选方法以检查其参数是否不为
null
, - 自定义生成toString –将
toString
方法添加到选定的类。
这两个功能都将在源菜单中添加一个新项。 仅当用户选择Java方法时,“检查非空参数”项才会启用。 该功能显示一个对话框,允许用户选择方法参数的子集。 然后修改选定的方法以检查选定的参数是否为空:
if (arg1==null || arg2==null || ... || argn==null)throw new IllegalStateException("The parameter may not be null.");
仅当用户选择一个Java类时,才会启用Custom generate toString项目。 它将显示一个对话框及其所有属性的列表。 用户选择属于toString方法的属性。 如果用户选择的属性少于四个,则此功能将以下代码添加到类中:
@Override
public String toString() {StringBuilder builder = new StringBuilder(this.getClass().getSimpleName());builder.append(" [ ");builder.append(b).append(", ").append(c).append(" ]");return builder.toString();
}
如果用户选择了更多或更少的四个属性,则该功能将以下代码添加到类中:
public String toString() {StringBuilder builder = new StringBuilder(this.getClass().getSimpleName());builder.append(" [ \n");builder.append(" a" + ": ").append(a).append("\n");builder.append(" b" + ": ").append(b).append("\n");builder.append(" c" + ": ").append(c).append("\n");builder.append(" d" + ": ").append(d).append("\n");builder.append(" ]");return builder.toString();
}
就这些。 该插件在Github上可用。
每个Eclipse版本都有多种风格。 最适合插件编写者的版本称为“ Eclipse for RCP and RAP Developers”。 RCP代表“富客户端平台”,它只是Eclipse平台的另一个名称。
从下载页面下载并安装“用于RCP和RAP开发人员的Eclipse”。
首先要做的是配置目标平台。 目标平台是eclipse的另一个实例。 它表示您的插件将使用的最低配置。 您的插件将针对目标平台进行编译。 它还将安装到其中并在您要对其进行测试时在其中运行。
整个工作空间只能有一个活动目标平台。 尽管这样做更有意义,但它不是特定于项目的。
最简单的方法是开发与运行时相同的Eclipse版本。 这是默认选项。 在这种情况下,您要做的就是向其中添加eclipse SDK。
安装Eclipse SDK:
- 转到“帮助”->“安装新软件...”。
- 选择您的Eclipse更新站点,在本例中为“ Eclipse项目更新”
http://download.eclipse.org/eclipse/updates/3.
更新网站。 - 检查Eclipse SDK和Eclipse Platform SDK。
- 单击下一步,接受许可并完成安装。
这就对了。 不需要任何其他操作,您就可以创建第一个插件项目了 。
可以单独下载和维护目标平台。 如果要与较早的版本兼容,或者要对目标平台配置有更大的控制权,请使用此选项。
如果您不感兴趣,请跳到下一章。
查找并下载您认为用户将拥有的任何内容的SDK。 如果找不到SDK,也可以使用“常规”版本。 但是,如果下载SDK,则将提供源代码和javadocs。
例如,我们的插件需要Eclipse Indigo版本。 Eclipse Indigo的版本号是3.7,因此我们必须下载Eclipse 3.7 SDK 。 归档发行版页面上提供了更早版本的Eclipse SDK的完整列表。
我们的插件将仅依赖于eclipse本身,因此我们要做的就是在某个地方解压缩下载的SDK。 如果需要其他插件,我们也必须搜索并下载其SDK。 我们还将解压缩它们并复制到与Eclipse SDK相同的目录中。
现在,我们必须配置RCP Eclipse以使用准备好的目标平台。
定义并激活目标平台:
- 转到“窗口”->“首选项”->“插件开发”->“目标平台”。
- 单击添加。
- 选择“无:从空目标定义开始”,然后单击下一步。
- 填写目标名称。
- 单击添加,选择目录,浏览至解压缩的Eclipse SDK并完成。
- 将新的目标平台检查为“有效”。
最后,转到“插件开发”首选项页面,然后选中“在Java搜索中包括来自目标的所有插件”。
本章介绍如何创建一个简单的插件项目以及如何对其进行调试。 简单的插件没有任何用处。 它只能显示一条消息以证明其存在。
在本章的最后,我们将删除示例消息,最后得到一个空的插件框架。
我们将使用Eclipse向导来生成插件。 从包资源管理器中调用向导:
- 右键点击包浏览器,
- 选择“新建”->“其他..”。
- 选择“插件项目”,然后单击“下一步”。
该向导有多个页面。 在第一个上配置项目名称和目标平台。 您可以根据需要使用任何项目名称,但是习惯上是以根java软件包命名该项目。 例如,由于我们要将所有类都放入org.meri.eclipse.defensiveapitools
包中,因此我们的项目名称为org.meri.eclipse.defensiveapitools
目标平台字段包含您要开发的Eclipse版本。 如果有人要使用您的插件,则将要求他下载数量相等或更大的Eclipse。 一个旧的不兼容的Eclipse将拒绝加载它。 我们可以为当前的Eclipse开发很好,所以我们选择3.7。
点击下一步'。
第二页包含基本项目信息。 随意填写ID,插件版本,名称和提供程序。 第一个重要参数是执行环境。 该插件将仅在指定的Java上运行,或者永远不在Java上运行。 在较早的JVM上运行的Eclipse只会忽略它。 我们选择了J2SE-1.6。
验证:
- 复选框“ Generate a activator,Java…”被选中,
- 复选框“此插件将为用户界面做出贡献”已选中,
- “是否要创建富客户端平台应用程序”的答案是否定的。
点击下一步'。
选择“ Hello,World Command”模板,然后单击“ Finish”。 这将创建带有示例菜单项的新插件。
该插件仅在正在运行的Eclipse中起作用。 Eclipse支持手动和自动JUnit测试。 在这两种情况下,都将在第一章中配置的目标平台内安装并运行该插件。
本章仅显示如何进行手动测试。 请参考其他资源,以学习如何为eclipse插件编写junit测试。
安装并运行插件:
- 右键点击插件项目,
- 单击“调试为”->“ Eclipse应用程序”。
系统将启动新的Eclipse实例。 它的主菜单有一个新条目,称为“样本菜单”。
现在,您有两个正在运行的Eclipse实例。 一个用于开发,另一个用于测试。 日蚀在开发人员内部运行。 所有调试工具均可用。 您可以放置断点,检查变量等:
- 在开发蚀中打开生成的
SampleHandler
类, - 将断点放在
execute
方法中, - 回到Eclipse,
- 选择“示例菜单”和“示例命令”
执行将在新的断点处停止。
我们已经看到该插件有效,因此我们可以从中删除生成的示例菜单。
删除示例菜单项及其处理程序:
- 打开plugin.xml文件,转到扩展选项卡并删除所有扩展。
- 找到并删除生成的
SampleHandler
类。
plugin.xml内的plugin
标签现在应该为空。 打开plugin.xml文件,然后转到plugin.xml选项卡:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
</plugin>
Eclipse是一个巨大的框架,您可以在其中安装无限数量的插件。 这创建了一个庞大的功能和插件系统,它们必须相互配合。 为了使该系统保持解耦和尽可能扩展,Eclipse框架使用适配器设计模式 。 这种模式非常普遍,无论您要编写哪种插件,您都可能会遇到它。
此设计模式将一个类或接口转换为另一个类或接口。 执行转换的类称为适配器。 该模式具有两种不同的风格,并且eclipse框架都支持。 两种风格之间的区别在于谁创建了适配器。 它可以直接由要转换的对象完成,也可以由独立的适配器工厂完成。
第一个子章节显示了如何编写适配器。 第二个子章节是关于能够创建自己的适配器的对象,第三个子章节是关于独立适配器工厂的。 最后一个子章节将所有内容放在一起,并说明如何转换未知类型的对象。
适配器是将一种类型转换为另一种类型的对象。 它必须表示其他类型,例如,如果将对象转换为类,则必须扩展该类。 如果将它们转换为接口,则必须实现该接口。
通常,适配器会转换具有所有必需功能但没有正确API的对象。 否则,典型的适配器包含很少的逻辑。 它只包装原始对象并将所有工作委托给它。
以下适配器能够将Minus
接口的实现转换为Plus
接口:
public class MinusToPlusAdapter implements Plus {private final Minus adaptee;public MinusToPlusAdapter(Minus minus) {super();this.adaptee = minus;}@Overridepublic int plus(int x, int y) {return adaptee.minus(x, -y);}}
在此设计模式的简单版本中,要转换的对象创建了自己的适配器。
我们将展示如何创建与Eclipse框架兼容的适应性对象。 该子章节的其余部分列出了此适配器样式风格的优点和缺点。
自适应对象必须实现IAdaptable
接口。 该接口只有一个方法getAdapter(Class type)
。 它返回一个适配器到请求的类型,或者返回null
。
适应对象:
public class MinusImpl implements Minus, IAdaptable {public int minus(int x, int y) {return x - y;}public Object getAdapter(Class type) {if (Plus.class.equals(type))return new MinusToPlusAdapter(this);return null;}}
getAdapter
方法可能会也可能不会调用全局适配器管理器来创建适配器。 一些Eclipse对象调用它,有些则没有。
自适应对象易于使用和调试。 该模式有助于保持类和接口层次结构的整洁。 它还提供了转换类型和所需类型之间的一些解耦。
在以下情况下使用它:
- 转换类型已经实现了太多接口。
- 转换后的类型必须与两个不同的特性兼容,并且每个特性都要求它扩展另一个类。
- 您希望将转换后的类型和所需的接口/类分开。
- 适配器需要访问方法的私有字段。
仅依赖于此模式版本的插件是不可扩展的。 第三方插件将无法向其中添加新的适配器。
此模式的第二个版本使用独立的工厂来创建适配器。
我们将展示如何在eclipse框架内调用适配器工厂。 该子章节的其余部分列出了此适配器样式风格的优点和缺点。
适配器由适配器工厂创建。 为了实现它们的独立性,适配器工厂被隐藏在全局适配器管理器的后面。 客户端代码从不直接与适配器工厂通信。
适配器管理器公开一个getAdapter(Object obj, Class type)
方法,该方法将调用委派给已安装的适配器工厂。 此方法返回适配器或null
。
使用适配器管理器创建适配器:
(Plus) Platform.getAdapterManager().getAdapter(minus, Plus.class);
适配器工厂可以通过编程方式或在plugin.xml中注册到适配器管理器中。 由于我们的插件不需要执行此操作,因此我们将忽略该信息。 阅读eclipse corner文章或Eclipse Adapters教程以获取更多信息。
注意:不允许适配器工厂调用已转换对象的getAdapter(Class type)
方法。 这将导致无限循环,因为可适配对象的getAdapter
方法可能会调用适配器管理器。
适配器工厂导致高度的去耦和可扩展性。 原始对象和所需类型的分离是绝对的。 它们之间没有依赖性。 而是,独立的适配器工厂取决于这两者。
向适配器管理器询问适配器可以使您的功能扩展。 任何人都可以贡献适配器以将其对象与您的插件集成。
使用它来:
- 使您的插件可由第三方插件编写者扩展,
- 集成两个插件。
去耦具有更高的复杂度。 如果出现问题,可能很难找出故障适配器的来源。 同样,与使用该模式的“可适配对象”版本相比,找出可用的适配器耗时更多。
如果您希望其他人扩展您的插件,请记录需要哪些适配器。 还要记录您要添加到系统中的适配器工厂。 在xml文件中查找所有这些信息可能非常耗时。
使对象适应所需接口的最正确方法不假设对象使用的适配器模式版本。
请遵循三个步骤以使对象适应所需的接口或类:
- 如果对象实现或扩展了所需的接口,请使用该对象。
- 如果对象可以自适应,请使用对象提供的适配器。
- 使用全局适配器管理器来适配对象。
使对象适应类型的完整实现:
public static Object getAdapter(Object obj, Class type) {// if the object implements or extends the desired interface, use itif (type.isInstance(obj))return obj;// if the object is able to adapt itself, let it do itif (obj instanceof IAdaptable) {IAdaptable adaptable = (IAdaptable) obj;Object adapter = adaptable.getAdapter(type);if (adapter != null)return adapter;}// delegate to the global adapter managerreturn Platform.getAdapterManager().getAdapter(obj, type);
}
Eclipse框架使用两个不同的层次结构来表示Java源代码。 第一个称为Java模型,第二个称为抽象语法树。 这些层次结构大多数是独立的,具有不同的用途和用法。
Java模型层次结构是轻量级的,容错的,快速重建的,并且其功能受到限制。 抽象语法树提供了对Java源代码的完全控制,但是重新创建的速度慢得多。 由于这些原因,Eclipse框架尽可能使用Java模型层次结构。 仅在必要时才使用抽象语法树。
第一个子章节显示了如何在插件中启用这些层次结构。 第二个子章节包含Java模型的概述,最后一个包含抽象语法树的概述。
这两个层次结构都属于org.eclipse.jdt.core
插件。 如果要使用它们,我们必须将jdt core插件添加到插件依赖项中:
- 打开plugin.xml并转到“依赖关系”标签。
- 单击“必需的插件”部分中的“添加”按钮。
- 选择
org.eclipse.jdt.core
插件。
Eclipse将自动将插件依赖项添加到MANIFEST.MF
文件的Require-Bundle
部分。
Java模型是一组表示Java方法,类,接口和其他元素的接口。 它是轻量级的,容错的并且可以快速重新创建。
Java模型层次结构提供有关Java代码结构的基本信息。 它也可以对其进行简单的更改。 例如,可以使用它来重命名或添加新的方法,类或接口。
Java模型层次结构的主要缺点是它不包含有关基础源代码的完整信息。 例如,它不包含方法主体。 结果,不可能执行更复杂的源代码更改。
Java模型层次结构的根是IJavaElement
接口。 扩展它的所有接口都属于此层次结构。
抽象语法树是代表Java方法,类,接口和其他元素的一组类。 它提供了有关Java代码结构的完整信息,并且能够对其进行任何更改。
抽象语法树层次结构的主要缺点是重新创建的速度比Java模型慢。 它的容错能力也较差。
抽象语法层次结构的根是ASTNode
类。 扩展它的所有类都属于此层次结构。
本章包含Eclipse用户界面的快速概述。 在本文的后面,我们将只解释UI那些部分的绝对基础。
第一个子章节是有关Eclipse UI最突出的部分:视图和编辑器。 第二小节介绍选择服务。
Eclipse用户界面的两个最重要的可视组件是视图和编辑器。 编辑器和视图都可以显示任何内容并以任何形式呈现。 两者都可以是可编辑的或只读的,但是只有编辑器才能将内容保持在未保存的脏状态。
编辑器和视图都称为零件。 Eclipse文档使用单词part作为“编辑器或视图”的快捷方式。
每个部分必须具有唯一的ID。 从技术上讲,id是任意字符串。 但是,所有官方插件都遵循的约定是在ID前面加上插件名称。 由于插件名称通常等于插件根软件包的名称,因此约定可以保证ID的唯一性。
每个部分都必须实现IWorkbenchPart
接口。 该接口被扩展了两次,分别导致了IWorkbenchPart2
和IWorkbenchPart3
接口。 您可以直接实现它们,也可以扩展名为WorkbenchPart
的默认实现。
所有零件均适用 。 IWorkbenchPart
接口扩展了IAdaptable
接口。 默认实现将getAdapter
方法委托给全局适配器管理器。
编辑器通常用于编辑或浏览文档或输入对象。 在编辑器中所做的更改不会立即存储。 内容已更改的编辑器处于脏状态,直到调用保存操作。 如果关闭编辑器而不保存,则所有未保存的更改都将丢失。 它的默认实现称为EditorPart
。
所有编辑器都显示在页面的同一区域中,无法最小化。 可能有多个相同类型的编辑器实例。
编辑器工具栏与全局工具栏一起显示,其菜单似乎是主菜单的一部分。
使用IEditorInput
接口的实例标识由编辑器编辑的文档或输入对象。
视图通常用于导航信息层次结构,打开编辑器或显示在活动编辑器中打开的事物的其他信息。 在视图中所做的修改将立即保存。 它的默认实现称为ViewPart
。
视图可以移动到页面的任何部分,并且可以最小化。 每个工作台页面通常只有一个给定视图的实例。
每个视图都有其自己的本地工具栏和菜单。 还允许他们将按钮添加到全局工具栏,并将菜单项添加到主菜单。
Eclipse选择系统是相当标准的。 每个视图和编辑器都会生成自己的选择。 该框架还有一个全局选择。 它通常包含活动部分的选择。
如果插件需要知道选定的对象,无论它们来自何处,都必须使用全局选择。 如果插件只希望将自己与少量视图和编辑器集成在一起,则它可能仅听取他们的选择。
本章介绍选择后如何解释。 Eclipse角落的文章描述了如何获取当前选择。
当前选择始终实现ISelection
接口。 该界面极其简约。 它的唯一方法是能够判断选择是否为空。
要获取更多详细信息,您必须将其转换为其子类型之一。 我们的插件有两个有趣的子类型:
-
ITextSelection
–有关所选文本的信息。 如果未选择任何文本,则包含光标位置。 -
IStructuredSelection
–包含选定对象的列表。
结构化选择可以包含任何类型的对象。 将它们转换为所需类或接口的最佳方法是使用适配器模式 。 简单的instanceof
和cast可能还不够。 蚀食的物体通常适用于多种类型,但是它们仅实现或扩展了其中的一些类型。
Eclipse菜单系统异常丰富且复杂。 至少有五种菜单类型。 外观相同或相似的菜单可以通过多种方式调用。 为了使它更加有趣,Eclipse具有两个不同的框架,它们能够将新项目添加到所有这些菜单中。
每个Eclipse菜单框架都有其自己的章节,而这两个章节都紧随其后。 本章仅包含各种菜单类型的概述,插件添加菜单项的概述以及这两个菜单框架的概述。
Eclipse有五种菜单类型:
- 上下文菜单–鼠标右键单击调用的菜单。 有时也称为弹出菜单。
- 主菜单–菜单始终在GUI顶部可见。
- 主工具栏–主菜单下始终可见的工具栏。
- 视图菜单–视图中可用的菜单。 单击视图中的白色向下箭头以调用它。
- 视图工具栏–大多数视图中都提供一个小工具栏。
与视图不同,编辑器没有自己的菜单或工具栏。 它们始终有助于主菜单或主工具栏。
“源”菜单包含“组织导入”或“生成委托方法...”之类的项目,并且这对我们的两个功能而言是合乎逻辑的。 它是由Java开发工具插件(JDT)贡献的。
该菜单位于主菜单或上下文菜单中。 这两个位置仅在某些情况下显示它。
仅在活动视图或编辑器支持的情况下,主菜单才包含源菜单项。 以下列表包含导致出现源菜单的视图和编辑器示例。 激活其中任何一个以在主菜单中查看它:
- Java编辑器
- 类型层次结构视图,
- 包浏览器视图,
- 项目资源管理器视图。
如果至少一个选定的项目代表Java文件,类,包方法或其他Java项目,则上下文菜单包含源菜单项目。 当然,这包括Java源代码编辑器中的文本选择。 使用源子菜单激活上下文菜单:
- 在编辑器中打开Java源文件,然后在内部右键单击,
- 在包资源管理器中选择Java文件或类,然后单击鼠标右键。
也可以使用快捷方式“ Alt + Shift + S”来调用源菜单。
Eclipse有两个不同的框架,它们可以将新项目添加到菜单中:
- 行动框架,
- 命令框架。
操作框架较旧且已过时。 命令框架是更新,灵活的,并且有点复杂。 它是优越的,应该用于任何新功能。
该命令框架与大多数菜单兼容,但并非与所有菜单兼容。 某些菜单尚未被重写,因此您必须使用动作框架对其进行贡献。 例如,主菜单中的源子菜单仅与动作框架兼容。
某些菜单与两个框架都不兼容。 快捷键CTRLS + ALT + S调用的源菜单就是这样的菜单。 无法为之作出贡献。
注意:不可能对菜单有所贡献。
命令框架能够将项目添加到大多数Eclipse菜单中。 它被设计为迷你模型视图控制器,并将UI与要执行的动作分开。
本章包含命令框架的基础知识。 我们将解释命令框架组件,并使用它们将新项目添加到源菜单中。 然后,我们将展示如何启用和禁用菜单项。 仅当新菜单项在当前选择中有用时,才会启用它们。
菜单中的新增内容称为菜单内容。 每个菜单项都需要知道在哪里绘制新项目,绘制哪些项目以及当有人单击它们时会发生什么。
大多数Eclipse菜单都分配了唯一的ID。 如果要为菜单添加内容,则必须找到该ID,从中组成所谓的位置URI,然后将其分配给菜单添加内容。
除其他事项外,每个菜单项都可以在菜单中添加分隔符和命令 。 分隔符是不同菜单部分之间的灰色线。 放置在菜单中的命令表示可单击的菜单项。 每个都有一个标签,可能有一个图标,并且可以启用或禁用。
但是,该命令无法执行操作。 这只是将GUI与实际操作分开的抽象事物。 实际工作是在命令处理程序中完成的。
菜单ID是分配给菜单或子菜单的任意字符串。 每个菜单可以具有多个ID。 查找Eclipse菜单的菜单ID会非常令人沮丧和困难。
如果幸运的话,该ID将与Eclipse RCP中提供的Plugin Spy一起显示。 它能够显示有关菜单项,UI元素和正在运行的Eclipse插件的信息。 如果您不走运,则必须自己找到ID。
如果您希望将一项添加到菜单或工具栏的顶层,那么事情就很容易了。
常规应用程序菜单列表:
- Eclipse主菜单使用
org.eclipse.ui.main.menu
。 ID仅指菜单的顶层,例如,该项目将与“文件”,“编辑”和“帮助”一起放置。 - Eclipse工具栏使用
org.eclipse.ui.main.toolbar
。 - 上下文菜单使用
org.eclipse.ui.popup.any
id。
如果您希望对某些视图内的菜单或工具栏有所帮助,请使用视图ID。 幸运的是,插件间谍可以帮助您找到视图ID。 在RCP Eclipse中打开视图,然后按“ Alt + Shift + F1”。 Plugin Spy将打开一个包含视图信息的弹出窗口:
查找子菜单的ID可能会更加复杂,因为Plugin Spy可能无法找到它。
使用“ Alt + Shift + F2”快捷方式启动您要贡献的插件间谍并打开菜单。 单击任何菜单项,Plugin Spy将显示有关它的各种信息。
使用插件间谍获取源菜单位置URI:
- 在开发Eclipse中打开任何Java文件,
- 按“ Alt + Shift + F2”,
- 在Java文件中右键单击
- 将鼠标悬停在“源”菜单项上,
- 点击“清理...”项。
Eclipse将显示以下弹出窗口:
如果弹出窗口包含位置URI,那么我们快到了。 复制并将其粘贴到某处。 警告:“插件间谍”弹出窗口在复制文本之前和之后都会添加新行,因此看起来好像没有任何内容被复制。
之间的部分:和? 是菜单ID。 例如,如果插件间谍显示
menu:org.eclipse.jdt.ui.source.menu?after=CleanUp
,菜单ID为
menu:org.eclipse.jdt.ui.source.menu?after=CleanUp
org.eclipse.jdt.ui.source.menu
如果Plugin Spy没有显示位置URI,则表示菜单项或菜单本身尚未重写到命令框架中。 这是旧菜单项的Plugin Spy弹出窗口的样子:
最好的选择是四处搜索并查看有助于该菜单的插件的plugin.xml。 可能有人遇到相同的问题并设法解决了。
您可以从jdg2e上可用的旧菜单列表开始。 如果菜单已经存在于Eclipse 3.0中,则会在菜单中列出其菜单ID。 该表中没有源菜单。
但是,其父菜单的ID是#CompilationUnitEditorContext
,例如,如果您右键单击任何java文件都可用的菜单。 这将是可以接受的二等奖。
尽管使用命令框架对顶级菜单的贡献很容易,但是未知的菜单ID使得对各种子菜单的贡献变得困难甚至不可能。 如果找不到运气,则必须使用旧的action框架 。
位置URI字符串包含三部分:方案,菜单ID和位置修饰符:
<scheme>:<menu-id>[?<placement-modifier>]
Eclipse有三种方案:
-
menu
–主应用程序菜单或视图菜单, -
toolbar
–主应用程序工具栏或视图工具栏, -
popup
–上下文菜单,例如,任何通过右键单击调用的菜单。
放置修饰符是可选的。 它具有<placement>=<id>
。 放置部分在after
或before
。 ID是分隔符名称,菜单ID或项目ID。 请注意,如果菜单不包含指定的ID,它将忽略您的贡献。
按照约定,每个菜单都应声明一个ID为'additions'的特殊项目。 在这里,菜单作者应该放置项目。 您不必尊重他们的意愿,某些菜单没有此类项目。 即使特殊添加项位于菜单中,您也可以将项目放置在任意位置。
几个例子:
-
menu:org.eclipse.ui.main.menu?after=file
–将项目添加到主菜单中的File和Edit子菜单之间。 -
toolbar:org.eclipse.ui.main.toolbar
–将项目添加到主工具栏。 -
menu:org.eclipse.ui.navigator.ProjectExplorer
–将项目添加到项目浏览器视图中可用的菜单。 -
toolbar:org.eclipse.ui.navigator.ProjectExplorer
–将项目添加到项目浏览器视图中可用的工具栏。 -
popup:org.eclipse.ui.popup.any
–将项目添加到上下文菜单。
将该项目放到源菜单中,而不用担心确切的位置:
popup:org.eclipse.jdt.ui.source.menu
注意:我们在位置URI中省略了可选的确切位置,因为它可能很棘手。 如果还希望指定确切的位置,则必须确保每次调用菜单时都存在选定的位置。 不幸的是,仅仅因为菜单项看起来相同,并不意味着它确实是同一菜单项。
例如,如果我们将?after=CleanUp
添加到上一个位置的末尾,则我们的菜单项将被放置在Java编辑器中右键调用的source子菜单中的“ Clean Up…”项之后。 但是,它在包浏览器视图中右键单击所调用的源子菜单中将不可见。
命令是抽象的事物,代表一个动作并具有唯一的ID。 可以将其放置在菜单中,并且可以为其分配快捷方式。
命令在plugin.xml文件中配置。 打开它并转到扩展选项卡。 使用左侧的名为“所有扩展名”的部分:
- 单击“添加”,然后选择
org.eclipse.ui.commands
扩展点。 - 右键单击新的扩展点,然后选择“新建”->“命令”。
- 填写ID。 约定是使用插件名称作为命令ID的前缀。
- 填写姓名。
我们创建了两个命令。 一个名为“ Generate Custom toString”,另一个名为“ Check Non-Null Parameter”。 他们的ID是:
-
org.meri.eclipse.defensiveapitools.generatetostring
-
org.meri.eclipse.defensiveapitools.checknonnullparameter
Eclipse自动生成相应的xml并将其放置到plugin.xml文件中。 转到plugin.xml选项卡进行查看:
<extension point="org.eclipse.ui.commands"><commandid="org.meri.eclipse.defensiveapitools.generatetostring"name="Generate Custom toString"></command><commandid="org.meri.eclipse.defensiveapitools.checknonnullparameter"name="Check Non-Null Parameter"></command>
</extension>
菜单贡献是菜单的补充。 它知道在何处绘制自身,并包含应绘制的项目列表。 放置在菜单项中的所有项目将按照其在该列表中的位置所定义的顺序一起显示。
我们将配置一个新的菜单内容,并在其中添加两个菜单项和两个分隔符。 向其添加其他元素类型是类推。
菜单项在plugin.xml文件中配置。 打开它并转到扩展选项卡。 使用左侧的名为“所有扩展名”的部分:
- 单击“添加”,然后选择
org.eclipse.ui.menus
扩展点。 - 右键单击新的扩展点,然后选择“新建”->“菜单贡献”。
- 填写locationURI 。
- Set allPopups to
true
.
Recall, that the source context menu location uri is:
-
popup:org.eclipse.jdt.ui.source.menu
Add commands to the menu contribution:
- Right click on the menu contribution and choose 'New' -> 'command'.
- Click Browse and find previously created command.
- Fill in label.
Eclipse automatically generates corresponding xml and places it to the plugin.xml file. Go to the plugin.xml tab to see it:
<extensionpoint="org.eclipse.ui.menus"><menuContributionallPopups="true"locationURI="popup:org.eclipse.jdt.ui.source.menu"><commandcommandId="org.meri.eclipse.defensiveapitools.generatetostring"label="Generate Custom toString"style="push"></command><commandcommandId="org.meri.eclipse.defensiveapitools.checknonnullparameter"label="Check Non-Null Parameter"style="push"></command></menuContribution>
</extension>
Test the menu. Run or debug the plugin and open any java file in the test Eclipse. Right click and choose the Source sub-menu. The menu contains two new items. As our commands have no handlers assigned, both items are disabled.
Add separator to the menu contribution:
- Right click on the menu contribution and choose 'New' -> 'separator'.
- Set visible to
true
. - Fill in name.
The order of elements in the menu contribution defines the order of corresponding items in the menu. Drag and drop new separator to the place where you would like to see it.
Eclipse automatically generates corresponding xml and places it to the plugin.xml file. Go to the plugin.xml tab to see it:
<menuContributionallPopups="true"locationURI="popup:org.eclipse.jdt.ui.source.menu"><separatorname="org.meri.eclipse.defensiveapitools.begin"visible="true"></separator>... commands ...<separatorname="org.meri.eclipse.defensiveapitools.end"visible="true"></separator>
</menuContribution>
Test the menu again. Run or debug the plugin and open any java file in the test Eclipse. Right click and choose the Source sub-menu. Our menu items are surrounded by menu separators.
The command handler is the class that executes an action whenever users clicks on the menu item. Once we assign it to the command, the menu item created in previous chapter will be enabled.
This section is divided into three part. First two sections show how to create and configure a dummy handler. Third section explains where the handler can get the information about currently selected items, active editor and other UI state.
A command handler must implement the IHandler2
interface. The easiest way to implement it is to extend the abstract AbstractHandler
class. This class provides standard implementation of all necessary methods except the execute
method.
The execute method is called whenever user invoked the command. It has one parameter which contains information about the current state of the application. The execute method must return null
.
Our first command handler is very simple:
public class GenerateToStringHandler extends AbstractHandler {@Overridepublic Object execute(ExecutionEvent event) throws ExecutionException {System.out.println("GenerateToStringHandler");// must return nullreturn null;}}
The only thing we have to configure is which commands should be handled by our handler.
Note: It is also possible to assign multiple handlers to one command, but we will not do it. It is an advanced topic discussed in additional resources .
As usually, command handlers are configured in plugin.xml file. Open it and go to extensions tab. Use the left part named 'All Extensions':
- Click 'Add' and choose
org.eclipse.ui.handlers
extension point. - Right click on the new extension point and choose 'New' -> 'handler'.
- Browse for the command id.
- Browse for the class implementing the command handler.
Eclipse automatically generates corresponding xml and places it to the plugin.xml file. Go to the plugin.xml tab to see it:
<extensionpoint="org.eclipse.ui.handlers"><handlerclass="org.meri.eclipse.defensiveapitools.generatetostring.GenerateToStringHandler"commandId="org.meri.eclipse.defensiveapitools.generatetostring"></handler><handlerclass="org.meri.eclipse.defensiveapitools.checknonnullparameter.CheckNonNullParameterHandler"commandId="org.meri.eclipse.defensiveapitools.checknonnullparameter"></handler>
</extension>
Run or debug the plugin and open any java file in the test Eclipse. Right click and choose the Source sub-menu. The 'Generate Custom toString' menu item is enabled. If you click on it, the command handler will print 'GenerateToStringHandler' into console in RCP Eclipse.
As we are going to invoke our feature from two different places, our command handler will delegate all real functionality to yet another class.
That another class will need some information about the context surrounding the command. Namely, 'Generate Custom toString' needs to know which class was selected and 'Check Non-Null Parameters' needs to know which method was selected.
Note: Eclipse generates mini-selection every time you place the cursor somewhere. You do not have to highlight the text inside editor.
The execute
method obtains an instance of ExecutionEvent
as a parameter. The execution event has reference to application context which contains various information about the state of the eclipse.
Use the HandlerUtil
to get that information out of the execution event. Handler util is a static class and has a lot of getWHATEVER
methods. We will need four of them:
-
getCurrentSelection
– returns current selection, -
getActivePartId
– returns id of active view or editor, -
getActiveEditorInput
– returns object edited by the opened editor, -
getActiveShell
– returned object will be needed for our plugin dialog.
private static final String JAVA_EDITOR_ID =
"org.eclipse.jdt.ui.CompilationUnitEditor";public Object execute(ExecutionEvent event) throws ExecutionException {//this object is needed to render wizards, messages and so on Shell activeShell = HandlerUtil.getActiveShell(event);//get selected items or text ISelection currentSelection = HandlerUtil.getCurrentSelection(event);//identify active GUI partString activePartId = HandlerUtil.getActivePartId(event);if (JAVA_EDITOR_ID.equals(activePartId)) {//get edited fileIEditorInput input = HandlerUtil.getActiveEditorInput(event);//currentSelection contains text selection inside input file//... locate class selected in that file ...} else {//currentSelection contains all selected classes //... collect all selected classes ...}return null;
}
Enabling, Disabling and Visibility
The menu item does not have to be visible and enabled all the time. Most commands are not universally usable.
Both our features are going to be visible all the time. However, we will have them enabled only under some conditions. 'Check Non-Null Parameters' will be enabled:
- inside java editor,
- if the current selection contains only modifiable java methods.
'Generate Custom toString' will be enabled:
- inside java editor,
- if the current selection contains only modifiable java classes or source files.
First, shortest section shows where to configure visibility and enablement. Next one describes xml language used to define visibility and enable conditions. Third section uses that language to test active editor and fourth tests selected objects. Final two sections put everything together and show conditions needed for our plugin.
If you want to make the menu item invisible, use the visibleWhen
tag on a command reference inside a menu contribution. If you want to make the item disabled, use the enabledWhen
tag on the command handler. Both tags works exactly the same way.
Open plugin.xml in an editor and go to the extensions tab. Right click either on the reference inside a menu contribution or command handler and choose either visibleWhen
or enabledWhen
.
If you right click on visibleWhen
or enabledWhen
tag, Eclipse will show a list of possible sub-tags. All those tags are part of xml boolean expression language and we will use them to define a condition. If the condition is satisfied, the menu item will be visible or enabled. If the condition is not satisfied, the menu item is either disabled or invisible.
One warning: not each tag shown on the list is directly usable. In this case, Eclipse simply shows all tags that defines a condition.
Usage of all listed tags is described on Eclipse help page . We will explain only five tags needed for our conditions:
-
or
– logical or, -
with
– specify the object under condition, -
iterate
– iterator over a collection, -
equals
– compares object under condition with a value, -
adapt
– adapts object under condition to the specified one.
Or
The element or
does logical or. Its child tags must represent conditions. If at least one of them returns true, the result is true.
With
The element with
specifies the object under condition. This tag can access various variables that describe Eclipse state. Each variable has a name. All childs of the with
tag will test their condition against the value of the specified variable.
This tag has one mandatory property variable
. Use it to specify the variable name. We will use two variables:
- activeMenuSelection – collection of all objects selected by the user,
- activePartId – the id of currently active GUI part (view, editor, preference page …).
As any plugin can add its own variable, the complete list of all variables is impossible to find. The list of default variables is available on Eclipse wiki page .
Iterate
The element iterate
is usable only inside the with
tag and only if this tag specified a collection as the object under the test. Its child tags must represent conditions. Iterate iterates through all objects inside the collection and runs all child conditions on those objects.
The iterate
tag has two arguments: operator
and ifempty
. The first argument value can be either and
or or
. Selected operator will be applied to evaluated conditions results. If no operator is specified, the iterator uses and
.
The ifempty
can be either true
or false
. This value will be returned if the collection under test is empty. If not specified then true
is returned when the operator equals and
and false
is return if the operator equals or
.
Equals
The element equals
compares the object under test with its value
argument. As the object under test may not be a string, the value argument is converted into the object. The exact conversion algorithm is described in Eclipse manual .
Adapt
The element adapt
adapts the object under test to the interface or class specified in its type
argument. It may have child tags that may process it further, but we will use it solely to check whether the object under test is adaptable to the desired interface.
If the menu was invoked from java editor, then id of the active part is the same as id of java editor. Therefore, we have to get java editor id and compare it to the value of activePartId
expression variable.
To get the id, open any java file in RCP eclipse and press ALT + SHIFT + F1. Plugin Spy will show popup with various information about active GUI part. According to this popup, the java editor id is org.eclipse.jdt.ui.CompilationUnitEditor
.
Combine the with
and equals
tags to compare the id:
<with variable="activePartId"><equals value="org.eclipse.jdt.ui.CompilationUnitEditor" />
</with>
Current selection can contain multiple items and all of them should represent something we can work with. The adapter pattern and java model hierarchy have been designed exactly for these kind of situation.
Three interfaces from java model hierarchy are relevant to our features:
-
org.eclipse.jdt.core.IMethod
– represents java methods, -
org.eclipse.jdt.core.IType
– represents java classes and interfaces, -
org.eclipse.jdt.core.ICompilationUnit
– represents java source file.
Therefore, we will iterate over the activeMenuSelection
variable and check whether each selected object is adaptable to one of needed types. If no item is selected, the condition should return false
.
A method is selected if it is possible to adapt all selected objects into the IMethod
interface:
<with variable="activeMenuSelection"><iterate ifEmpty="false" operator="and"><adapt type="org.eclipse.jdt.core.IMethod" /></iterate>
</with>
A java source file or a class is selected if it is possible to adapt all selected objects into either ICompilationUnit
or IType
interface:
<with variable="activeMenuSelection"><iterate ifEmpty="false" operator="and"><or><adapt type="org.eclipse.jdt.core.IType" /><adapt type="org.eclipse.jdt.core.ICompilationUnit" /></or></iterate>
</with>
Note 1: Unfortunately, the xml expression language is not expressive enough to distinguish between classes and interfaces. An instance of IType
interface represents class if its isClass
method returns true
, but xml language does not support method calls.
Note 2: We are cheating little bit here. It is not possible to modify compiled java methods and classes inside jar packages, but they are adaptable to java model interfaces too. Those objects are modifiable only if the method getCompilationUnit
does not return null
. As with the previous note, this is not possible to check from the xml expression language. Fortunately, we are contributing to the source sub-menu which is available only on modifiable java elements, so we do not have to solve this problem.
Note 3: In both cases, the correct solution would be to create own with
variable and handle both problems in java. This is possible and easy, but out of scope of this article. If you wish to know how to do it, read the post on Lars Vogel blog.
Check Non-Null Parameters Enablement
To reiterate, the menu item 'Check Non-Null Parameters' will be enabled:
- inside java editor,
- if the current selection contains only modifiable java methods.
Use or
to combine conditions created in previous chapters. This is the final condition:
<enabledWhen><or><with variable="activePartId"><equals value="org.eclipse.jdt.ui.CompilationUnitEditor" /></with><with variable="activeMenuSelection"><iterate ifEmpty="false" operator="and"><adapt type="org.eclipse.jdt.core.IMethod" /></iterate></with></or>
</enabledWhen>
Generate Custom toString Enablement
Recall, that the menu item 'Generate Custom toString' will be enabled:
- inside java editor,
- whenever java class is selected,
- whenever java file is selected.
Use or
to combine conditions created in previous chapters. This is the final condition:
<enabledWhen><or><with variable="activePartId"><equals value="org.eclipse.jdt.ui.CompilationUnitEditor" /></with><with variable="activeMenuSelection"><iterate ifEmpty="false" operator="and"><or><adapt type="org.eclipse.jdt.core.IType" /><adapt type="org.eclipse.jdt.core.ICompilationUnit" /></or></iterate></with></or>
</enabledWhen>
Expression Language – Additional Resources
The complete explanation on how those conditions work is out of scope of this post. If you wish to read more, the basic and short article is on eclipse-tips blog and a detailed one is on Lars Vogel blog.
The detailed post explains also how to reuse conditions and how to create new with
variable. It is definitely worth reading, especially if you plan to do something complicated.
Command Framework – Additional Resources
We simplified things a little in this chapter. The full functionality and possibilities of the command framework are out of scope of this article.
If you wish to know more, good tutorials are available on Lars Vogel blog or in IBM library .
Theoretically speaking, the actions framework is old and has been deprecated. The newer commands framework should be used for most purposes. Unfortunately, not all menus have been rewritten yet.
If the menu you are interested in has not been rewritten yet, you have to use the old actions framework to contribute to it.
As most menus are already compatible with the new command framework, we will show only the part of actions framework that is able to contribute to the source sub-menu in main menu. If you wish to read more about the actions framework, the last sub-chapter links to more detailed articles.
Two most important elements in the actions framework are action and action delegate. An action is assigned to menu items and knows the menu where it should be drawn. Action delegate is a class that does all the work whenever a menu item is invoked.
Each action delegate can be assigned to any number of actions. However, each action can have only one action delegate.
Items and menus definitions are kept either inside an action set or inside something called a contribution. There is not much difference between them, both action set and contribution contain list of actions and sub-menus to be drawn within menu system.
Eclipse framework has three types of actions contributions and each is able to specify a simple condition that must be satisfied to have a visible action:
-
viewerContribution
– an action is available only inside specified view, -
objectContribution
– an action is available only if specified object type has been selected, -
editorContribution
– an action is available only inside editor menu or toolbar.
Note: it is also possible to assign a condition to an action. Action conditions are powerful, but out of scope of this article.
Both contribution and action set are placed directly inside an extension point. Each menu type has its own extension point:
-
org.eclipse.ui.actionSets
– main menu or main toolbar, -
org.eclipse.ui.popupMenus
– context menu, -
org.eclipse.ui.viewActions
– local menu or toolbar in a view, -
org.eclipse.ui.editorActions
– local menu or toolbar in an editor (recall that the editors menu is shown inside the main menu/toolbar), -
org.eclipse.ui.perspectiveExtensions
– we will ignore that.
So, we have to create action delegate class, identify the menu we want to contribute to and configure an action inside a action set.
Action delegate implementation depends on where you want to place the associated action. Menus supply the action delegate with additional information that depends on the menu type. Therefore, each menu type requires it to implement different interface.
Each action delegate must implement IActionDelegate
interface. That interface was later extended with some lifecycle methods, so if you need to initialize your action delegate or know when it is disposed, implement also IActionDelegate2
interface.
Which method is invoked when a menu item is clicked depends on implemented interfaces. An action delegate that does NOT implement IActionDelegate2
interface must place all the work inside the run
method. However, an action delegate that implements the IActionDelegate2
interface must place all the work inside the runWithEvent
. In this case, the run
method is never called.
Which sub-interfaces of IActionDelegate
interface you should use depends on where do you want to place the action. Some parent menus send additional information about active parts and the action delegate must be able to acquire it.
List of eclipse menus and expected action delegate interfaces:
- main menu or toolbar –
IWorkbenchWindowActionDelegate
, - view menu or toolbar –
IViewActionDelegate
, - view context menu –
IViewActionDelegate
orIObjectActionDelegate
, - editor menu or toolbar –
IEditorActionDelegate
, - editor context menu –
IObjectActionDelegate
.
Parent menu uses the method selectionChanged
to inform the action delegate about current selection changes. However, selection changes are sent to the action delegate only after it was invoked for the first time. All prior selection changes are ignored.
The selectionChanged
method is called for the first time right before the first call of run
or runWithEvent
method.
We are ready to implement our action delegates. As it was with the command handler in command framework, our action delegate will only collect information about current editor and selected objects or text. The real work is delegated to yet another class.
As we want to put our action to the main menu, we have to implement the IWorkbenchWindowActionDelegate
interface. Main menu sends changes of current selection it to its action delegates, so all we have to do is to store it:
private ISelection selection;public void selectionChanged(IAction action, ISelection selection) {this.selection = selection;
}
Getting current editor is little bit more complicated. Main menu does not inform its items about active UI parts. However, it sends them an instance of IWorkbenchWindow
upon initialization. Fortunately, the workbench window object is aware of almost everything that is going on in the eclipse.
The explanation of the workbench window object would take too much space and it is not that important. The important is, that it provides access to all kind of information about eclipse user interface.
Use workbench window to get active editor and its id:
private IWorkbenchWindow window;public void init(IWorkbenchWindow window) {this.window = window;
}private String getActivePartId() {return window.getPartService().getActivePartReference().getId();
}private IEditorPart getActiveEditor() {return window.getActivePage().getActiveEditor();
}
Finally, we are ready to implement the run method:
public class GenerateToStringActionDelegate implements IWorkbenchWindowActionDelegate {private static final String JAVA_EDITOR_ID =
"org.eclipse.jdt.ui.CompilationUnitEditor";public void run(IAction action) {//this object is needed to render wizards, messages and so on Shell activeShell = window.getShell();//get selected items or text ISelection currentSelection = selection;//identify active GUI partString activePartId = getActivePartId();//java editor must be handled differently than view selection if (JAVA_EDITOR_ID.equals(activePartId)) {//get edited fileIEditorInput input = getActiveEditor().getEditorInput();//currentSelection now contains text selection inside input file//... locate class selected in that file ...} else {//currentSelection now contains all classes inside //... collect all selected classes ...}System.out.println("GenerateToStringActionDelegate");}}
Before you configure the action, you have to find the menu or toolbar path. It identifies a menu or toolbar where your action will be shown.
Each menu or sub-menu has its name and menu or toolbar path navigates those names. It starts with the top level menu name and continues with all sub-menu names. The final part is optional and specifies a location in the final menu. If it is missing, the item is placed to the end of the specified menu.
For example, the menu path #menuName/subMenuName/additions
should be read as “place the item in the end of the additions
group which is located inside the sub-menu subMenuName
of the #menuName
menu”.
Or, the menu path #menuName/subMenuName/
should be read as “place the item in the end of the sub-menu subMenuName
of the #menuName
menu”.
Important: Menu ids are the same as described in the command framework chapter . The id of the source menu id is org.eclipse.jdt.ui.source.menu
. As the main source menu is a top level menu, menubarPath is:
org.eclipse.jdt.ui.source.menu/
Action configuration is quite simple. Add an extension point, put either action set or contribution into it and place the action.
Which one of five extension points should be used depends on the menu. We want to add an action to the main menu, so we have to use the action sets extension point.
Open plugin.xml file and go to extensions tab. Use the left part named 'All Extensions'. First, configure an action set:
- Click 'Add' and choose
org.eclipse.ui.actionSets
extension point. - Right click on the new extension point and choose 'New' -> 'actionSet'.
- Fill in the action set id. The convention is to use plugin name as its prefix. Important: This field has some strange limitations. We could not really figure them out, so all we can say is that:
org.meri.eclipse.defensiveapitools.mainmenucontrib
works
In any case, if nothing shows up in the menu, try to change this id.
- Fill in label. 可以是任何东西。
- Set visible to
true
.
Second, add actions to the action set:
- Right click on the action set and choose 'New' -> 'action'.
- Fill in the action id. The convention is to use plugin name as id prefix.
- Fill in label. 可以是任何东西。
- Fill in either menubarPath or toolbarPath.
- Scroll down and browse for the action delegate in class field.
Eclipse automatically generates corresponding xml and places it to the plugin.xml file. Go to the plugin.xml tab to see it:
<extensionpoint="org.eclipse.ui.actionSets"><actionSetid="org.meri.eclipse.defensiveapitools.sourcemenu"label="Defensive API Tools "visible="true"><actionclass="org.meri.eclipse.defensiveapitools.generatetostring.
GenerateToStringActionDelegate"id="org.meri.eclipse.defensiveapitools.generatecustomtostring"label="Generate Custom toString"menubarPath="org.eclipse.jdt.ui.source.menu/"style="push"></action><actionclass="org.meri.eclipse.defensiveapitools.checknonnullparameter.
CheckNonNullParameterActionDelegate"id="org.meri.eclipse.defensiveapitools.checknonnullparameters"label="Check Non-Null Parameters"menubarPath="org.eclipse.jdt.ui.source.menu/"style="push"></action></actionSet>
</extension>
Run or debug the plugin and open any java file in the test Eclipse. Click on the Source main menu item. The menu contains two new items. Click on the Generate Custom toString' menu item, the action delegate will print 'GenerateToStringActionDelegate' into console in RCP Eclipse.
Walkthrough of all types of actions contributions is available in an eclipse corner article . Easy to read FAQ article explains actions in the main menu.
Actions framework supports also complicated conditions and filters to show actions only under some circumstances. If you have a reason to use that, the best starting point is in eclipse documentation .
Everything directly related to chapters in this post was already linked. We will add only a link on a very good series with various eclipse development tips .
If you have a problem and can not find an answer, you can also ask questions on official freenode #eclipse IRC channel.
Although we added only some new items into the menu so far, almost everything needed to finish the plugin is already there. If you do not insist on having the generated code formatted, you should be able to finish the generate toString feature just by browsing through java model hierarchy API.
Next part of this tutorial will show how to finish both features, including the formatting of the generated code. It will also explain how to create and work with abstract syntax tree and how to create a dialog to communicate with user.
Reference: Writing Eclipse Plugins Tutorial – Part 1 from our JCG partner Maria Jurcovicova at the This is Stuff blog.
翻译自: https://www.javacodegeeks.com/2012/05/writing-eclipse-plugins-tutorial-part-1.html
eclipse 插件教程