Help us understand the problem. What is going on with this article?

[Eclipseプラグイン開発] Resource関連

More than 5 years have passed since last update.

目的

  • Eclipseプラグインに関連する知識を(自分的に)再整理したい
  • 主にResource関連について整理する
  • 関連する主なプラグインは
    • プラグインID : org.eclipse.core.resources
    • プラグイン本体 : ResourcesPlugin
  • 環境は Eclipse 4.5 (3.2 以降ならあまり変わらないはず)

要素

Eclipse は Java をはじめとしたさまざまな言語の開発環境をサポートしています。また開発環境以外の目的で使われることもあります。
そしてそれぞれ用の独自のプロジェクトなどがあります。

IResource があらわすのは、特定の開発環境やプロジェクトなどに依存しない、共通的なリソース(ファイルやフォルダ、汎用的なプロジェクトなど)です。

IResource

IResource は、Eclipse で管理しているリソース(ファイルやフォルダ)をあらわすインタフェースです。
逆に言えば、Eclipse が管理していないファイルやフォルダを表すことはできません。

また IResource は、これから作られるリソースを示すこともあります。つまり IResource のオブジェクトはあっても、それが指し示す実体のファイルやフォルダがまだ作られていないことがあります。
(java.io.File を new したからといって、ファイルができるわけでは無いことと同じです)

表す対象に応じて、以下のインタフェースが用意されています。
また、子を持つインタフェースは IContainer も拡張しています。

インタフェース名 説明 IContainer の拡張
IWorkspaceRoot ワークスペース
IProject プロジェクト
IFolder フォルダ
IFile ファイル ×

IContainer

ワークスペース、プロジェクト、フォルダなどの「子要素を持つことのできるリソース」を表します。

子要素は IContainer#findMember()IContainer#members() などで取得することができます。

IWorkspaceRoot

Eclipse のワークベンチは、1つのワークスペースを対象としています。

ワークスペースを表すクラスは2種類あり、1つは IWorkspaceRoot であり、もう1つは IWorkspace です。

位置づけ的に IWorkspace がワークスペースの「機能的」側面を表しており、 IWorkspaceRoot はワークスペースの「リソース的」側面を表すものだと思います(たぶん)。

IWorkspaceResourcesPlugin#getWorkspace() から取得できます。
IWorkspaceRootIWorkspace#getRoot() から取得することができます。

IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot workspaceRoot = workspace.getRoot();

また IResource は自分の属する IWorkspace を覚えており、 IResource#getWorkspace() で取得することもできます。

IProject

ワークスペース内には複数のプロジェクトを持つことができます。

IWorkspaceRoot#getProjects() ですべてのプロジェクトを取得できます。
名前がわかっていれば IWorkspaceRoot#getProject(String) でプロジェクトを取得することができます。

また IResource は自分の属する IProject を覚えていますので IResource#getProject() で取得することができます。

IFolder

フォルダを表します。フォルダ内にはサブフォルダやファイルを持つことができます。

フォルダは、以下のメソッドなどで取得可能です。

  • IProject#getFolder(String)
  • IContainer#getFolder(IPath)
  • IContainer#findMember() - フォルダ以外のこともある
  • IResource#getParent() - フォルダ以外のこともある
  • その他、いろいろ

基本的にメソッド名が find から始まるものは、存在するリソースを見つけます。しかし getFolder() メソッドなどはフォルダが存在しなくても IFolder オブジェクトを返します。必要であれば create() メソッドで作成してください。

IFile

ファイルを表します。

以下のようなメソッドなどで取得できます。

  • IWorkspaceRoot#getFileForLocation(IPath)
  • IProject#getFile(String)
  • IContainer#getFile(IPath)
  • IContainer#findMember() - ファイル以外のこともある
  • その他、いろいろ

基本的にメソッド名が find から始まるものは、存在するファイルを見つけます。しかし getFile() メソッドなどはファイルが存在しなくても IFile オブジェクトを返してきます。
そのためファイルが存在する場合には更新、ファイルが存在しない場合にはファイルを新規作成といった判断が必要です。

try (InputStream in = new ByteArrayInputStream(bytes)) {
    IFile file = IFolder.getFile(name);
    if (file.exists()) {
        file.setContents(in, false, true, null);

    } else {
        file.create(in, false, null);
    }
}

IPath

リソースそのものを示すのは IResource ですが、リソースの場所を示すのは IPath です。
(正確には IPath は Eclipse で管理しているリソース以外も表せます)
IPath には相対パスや絶対パスがあります。

IResource のメソッドでいくつかの IPath を取得できます。

たとえば C:\Workspace にワークスペースがあるとして、Project project 内の data/file.txt のファイルの場合の取得例を示します。

メソッド名 取得できる内容 取得例
IResource#getFullPath() ワークスペースからの相対パス /project/data/file.txt
IResource#getProjectRelativePath() プロジェクトからの相対パス data/file.txt
IResource#getLocation() 絶対パス C:/Workspace/data/file.txt
IResource#getRawLocation() 絶対パス(リンク対応) (同上)

※文字列化は IPath#toPortableString() を使用した例です。
※プロジェクトはワークスペース直下にあることを想定しています。別の場所にあることもあるので注意してください。
getRawLocation() はリンクされたリソースの場合に異なる結果を返すことがあります。またリソースの種類によっては null を返すことがあります。

また IPath を文字列化する方法は以下のメソッドで可能です。

メソッド名 取得できる内容 取得例
IPath#toOSString() プラットフォーム個別パス C:\Workspace\data\file.txt
IPath#toPortableString() プラットフォーム共通パス C:/Workspace/data/file.txt
IPath#toString() 文字列化 (同上)

相対パスは IPath#append() などで結合した新しい IPath を作ることができます。元の IPath は書きかわらずに、新しいインスタンスが生成されます。

IPath projectPath = project.getLocation();
IPath newPath = projectPath.append("data/file2.txt");

また IPath の具象クラスとして org.eclipse.core.runtime.Path があります。

String pathName = "C:/Workspace/project/data/file3.txt";
IPath path = new Path(pathName);

IAdaptable

前述のとおり Eclipse には、独自の開発環境用のプロジェクトや、それ専用のリソースを表すクラスもあります。

例えば、Java の開発環境(Java development tools; JDT)では IResource の代わりに org.eclipse.jdt.core.IJavaElement というインタフェースでリソースを表します。
そして、プラグインで選択項目( org.eclipse.jface.viewers.IStructuredSelection )を取得したりすれば、それらを実装したクラスが返ってくることがあります。

もちろん IJavaElement から、共通のリソースである IResource に変換するメソッドはあります( IJavaElement#getCorrespondingResource() )。
そして JDT だけではなく他の開発環境などでも同じようなメソッドは用意されていると思います。

しかし、汎用的な「選択されたファイルの文字コードを変換する」というプラグインを作る際に、JDTやその他のプラグインのすべてのクラスに対応することは、現実的ではありません(プラグインの依存関係はどうする? 今後追加された別の開発環境用のクラスはどうする? など)。

そこで、Eclipse では IAdaptable というインタフェースを用意しています。

これは「指定のクラスに変換できるなら、変換したオブジェクトを返す」というメソッドが定義されたインタフェースです。

IAdaptable.java
package org.eclipse.core.runtime;

public interface IAdaptable {
    public <T> T getAdapter(Class<T> adapter);
}

これを使えば、未知のクラスであっても IResource に変換して扱うことができます。もちろん、そのオブジェクトが IResource に変換が可能な場合のみですが。

SampleHandler.java
public class SampleHandler extends AbstractHandler {

    @Override
    public Object execute(ExecutionEvent event) throws ExecutionException {
        ISelection selection = HandlerUtil.getCurrentSelection(event);
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection structuredSelection = (IStructuredSelection) selection;
            Iterator<?> iterator = structuredSelection.iterator();
            while (iterator.hasNext()) {
                Object value = iterator.next();
                if (value instanceof IAdaptable) {
                    IResource resource = ((IAdaptable) value).getAdapter(IResource.class);
                    // resource を使う処理
                }
            }
        }

        return null;
    }
}

【言い訳】
上記ソースを見ると IStructuredSelection を拡張forループでまわせば良いのにと思うかもしれません。
しかし IStructuredSelection はこんなメソッド名を持っているのに、なぜか Iterable になっていません。仕方が無いので愚直に Iterator を扱っています。
Java8 以降限定でよければ、メソッド参照を使って以下のように書くことは可能です。

for (Object value : (Iterable<?>) structuredSelection::iterator) {
    // ...
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away