Eclipse 3.1 与 3.2 之间的不兼容性

在 Eclipse 3.1 与 3.2 之间以不兼容的方式进行了更改,这对插件产生了影响。下列条目对已更改的领域作了描述,并提供了有关从 3.1 插件迁移到 3.2 插件的指示信息。请注意,仅当您在 3.2 平台上运行 3.1 插件遇到问题时,才需要参阅本文档。

  1. 资源在本地文件系统中不再是必需的
  2. 对 MultiPageEditorSite 进行的 API 更改
  3. config.ini 中的内容更改
  4. JNLP 部署的应用程序中的内容更改
  5. 显式地调用 Bundle.start() 将导致在下次重新启动时强制激活捆绑软件
  6. 在插件版本号中不再将下划线替换为连字符

1. 资源在本地文件系统中不再是必需的

受影响的内容:那些假定资源存储在本地文件系统中的 IWorkspace API 客户机。

描述:在 Eclipse 3.2 以前,每个现有的 IResource 在文件系统中都有可通过 java.io.File 访问的相应文件或目录。在 Eclipse 3.2 中,还支持创建将内容存储在专用后备文件系统中的资源。不再能够将使用此支持的资源直接表示为 java.io.File

需要执行的操作:旧方法 IResource.getLocation() 返回资源的本地文件系统路径。对于未存储在本地文件系统中的资源,此方法返回 null。getLocation() 的大部分调用者通过调用它来获取 java.io.File 的实例,但该实例不再能够用于未存储在本地文件系统中的资源。

新的 org.eclipse.core.filesystem 插件提供了可用于替代 java.io.File 的通用文件系统 API。尤其是,org.eclipse.core.filesystem.IFileStore 的实例提供了大部分可用于 java.io.File 的方法。以下代码片段针对给定资源获取 IFileStore 的实例:

   IResource resource = ...;//some resource
   IFileStore store = EFS.getStore(resource.getLocationURI());

下表提供了通常对 java.io.File 执行的操作在 IFileStore 中的等同方法:

java.io.FileIFileStore
deletedelete
getNamegetName
getParentgetParent
listchildNames
mkdirmkdir(EFS.SHALLOW, null)
mkdirsmkdir(EFS.NONE, null)
renameTomove
new FileInputStream(file)openInputStream
new FileOutputStream(file)openOutputStream

IFileStore API 中,大部分关于文件的信息存储在名为 IFileInfo 的结构中,您可以通过调用 IFileStore.fetchInfo() 来获取此信息。由于许多有关文件的属性通常可以通过单一文件系统调用来获取,因此这种设计使您能够对使用 java.io.File 的代码进行更大程度的优化。请注意,如果底层文件被更改,IFileInfo 中的信息就会变旧,因此只应该在有需要时才使用实例。下面列示了 java.io.FileIFileInfo 之间的等同方法:

java.io.FileIFileInfo
canWriteisReadOnly
existsexists
getNamegetName
isDirectoryisDirectory
isFile!isDirectory()
isHiddenisHidden
lastModifiedgetLastModified
lengthgetLength
setLastModifiedsetLastModified
setReadOnlysetAttribute(EFS.ATTRIBUTE_READ_ONLY, true)

作为具体的示例,先前调用 java.io.File.exists() 的代码现在可以调用 IFileStore.fetchInfo().exists()。修改 IFileInfo 时,需要使用 IFileStore.putInfo 方法来存储结果。例如,此代码段对文件切换只读属性:

   IFileStore store = ...;//some file store
   IFileInfo info = store.fetchInfo();
   boolean readOnly = info.getAttribute(EFS.ATTRIBUTE_READ_ONLY);
   info.setAttribute(EFS.ATTRIBUTE_READ_ONLY, !readOnly);
   store.putInfo(info, EFS.SET_ATTRIBUTES, null);

IProjectDescription.getLocation()

对于 getLocation() 方法来说,项目描述的位置不再位于本地文件系统中。可以使用方法 IProjectDescription.getLocationURI() 来获取任意文件系统中的资源位置。

本地高速缓存

某些客户机绝对必须使用文件的本地表示。例如,它们可能正在对该文件启动本机工具,或者正在使用那些不支持 Eclipse 而只能处理文件系统资源的库(例如 java.util.zip.ZipFile)。在这些情况下,可以要求 IFileStore 返回其内容的本地高速缓存副本:

   IFileStore store = ...;//some file store
   //see if it can directly be represented as a local file
   java.io.File local = store.toLocalFile(EFS.NONE, null);
   //if not, ask for a cached local copy of the file
   if (local == null)
      local = store.toLocalFile(EFS.CACHE, null);

请注意,一旦获取文件的高速缓存副本,该文件就不再与它的实际文件系统保持同步。修改高速缓存的副本时,并不会导致修改底层的文件。

平稳地发生故障

无法处理本地文件系统外部的资源的客户机可能想改写它们的代码,以便更平稳地发生故障。客户机可以检查资源是否在本地文件系统中,并在遇到无法处理的资源时忽略该资源或提醒用户。要确定资源是否在本地文件系统中,需要确定它的文件系统方案。可以从资源获取此信息,如下所示:

   IResource resource = ...;//some resource
   URI uri = resource.getLocationURI();
   if (uri != null && EFS.SCHEME_LOCAL.equals(uri.getScheme())) {
      //file is in local file system
   } else {
      //file is not in the local file system
   }

如果有 IFileStore 实例,则可按如下方式获取方案:

   IFileStore store = ...;//a file store
   store.getFileSystem().getScheme();

2. 对 MultiPageEditorSite 进行的 API 更改

受影响的内容:调用了 MultiPageEditorSite.progressStart()MultiPageEditorSite.progressEnd() 的客户机。

描述:在 Eclipse 3.0 开发期间,在进度支持工作过程中添加了这些方法。在 3.0 发行版以前,已更改了进度的处理方式,这些方法不再是必需的。由于程序员的错误,在 3.0 发行版中仍提供了这些公用方法。这两个方法在 Eclipse 发行版中从未起过任何作用,因此已将它们删除。

需要执行的操作:调用了 MultiPageEditorSite.progressStart()MultiPageEditorSite.progressEnd() 的客户机应该改为使用 IWorkbenchSiteProgressService

3. config.ini 中的内容更改

受影响的内容:使用定制 config.ini 并将应用程序移至 3.2 的客户机。

描述:在 3.2 以前,config.ini 中包含的 osgi.bundles 的典型值是 org.eclipse.core.runtime@2:start, org.eclipse.update.configurator@3:start。由于进行了运行时重构,所以必须更新此值,这样应用程序才能成功启动。

需要执行的操作:将 osgi.bundles 的值更改为包含 org.eclipse.equinox.common@2:start, org.eclipse.update.configurator@3:start, org.eclipse.core.runtime@start

4. JNLP 部署的应用程序中的内容更改

受影响的内容:部署 RCP 应用程序并指定了 osgi.bundles 值的客户机。

描述:在 3.2 以前,主 JNLP 文件中包含的 osgi.bundles 的典型值是 org.eclipse.core.runtime@2:start, org.eclipse.update.configurator@3:start。由于进行了运行时重构,所以必须更新此值,否则会抛出 NullPointerException,从而导致应用程序无法启动。

需要执行的操作:将 osgi.bundles 的值更改为包含 org.eclipse.equinox.common@2:start, org.eclipse.update.configurator@3:start, org.eclipse.core.runtime@start

5. 显式地调用 Bundle.start() 将导致在下次重新启动时强制激活捆绑软件

受影响的内容:调用了 Bundle.start() 的客户机。

描述:在 Eclipse 中,通过使用 Eclipse-LazyStart 头(或者建议不要使用的 Eclipse-AutoStart 头),可以将捆绑软件指定成惰性启动捆绑软件。在 Eclipse 3.1 中,org.osgi.framework.Bundle.start() 方法未将惰性启动捆绑软件标记为持久启动。由于惰性启动捆绑软件永远不会被标记为持久启动,所以,它们不会在 Eclipse 重新启动时自动启动。Bundle.start() 的 Javadoc 指出,在调用此方法时,必须发生以下情况:

“持久记录此捆绑软件已启动。当框架重新启动时,此捆绑软件必须自动启动。”

在 Eclipse 3.2 中,已将 Bundle.start() 方法修正为正确地将捆绑软件标记为持久启动,即使该捆绑软件是惰性启动捆绑软件亦如此。必须进行此项修正才能与 OSGi 框架规范保持一致。因此,Bundle.start() 的调用者将强制使该捆绑软件在 Eclipse 重新启动时启动。由于会导致每次启动 Eclipse 时都激活非必需的捆绑软件,因此通常认为这是一种不好的做法。在某些情况下,这会导致意外的结果,例如错误 134412

需要执行的操作:Bundle.start() 的客户机需要评估它们是否打算在每次重新启动时都永久激活捆绑软件。如果意图并非如此,则客户机应该采用另一种方法来激活捆绑软件。在大多数情况下,通过在从目标捆绑软件中装入类时简单地允许惰性激活该捆绑软件,可以避免调用 Bundle.start()。在一些罕见的情况下,需要主动地激活惰性启动捆绑软件,但不能永久地将它们标记为在每次重新启动时激活。在这些类型的情况下,应该使用 Bundle.loadClass() 来从需要激活的捆绑软件中装入类,而不应该调用 Bundle.start()

5. 在插件版本号中不再将下划线替换为连字符

在 Eclipse 3.0 中,不支持在版本标识的限定符段使用下划线(“_”)字符,但也没有强制实施此规定。 In Eclipse 3.0, the use of an underscore ('_') character in the qualifier segment of a version identifier was not supported, but also was not enforced. 如果插件版本标识在限定符中包含下划线,在将该插件导出到文件系统以及在从更新站点安装该插件时,将把此字符转换为连字符(“-”)。
在 Eclipse 3.1 中,在限定符中已允许使用下划线字符。因此,在导出或安装违例的插件时,未将限定符修改为与原始状态不同。在从 3.0 到 3.1 的迁移指南中,意外地遗漏了此项细微更改。在 Eclipse 3.2 中,我们保持与 Eclipse 3.1 兼容,在版本限定符中使用了下划线字符的插件在处理旧插件版本时(既包括导出旧版本插件时也包括在更新站点上存在旧版本插件时),应该考虑上述更改。例如,这意味着在更新站点上有旧版本插件的插件提供者应该确保文件系统中的名称与插件名匹配。