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 之前,在 java.io.File 所能存取的檔案系統中,每個現有的 IResource 都有對應的檔案或目錄。 Eclipse 3.2 增加了新支援,所建立的資源能夠將內容儲存在任何支持的檔案系統中。 java.io.File 已無法直接代表使用這項支援的資源。

所需的動作:舊的 IResource.getLocation() 方法會傳回資源的本端檔案系統路徑。 如果資源不是儲存在本端檔案系統中,這個方法會傳回空值。 getLocation() 的大部分呼叫端先前都這麼做,以便取得 java.io.File 的實例,但這個實例已無法用在本端檔案系統所未儲存的資源上。

新的 org.eclipse.core.filesystem 外掛程式提供了一般的檔案系統 API,以便取代 java.io.File。 尤其是,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 中,檔案的大部分資訊都儲存在藉由呼叫 IFileStore.fetchInfo() 來取得,稱為 IFileInfo 的結構中。 這項設計可讓您利用 java.io.File 來進行更大規模的程式碼最佳化,許多關於檔案的屬性,通常都可以利用單一檔案系統呼叫來取得。 請注意,如果基礎檔案有了改變,IFileInfo 中的資訊會成為太舊,因此,只應在必要之時,才保持實例。 以下是在 java.io.File 上的一些方法,它們在 IFileInfo 上有對等的方法:

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 = ...;//某個檔案儲存庫
   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 = ...;//某個檔案儲存庫
   //看它是否能夠直接以本端檔案來表示
   java.io.File local = store.toLocalFile(EFS.NONE, null);
   //如果不能,便要求檔案的快取本端副本
   if (local == null)
      local = store.toLocalFile(EFS.CACHE, null);

請注意,在取得檔案的快取副本卜之後,它不會與原來的實際檔案系統保持同步。 修改快取的副本,並不會造成修改基礎檔案。

溫和失敗

無法處理本端檔案系統外之資源的用戶端,仍可能想改寫程式碼,使失敗顯得溫和一些。 用戶端可以檢查資源是否在本端檔案系統中,當發現它們無法處理的資源時,便忽略資源,或向使用者發出警示。 如果要判斷資源是否在本端檔案系統中,您必須瞭解它的檔案系統架構。 您可以依照下列方式,從資源取得這項資訊:

   IResource resource = ...;//某項資源
   URI uri = resource.getLocationURI();
   if (uri != null && EFS.SCHEME_LOCAL.equals(uri.getScheme())) {
      //檔案在本端檔案系統中
   } else {
      //檔案不在本端檔案系統中
   }

如果您有現成的 IFileStore 實例,您可以依照下列方式來取得架構:

   IFileStore 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.start(),而是利用 Bundle.loadClass() 來從必須啟動的軟體組載入類別。

5. 在外掛程式版本號碼中,底線已不再更換為連字號

在 Eclipse 3.0 中,既不支援,也不強制在版本 ID 限定元區段使用底線 ('_') 字元。 如果外掛程式版本 ID 的限定元包含底線,當外掛程式匯出到檔案系統中,以及從更新網站安裝外掛程式時,這個字元都會轉換成連字號 ('-')。
在 Eclipse 3.1 中,放寬了限定元容許字元的規則,併入了底線字元,因此,當匯出或安裝不適當的外掛程式時,不會修改限定元的原始狀態。 3.0 至 3.1 的移轉手冊遺漏了這項細緻的變更。 對於 Eclipse 3.2,我們仍在維護與 Eclipse 3.1 的相容性,當處理舊的外掛程式版本時(匯出之時,以及它們存在於更新網站之時),版本限定元含有底線字元的外掛程式應該知道前面提到的變更。 這表示,例如,當外掛程式提供者有舊版的外掛程式在更新網站中,便應該確定檔案系統中的名稱符合外掛程式的名稱。