Java项目模型
Eclipse的项目有很多种包括Java项目C++项目C#项目等每种项目都有自己的特点我们最常接触到的项目就是Java项目因此我们重点来讲解一下Java项目模型
Java模型是用来对与创建编辑和构建Java程序相关联的对象进行建模的一些类Java模型类是在re中定义的这些类实现资源的特定于Java的行为并进一步将Java资源分解成模型元素
Java模型的继承结构图如图所示
图 Java模型的继承结构图
IJavaElement的子类接口还有IMethodIType等在这里没有全部列出Java模型中的类结构比较简单级次也非常少
下面介绍一下各个接口的主要方法
() IJavaElement
exists判断元素是否存在处理Java元素与处理资源对象相似当使用Java元素时实际上是在使用某些底层的模型对象的句柄必须使用exists()来确定元素是否真正存在于工作空间中
getElementName返回元素的名称
getJavaModel返回其对应的JavaModel返回值类型是IJavaModel
getJavaProject返回元素对应的Java工程返回值类型是IJavaProject
getParent返回父元素返回值类型是IJavaElement
getResource返回元素对应的资源返回值类型是IResource
() IClassFile
此接口代表编译后的class二进制文件
isClass判断是否是Java类
isInterface判断是否是接口
() ICompilationUnit
此接口代表Java源文件
getAllTypes返回此文件中定义的所有类型返回值类型是IType[]一个Java文件中可以定义多个类型
getPrimary返回主类型返回值类型是ICompilationUnit
() IJavaModel
此接口表示根 Java 元素对应于工作空间是所有具有 Java 性质的项目的父类它对于Java项目的作用和IWorkspaceRoot对于IProject的作用相似
contains判断是否存在指定的资源
getJavaProject返回指定名字的Java项目返回值类型是IJavaProject
getJavaProjects返回所有的Java项目返回值类型是IJavaProject[]
getWorkspace返回所在的工作空间
() IJavaProject
此接口表示Java项目
IJavaElement findElement(IPath path)返回项目的path路径下的Java元素
IPackageFragment findPackageFragment(IPath path)返回项目的path路径下的IPackageFragment
IPackageFragmentRoot findPackageFragmentRoot(IPath path)返回项目的path路径下的IPackageFragmentRoot
findType根据一个全名取得此元素的类型此类有数个重载方法返回值类型为IType
getAllPackageFragmentRoots返回所有的IPackageFragmentRoot返回值类型是IPackageFragmentRoot[]
getOutputLocation返回输出路径返回值类型是IPath
getRequiredProjectNames返回依赖项目返回值类型是字符串数组
setOutputLocation设定输出路径
() IPackageFragment
此接口表示整个包或者包的一部分
createCompilationUnit创建一个ICompilationUnit返回值类型是ICompilationUnit
getClassFile返回指定名称对应的IClassFile返回值类型是IClassFile
getClassFiles返回所有的IClassFile返回值类型是IClassFile[]
getCompilationUnit返回指定名称对应的ICompilationUnit返回值类型是ICompilationUnit
getCompilationUnits返回所有ICompilationUnit返回值类型是ICompilationUnit[]
getKind判断此包是源码包还是普通包返回值是int型如等于IPackage FragmentRootK_SOURCE则是源文件包如等于IPackageFragmentRootK_BINARY则为普通包
hasSubpackages是否有子包
() IPackageFragmentRoot
此接口表示一组包段并将各段映射至底层资源它可以是文件夹JAR或ZIP文件
createPackageFragment创建一个IPackageFragment返回值类型是IPackage Fragment
getKind此包段是源码包段还是二进制包段返回值类型是int如果等于IPackageFragmentRootK_SOURCE则是源文件包段如果等于IPackageFragment RootK_BINARY则为二进制包段
getPackageFragment根据包名返回对应的IPackageFragment
常用工具类
() JavaCore(定义在re包下)
JavaCore从Plugin继承它是JDT插件的生命周期管理器不过对于第三方插件开发人员来说它的重要性更多地体现在它提供的一些工具类方法中
IJavaElement create(IFile file)从文件创建对应的Java元素
IJavaElement create(IFolder folder)从文件夹创建对应的Java元素
IJavaProject create(IProject project)得到IProject对应的IJavaProject
IJavaElement create(IResource resource)从资源创建对应的Java元素
IJavaModel create(IWorkspaceRoot root)从工作空间根目录得到对应的IJavaModel
IClassFile createClassFileFrom(IFile file)从文件创建对应的IClassFile
ICompilationUnit createCompilationUnitFrom(IFile file)从文件创建对应的ICompilationUnit
() JavaUI(定义在orgeclipsejdtui包下)
JavaUI中定义了常用的Java插件界面相关的方法
createPackageDialog创建一个包选择对话框返回值是SelectionDialog
createTypeDialog创建一个类型选择对话框返回值是SelectionDialog
IEditorPart openInEditor(IJavaElement element)用编辑器打开指定的Java元素并返回编辑器实例
revealInEditor(IEditorPart part IJavaElement element)在编辑器中定位元素element
插件开发中经常会碰到一些常用的技巧掌握这些技巧可以极大地提高插件的开发效率并且可以减小插件的体积下面列出一些常见的技巧
() 由一个普通项目得到Java项目
Java项目是一种特殊的项目需要注意的是IJavaProject并不是从IProject继承的不能将一个IProject对象强制转换成一个IJavaProject对象也不能把一个IJavaProject实例赋值给IProject变量
由IProject项目得到Java项目的方式
IJavaProject javaPoject = JavaCorecreate(IProject);
由IJavaProject得到IProject的方式
调用IJavaProject的IProject getProject();
()得到工作空间中的所有Java项目
我们可以首先得到工作空间中的所有项目然后逐个进行转换不过这不免麻烦了一些下面介绍更好的方式IJavaModel是所有Java项目的根通过它就可以得到所有的Java项目
IWorkspaceRoot root = ResourcesPlugingetWorkspace()getRoot(); IJavaModel jModel = JavaCorecreate(root); IJavaProject jProject[] = jModelgetJavaProjects();
() 打开Java编辑器并显示Java编译单元的特定成员
代码如下
void showMethod(IMember member) { ICompilationUnit cu = membergetCompilationUnit(); IEditorPart javaEditor = JavaUIopenInEditor(cu); JavaUIrevealInEditor(javaEditor member); }
() 在工程下创建一个wnew包并创建一个Hellojava文件
() 打开【打开类型】对话框
以下代码段使用 JavaUI 类来打开【打开类型】对话框
new ProgressMonitorDialog(parent) SearchEnginecreateWorkspaceScope()
用类似方法还可以创建【打开包】和【打开主要类型】对话框
() 打包指定的文件
我们写一些工具的时候也许需要把文件打成jar包然后进行发布到应用服务器等操作调用JDT提供的类可简化这个操作(用到的打Jar包的类都在orgeclipseuijarpackager下)
JarPackageData description= new JarPackageData(); IPath location= new Path(C:/cownewjar); descriptionsetJarLocation(location); descriptionsetSaveManifest(true); descriptionsetManifestMainClass(mainType); descriptionsetElements(filestoExport); IJarExportRunnable runnable= descriptioncreateJarExportRunnable(parentShell); new ProgressMonitorDialog(parentShell)run(truetrue runnable);
参数mainType表示Jar包的main类filestoExport为要打包的文件
() 自动设置Java项目的构建路径
有一些插件会将需要的jar包自动设置到构建路径上比如使用WTP的新建向导新建web项目的时候就会把web开发需要的jar包自动放入项目的构建路径使用PDE的将项目转换为插件项目功能后项目的构建路径中就增加了插件依赖项的库那么它们是怎么实现的呢?
Java项目的构建路径有如下几种源文件夹二进制库依赖项目类路径变量和类路径容器
图 源文件夹
图 构建依赖项目
图 Jar和类文件夹依赖
每种不同的构建路径都有不同的作用源文件夹是把源码进行构建的途径二进制库是导入少量jar包的方式依赖项目是供多项目分模块开发使用的使用类路径变量可以避免二进制包的路径依赖而类路径容器则为大量二进制库的引入提供了方便
JDT为这些不同的构建路径提供了一个统一的接口IClassPathEntry只要调用IJavaProject的setRawClasspath方法就可以为项目设定构建路径
可以看到setRawClasspath方法需要一个IClasspathEntry数组数组中的元素就是要设置的每一个构建路径前面提到的JavaCore类提供了一系列的静态方法来帮助我们生成不同的IClasspathEntry而无须关注生成的细节下面来看不同构建路径的添加方式
① 源文件夹使用JavaCorenewSourceEntry方法下面的代码的作用是构造项目MyProject的源文件夹src的类路径条目
JavaCorenewSourceEntry(new Path(/MyProject/src));
② 二进制库IClasspathEntry使用JavaCorenewLibraryEntry 方法下面的代码就是构造MyProject的类文件lib的类路径条目
Path(/MyProject/lib)null nullfalse);
以下类路径条目具有源代码连接
设定关联源代码包有利于代码的跟蹤调试
③ 依赖项目使用JavaCorenewProjectEntry方法下面的代码就是构造依赖项目MyFramework
IClassPathEntry prjEntry = JavaCorenewProjectEntry(new
Path(/MyFramework) true);
④ 类路径变量使用JavaCorenewVariableEntry方法类路径变量对于整个工作空间来说是全局的并且可以通过 JavaCore 方法 getClasspathVariable 和 setClasspathVariable 来处理
可能会注册自动的类路径变量初始化方法当启动工作空间时通过扩展点 orgeclipse reclasspathVariableInitializer来调用该类路径变量初始化方法
以下类路径条目指示一个库该库的位置存放在变量HOME中使用变量SRC_HOME和SRC_ROOT来定义源代码连接
IClassPathEntry varEntry = JavaCorenewVariableEntry(
new Path(HOME/foojar) //库路径
new Path(SRC_HOME/foo_srczip) //源码归档路径
new Path(SRC_ROOT) //源码归档根路径
true);
JavaCoresetClasspathVariable(HOME new Path(d:/myInstall) null);
⑤ 类路径容器通过 JavaCore的getClasspathContainer和setClasspathContainer两个方法来处理类路径容器
可能会注册一个自动的类路径容器初始化方法当需要绑定容器时通过扩展点 reclasspathContainerInitializer来被动地调用类路径容器初始化方法
以下类路径条目指示系统类库容器
IClassPathEntry varEntry = JavaCorenewContainerEntry( new Path(JDKLIB/default)false); JavaCoresetClasspathContainer( new Path(JDKLIB/default) new IJavaProject[]{ myProject } new IClasspathContainer[] { new IClasspathContainer() { public IClasspathEntry[] getClasspathEntries() { return new IClasspathEntry[]{ JavaCorenewLibraryEntry( new Path(d:/rtjar) null null false); }; } public String getDescription() { return Basic JDK library container; } public int getKind() { return IClasspathContainerK_SYSTEM; } public IPath getPath() { return new Path(JDKLIB/basic); } } } null);
我们只要调用相应的方法创建我们的类路径条目就可以了然后把这些条目组成的数组通过setRawClasspath方法设定到项目中需要注意的是如果我们只把要添加的类路径条目传入 setRawClasspath方法的话就会替换原有的项目构建路径这常常是我们不希望的可以调用IJavaProject的 readRawClasspath方法读取项目已有的设置把我们要设置的构建路径添加到它的后面然后再调用setRawClasspath方法设定新的项目构建路径
在这个例子中将要实现一个为项目添加 lucene支持的功能用户在项目上右击选择菜单中的【为项目添加lucene支持】命令以后插件就会把lucene的jar包和源码包复制到项目的lib目录下并且将jar包加入构建路径如图所示为增加lucene支持前的项目结构
图 增加lucene支持之前的项目结构
用户在项目上右击在弹出的快捷菜单中选择【为项目添加lucene支持】命令后的项目结构如图所示
图 增加lucene支持之后的项目结构
图是项目的构建路径
图 增加的lucene包
首先新建一个插件工程并将JDT相关的依赖项加入然后添加一个orgeclipseuipopupMenus的扩展点如果不熟悉怎么添加可以使用插件向导中的弹出菜单向导
需要注意contribution的配置如图所示
图 contribution的配置
此插件只针对Java项目起作用因此 objectClass中填入reIJavaProject;adaptable选择true;如果是用向导生成的那么请记住清空nameFilter下面是核心类ActionAddLucene的实现代码
SystemgetProperty(fileseparator/); JavaCorenewLibraryEntry(project getFullPath() project LUCENESRCJAR)getFullPath() null new IClasspathEntry[oldPathslength + ]; LIB + FILESEPARATOR + LUCENEJAR); LIB + FILESEPARATOR + LUCENESRCJAR); IClasspathEntry entry) egetMessage() e));
下面解释一下代码中的重点部分
IClasspathEntry[] oldPaths = javaProjectreadRawClasspath();
读取项目原有的构建路径条目
IClasspathEntry luceneLibEntry = JavaCorenewLibraryEntry( projectgetFile(LIB + FILESEPARATOR + LUCENEJAR)getFullPath() projectgetFile(LIB + FILESEPARATOR + LUCENESRCJAR)getFullPath() null false);
这一句构建lucene的jar包
第个参数是二进制jar包的位置我们的二进制jar包的位置为项目路径下的lib/lucenesrcjar
第个参数是jar包对应的源码包的位置
第个参数为源码包的根路径因为有的源码jar包的源码根路径不是jar包的根路径比如simplejta的源码jar包的格式如图所示
图 Jar包的结构
对于这种情况就要指定第个参数为srclucene的源码包的源码根路径就是jar包的根路径因此我们设置此参数为null
第个参数表示是否导出我们设置为false
() URL luceneLib = ActivatorgetDefault()getBundle()getEntry(RESOUCELIB + FILE SEPARATOR + LUCENEJAR);
我们把lucenejar lucenesrcjar放到我们插件的resoucelib目录下当用户单击【为项目添加lucene支持】的时候要把这两个文件复制到项目的lib目录下因此需要首先读取插件路径resoucelib目录下的这两个jar包
读取插件路径下的文件时我们使用插件Activator类提供的方法即可比如如下调用
就可以读取到插件根目录下的文件config/myxml返回类型是URL
() copyURLToFile(luceneLib project LIB + FILESEPARATOR + LUCENEJAR);
ActivatorgetDefault()getBundle()getEntry读取到的文件位置是URL类型的我们需要把这个URL对应的文件复制到项目的lib下下面看一下copyURLToFile的主干代码
URL类有一个openStream可以打开文件的输入流IFile也有一个接受输入流的create方法用来创建文件因此我们只需要把url的输入流输出给IFile的create方法即可
这里我们也可以由url得到其对应的磁盘上的路径也可以得到IFile对应的磁盘上的路径然后使用Java IO来进行文件复制操作但是这样做不仅代码数量变多了而且由于使用的不是Eclipse的资源管理API会带来无法自动刷新等问题因此建议尽量使用Eclipse提供的API来完成此功能
学习Eclipse插件开发的最好的方式就是研读 Eclipse的源码而对插件开发者最有参考价值的就是JDT(Java Development Tools)的代码相信把所有的包研读一遍以后就会成为插件开发的高手了下面是各个主要包的内容读者可以根据需要有选择地进行研读