chairbender
chairbender

Reputation: 849

Eclipse Plug In: IDE.openEditor throws IllegalArgumentException

I'm writing an Eclipse plugin. It runs a code analysis on Java code and, using a ListViewer, reports lines of code that violate certain criteria. When somebody selects one of those lines in the listviewer, I want to open the Eclipse Java file editor to that file and go to that line. The way the analysis works, each violation has a field holding the file that the violation occurs in as a standard java.io.File. So, I need to turn this into an IFile so I can open it in the Eclipse Java editor.

Here's most of the code that runs when the user clicks one of the lines in the listviewer. Violation is the class I made to represent a specific line of Java code that violates some criteria:

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);
}

Running this, I get IllegalArgumentException on the line that invokes IDE.openEditor (which corresponds to CalisthenicsView.java:75):

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)

I've looked at the line of source code that throws this in FileEditorInput.java:218. Apparently it does this (where "file" is the same as "toOpen" in the first code block):

 final URI locationURI = file.getLocationURI();
 if (locationURI == null)
   throw new IllegalArgumentException();

To me, it seems like .getFile(path) is returning an IFile that doesn't have a locationURI, for some reason. I don't know why.

Is there a way to fix this? Is there a different way I can accomplish this (opening a Java editor to a specific line of a specific file)? Keep in mind that I don't have access to an IProject, since this analysis can be run on any project in the workspace or even the entire workspace.

EDIT: Another thing I don't understand is the code that's trying to invoke FileEditorInput.getPaht(). Looking at WorkbenchPage.busyOpenEditor on line 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;
    }

This is the code that invokes FileEditorInput.getPath(). Apparently it is trying to open something called an "external editor", which sounds like it's not what I want it to do. I just want to open the default Java source code editor. This sounds like it's trying to open something else.

Also, I wanted to add that the .toString() value of toOpen (the IFile I'm trying to open) is: L/Programming/runtime-New_configuration/slackbot-resistance/src/main/java/com/chairbender/slackbot/resistance/ResistanceBot.java

...so it's definitely not null or invalid and I would assume Eclipse knows it's a Java file.

Upvotes: 3

Views: 820

Answers (2)

chairbender
chairbender

Reputation: 849

This problem was due to me not understanding the documentation for ResourcesPlugin.getWorkspace().getRoot().getFile(path). It says "The supplied path may be absolute or relative; in either case, it is interpreted as relative to this resource and is appended", which kind of confused me. How can an absolute path be interpreted as relative to anything? If I pass it an absolute path, why doesn't it just make that path relative to the workspace by checking if the workspace path is at the start of the passed absolute path? I expected the method to behave more intelligently.

The following worked for me. I had to convert the absolute path from my java.io.File into a relative path by chopping off the part of the path corresponding to the workspace, using the IPath.makeRelativeTo method:

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

The suggestion to use getFileForLocation instead of getFile didn't work. That method always returned null for me regardless of whether the path was relative or absolute. I think it's broken.

Upvotes: 0

greg-449
greg-449

Reputation: 111142

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

You appear to be passing an absolute file path to the getFile method. The JavaDoc for this says:

This is a resource handle operation; neither the resource nor the result need exist in the workspace. The validation check on the resource name/path is not done when the resource handle is constructed; rather, it is done automatically as the resource is created.

The supplied path may be absolute or relative; in either case, it is interpreted as relative to this resource and is appended to this container's full path to form the full path of the resultant resource. A trailing separator is ignored. The path of the resulting resource must have at least two segments.

So the path is interpreted as relative to the current workspace (that is your test workspace not your development workspace). No test is done to see if the file actually exists.

The exception inside IDE.openEditor is because the IFile does not appear to be in a valid project in the workspace. This is also why it is trying to open an external editor.

If you want to open a file which is not in the workspace you need to use an IURIEditorInput as implemented by FileStoreEditorInput:

IFileStore store = EFS.getStore(file.toURI());

IEditorInput input = new FileStoreEditorInput(store);

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

Note: Some editors don't support files which are not in the workspace, others may have reduced functionality.

The editor id for the Java editor is given by JavaUI.ID_CU_EDITOR ("org.eclipse.jdt.ui.CompilationUnitEditor")

If you have a file which is in the workspace but you only have the absolute path of the file use IWorkspaceRoot.getFileForLocation:

IFile toOpen = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path);

Note: This will return null if the IFile cannot be found.

Upvotes: 2

Related Questions