Eclipse插件:IDE.openEditor抛出IllegalArgumentException异常

3
我正在编写一个Eclipse插件。它对Java代码进行代码分析,并使用ListViewer报告违反某些标准的代码行。当有人在listviewer中选择其中一行时,我希望打开Eclipse Java文件编辑器并跳转到该行。代码分析的方式是,每个违规都有一个字段,保存违规发生的文件作为标准java.io.File。因此,我需要将其转换为IFile,以便在Eclipse Java编辑器中打开它。
以下是用户单击listviewer中的某行时运行的大部分代码。Violation是我创建的类,用于表示违反某些标准的特定Java代码行:
Violation selectedViolation = <I get this from the ListViewer> 
IPath path = new Path(violation.getSourceFile().getAbsolutePath());
IFile toOpen = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
IEditorPart editorPart =  PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
if (editorPart == null) {
    IWorkbenchPage curPage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
    editorPart = IDE.openEditor(curPage, toOpen, true);
}

运行此代码时,我在调用IDE.openEditor这一行(对应CalisthenicsView.java的第75行)时遇到了IllegalArgumentException异常。
at org.eclipse.ui.part.FileEditorInput.getPath(FileEditorInput.java:218)
at org.eclipse.ui.internal.WorkbenchPage.busyOpenEditor(WorkbenchPage.java:3163)
at org.eclipse.ui.internal.WorkbenchPage.access$25(WorkbenchPage.java:3149)
at org.eclipse.ui.internal.WorkbenchPage$10.run(WorkbenchPage.java:3131)
at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
at org.eclipse.ui.internal.WorkbenchPage.openEditor(WorkbenchPage.java:3126)
at org.eclipse.ui.internal.WorkbenchPage.openEditor(WorkbenchPage.java:3090)
at org.eclipse.ui.internal.WorkbenchPage.openEditor(WorkbenchPage.java:3080)
at org.eclipse.ui.ide.IDE.openEditor(IDE.java:541)
at org.eclipse.ui.ide.IDE.openEditor(IDE.java:500)
at com.chairbender.eclipse.object_calisthenics_analyzer.views.CalisthenicsView$1.selectionChanged(CalisthenicsView.java:75)

我已经查看了FileEditorInput.java的代码,并定位到抛出此错误的源代码行号为218。显然,该代码行执行以下操作(其中“file”与第一个代码块中的“toOpen”相同):
 final URI locationURI = file.getLocationURI();
 if (locationURI == null)
   throw new IllegalArgumentException();

对我来说,似乎.getFile(path)返回的是一个没有locationURI的IFile。我不知道为什么会这样。
有没有办法解决这个问题?是否有其他方法可以实现这一目标(打开Java编辑器到特定文件的特定行)?请注意,由于此分析可以在工作区中的任何项目甚至整个工作区上运行,因此我无法访问IProject。
编辑:我不理解的另一件事是试图调用FileEditorInput.getPaht()的代码。查看WorkbenchPage.busyOpenEditor的第3163行:
// Special handling for external editors (they have no tabs...)
    if ("org.eclipse.ui.systemExternalEditor".equals(editorId)) { //$NON-NLS-1$
        IPathEditorInput fileInput = getPathEditorInput(input);
        if (fileInput == null) {
            throw new PartInitException(WorkbenchMessages.EditorManager_systemEditorError);
        }

        String fullPath = fileInput.getPath().toOSString();
        Program.launch(fullPath);
        return null;
    }

这是调用FileEditorInput.getPath()的代码。显然它正在尝试打开称为“外部编辑器”的东西,这听起来不像我想要做的事情。我只想打开默认的Java源代码编辑器。这听起来像是它正在尝试打开其他东西。
另外,我想补充一下,toOpen(我要打开的IFile)的.toString()值是: L/Programming/runtime-New_configuration/slackbot-resistance/src/main/java/com/chairbender/slackbot/resistance/ResistanceBot.java
所以它绝对不是null或无效的,并且我会认为Eclipse知道它是一个Java文件。
2个回答

2
IPath path = new Path(violation.getSourceFile().getAbsolutePath());
IFile toOpen = ResourcesPlugin.getWorkspace().getRoot().getFile(path);

您似乎正在将绝对文件路径传递给getFile方法。JavaDoc中说:
这是一个资源句柄操作;资源和结果都不需要存在于工作区中。当构建资源句柄时,不会执行资源名称/路径的验证检查;相反,当资源被创建时,它会自动执行。提供的路径可以是绝对或相对路径;在任一情况下,它都被解释为相对于此资源,并附加到此容器的完整路径以形成结果资源的完整路径。尾随分隔符将被忽略。生成的资源的路径必须至少具有两个段。
因此,该路径被解释为相对于当前工作区(即您的测试工作区而不是开发工作区)。没有测试来查看文件是否实际存在。
IDE.openEditor中的异常是由于IFile似乎不在工作区中的有效项目中。这也是为什么它试图打开外部编辑器的原因。
如果要打开不在工作区中的文件,则需要使用IURIEditorInput,由FileStoreEditorInput实现。
IFileStore store = EFS.getStore(file.toURI());

IEditorInput input = new FileStoreEditorInput(store);

IDE.openEditor(page, input, "editor id", true);

注意:一些编辑器不支持不在工作区的文件,其他编辑器可能功能减弱。
Java编辑器的编辑器ID由JavaUI.ID_CU_EDITOR(“org.eclipse.jdt.ui.CompilationUnitEditor”)给出。
如果您有一个在工作区中但只有文件的绝对路径,请使用IWorkspaceRoot.getFileForLocation
IFile toOpen = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path);

注意:如果找不到IFile,则会返回null

实际上,那个文件在测试工作区中。工作区名称为New_configuration。我应该使用什么命令来打开工作区中的文件?我在想问题是否在于我正在传递一个绝对路径给getFile,正如你所指出的那样。所以我的问题是:当我知道它是工作区中的文件时,如何将Java.io.File转换为IFile? - chairbender
1
增加了使用getFileForLocation方法,通过绝对路径在工作空间中查找文件的功能。 - greg-449
我尝试了那个方法,getFileForLocation返回null。但是我知道文件是存在的。我的IPath(名为"path"的变量)的toString()是C:/Programming/runtime-New_configuration/slackbot-resistance/src/main/java/com/chairbender/slackbot/resistance/BotState.java,这个路径肯定存在,并且我可以在工作区的项目中看到那个java文件。我需要以某种方式实例化我的IPath吗(不使用绝对路径)? - chairbender
我所要做的就是通过使用.makeRelativeTo()方法,将路径转换为相对路径(相对于工作区根目录),并删除工作区部分。我认为getFileForLocation方法完全失效了。无论我传递绝对路径还是相对路径,它始终返回null,即使是对于一个非常简单的测试用例也是如此。 - chairbender
getFileForLocation 绝对可行。在核心 Eclipse 代码中至少有 10 处使用它。 - greg-449

0
这个问题是由于我没有理解ResourcesPlugin.getWorkspace().getRoot().getFile(path)的文档而引起的。它说:“提供的路径可以是绝对或相对的;在任何情况下,它都被解释为相对于此资源并被附加”,这有点让我困惑。一个绝对路径怎么可能被解释为相对于任何东西呢?如果我传递一个绝对路径,为什么它不会通过检查工作区路径是否在传递的绝对路径的开头来使该路径相对于工作区呢?我期望这个方法能更智能地处理。
以下方法对我有效。我必须将我的java.io.File的绝对路径转换为相对路径,通过使用IPath.makeRelativeTo方法去掉与工作区相对应的路径部分:
IPath path = new Path(violation.getSourceFile().getAbsolutePath());
IPath workspacePath = ResourcesPlugin.getWorkspace().getRoot().getLocation();
path = path.makeRelativeTo(workspacePath);
IFile toOpen = ResourcesPlugin.getWorkspace().getRoot().getFile(path);

建议使用getFileForLocation而不是getFile并没有起作用。无论路径是相对还是绝对,该方法始终返回null。我认为它是有问题的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接