目的
- Eclipseプラグインに関連する知識を(自分的に)再整理したい
- 主にResource関連について整理する
- 関連する主なプラグインは
- プラグインID :
org.eclipse.core.resources
- プラグイン本体 :
ResourcesPlugin
- プラグインID :
- 環境は 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
はワークスペースの「リソース的」側面を表すものだと思います(たぶん)。
IWorkspace
は ResourcesPlugin#getWorkspace()
から取得できます。
IWorkspaceRoot
は IWorkspace#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
というインタフェースを用意しています。
これは「指定のクラスに変換できるなら、変換したオブジェクトを返す」というメソッドが定義されたインタフェースです。
package org.eclipse.core.runtime;
public interface IAdaptable {
public <T> T getAdapter(Class<T> adapter);
}
これを使えば、未知のクラスであっても IResource
に変換して扱うことができます。もちろん、そのオブジェクトが IResource
に変換が可能な場合のみですが。
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) {
// ...
}