Skip to content

Commit 35da3f9

Browse files
laeubiiloveeclipse
authored andcommitted
Restore original type from class file input in background
If ClassFileEditor is restored, underlined class file might be moved in the meantime (e.g. library on classpath changed version so the type is still there but the absolute class file path changed). To check if the type is still on the classpath of the project might freeze UI for some time, so move this check to a job. If the job is running very early on startup, project classpath might be not yet updated (see RequiredPluginsInitializer and UpdateClasspathsJob in PDE which initialize classpath container lazily). In the case the type is not found, listen to JDT model changes and refresh the input in case the project classpath is updated. Fixes #2245
1 parent 1f472d2 commit 35da3f9

4 files changed

Lines changed: 106 additions & 57 deletions

File tree

org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileDocumentProvider.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ public ClassFileDocumentProvider() {
209209
protected boolean setDocumentContent(IDocument document, IEditorInput editorInput, String encoding) throws CoreException {
210210
if (editorInput instanceof IClassFileEditorInput) {
211211
IClassFile classFile= ((IClassFileEditorInput) editorInput).getClassFile();
212-
String source= classFile.getSource();
212+
String source= getSourceIfPresent(classFile);
213213
if (source == null)
214214
source= ""; //$NON-NLS-1$
215215
document.set(source);
@@ -218,6 +218,15 @@ protected boolean setDocumentContent(IDocument document, IEditorInput editorInpu
218218
return super.setDocumentContent(document, editorInput, encoding);
219219
}
220220

221+
private String getSourceIfPresent(IClassFile classFile) {
222+
try {
223+
return classFile.getSource();
224+
} catch (JavaModelException e) {
225+
//Assume no source...
226+
return null;
227+
}
228+
}
229+
221230
/**
222231
* Creates an annotation model derived from the given class file editor input.
223232
*

org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileEditor.java

Lines changed: 89 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,18 @@
7373
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
7474

7575
import org.eclipse.jdt.core.ClasspathContainerInitializer;
76+
import org.eclipse.jdt.core.ElementChangedEvent;
7677
import org.eclipse.jdt.core.IClassFile;
7778
import org.eclipse.jdt.core.IClasspathAttribute;
7879
import org.eclipse.jdt.core.IClasspathContainer;
7980
import org.eclipse.jdt.core.IClasspathEntry;
81+
import org.eclipse.jdt.core.IElementChangedListener;
8082
import org.eclipse.jdt.core.IJavaElement;
8183
import org.eclipse.jdt.core.IJavaModelStatusConstants;
8284
import org.eclipse.jdt.core.IJavaProject;
8385
import org.eclipse.jdt.core.IOrdinaryClassFile;
8486
import org.eclipse.jdt.core.IPackageFragmentRoot;
87+
import org.eclipse.jdt.core.ISourceReference;
8588
import org.eclipse.jdt.core.IType;
8689
import org.eclipse.jdt.core.JavaCore;
8790
import org.eclipse.jdt.core.JavaModelException;
@@ -111,6 +114,75 @@
111114
* Java specific text editor.
112115
*/
113116
public class ClassFileEditor extends JavaEditor implements ClassFileDocumentProvider.InputChangeListener {
117+
118+
private final class LoadJob extends Job implements IElementChangedListener {
119+
private final IJavaElement fElement;
120+
private volatile boolean continueListening;
121+
122+
private LoadJob(IJavaElement element) {
123+
super("Restoring editor input for " + element.getElementName()); //$NON-NLS-1$
124+
fElement= element;
125+
}
126+
127+
@Override
128+
protected IStatus run(IProgressMonitor monitor) {
129+
try {
130+
if(monitor.isCanceled() || disposed) {
131+
continueListening = false;
132+
return Status.CANCEL_STATUS;
133+
}
134+
if (!(fElement instanceof IOrdinaryClassFile) || fElement.exists()) {
135+
return Status.OK_STATUS;
136+
}
137+
/*
138+
* Let's try to find the class file,
139+
* see https://bugs.eclipse.org/bugs/show_bug.cgi?id=83221
140+
*/
141+
IOrdinaryClassFile cf= (IOrdinaryClassFile)fElement;
142+
IType type= cf.getType();
143+
IJavaProject project= fElement.getJavaProject();
144+
if (project != null) {
145+
type= project.findType(type.getFullyQualifiedName());
146+
if (type != null) {
147+
continueListening = false;
148+
IJavaElement javaElement= type.getParent();
149+
IEditorInput editorInput= EditorUtility.getEditorInput(javaElement);
150+
PlatformUI.getWorkbench().getDisplay().asyncExec(() -> {
151+
if (!disposed) {
152+
setInput(editorInput);
153+
if(javaElement instanceof ISourceReference ref) {
154+
setBreadcrumbInput(ref);
155+
}
156+
}
157+
});
158+
} else {
159+
if (!continueListening) {
160+
continueListening= true;
161+
JavaCore.addElementChangedListener(this);
162+
}
163+
}
164+
}
165+
} catch (CoreException e) {
166+
return e.getStatus();
167+
} finally {
168+
if (!continueListening) {
169+
JavaCore.removeElementChangedListener(this);
170+
}
171+
}
172+
return Status.OK_STATUS;
173+
}
174+
175+
@Override
176+
public boolean belongsTo(Object family) {
177+
return family == ClassFileEditor.class;
178+
}
179+
180+
@Override
181+
public void elementChanged(ElementChangedEvent event) {
182+
schedule(100);
183+
}
184+
}
185+
114186
/**
115187
* A form to attach source to a class file.
116188
*/
@@ -409,7 +481,9 @@ private void updateCodeView(StyledText styledText, IClassFile classFile) {
409481
try {
410482
content= disassembler.disassemble(classFile.getBytes(), "\n", ClassFileBytesDisassembler.DETAILED); //$NON-NLS-1$
411483
} catch (JavaModelException ex) {
412-
JavaPlugin.log(ex.getStatus());
484+
if (!ex.isDoesNotExist()) {
485+
JavaPlugin.log(ex.getStatus());
486+
}
413487
} catch (ClassFormatException ex) {
414488
JavaPlugin.log(ex);
415489
}
@@ -511,6 +585,7 @@ private boolean isEqualInput(IEditorInput input1, IEditorInput input2) {
511585
* @since 3.3
512586
*/
513587
private StyledText fNoSourceTextWidget;
588+
private volatile boolean disposed;
514589

515590
/**
516591
* Default constructor.
@@ -644,21 +719,8 @@ public boolean isEditorInputReadOnly() {
644719
protected IEditorInput transformEditorInput(IEditorInput input) throws CoreException{
645720
if (input instanceof HandleEditorInput handle) {
646721
IJavaElement element= handle.getElement();
647-
if (!element.exists() && element instanceof IOrdinaryClassFile) {
648-
/*
649-
* Let's try to find the class file,
650-
* see https://bugs.eclipse.org/bugs/show_bug.cgi?id=83221
651-
*/
652-
IOrdinaryClassFile cf= (IOrdinaryClassFile)element;
653-
IType type= cf.getType();
654-
IJavaProject project= element.getJavaProject();
655-
if (project != null) {
656-
type= project.findType(type.getFullyQualifiedName());
657-
if (type == null)
658-
return null;
659-
element= type.getParent();
660-
}
661-
}
722+
LoadJob job= new LoadJob(element);
723+
job.schedule();
662724
input= EditorUtility.getEditorInput(element);
663725
}
664726
if (input instanceof IFileEditorInput) {
@@ -694,21 +756,6 @@ private void doSetInputCached(IEditorInput input) throws CoreException {
694756
message,
695757
null));
696758
}
697-
698-
JavaModelException e= probeInputForSource(input);
699-
if (e != null) {
700-
IClassFileEditorInput classFileEditorInput= (IClassFileEditorInput) input;
701-
IClassFile file= classFileEditorInput.getClassFile();
702-
IJavaProject javaProject= file.getJavaProject();
703-
if (!javaProject.exists() || !javaProject.isOnClasspath(file)) {
704-
throw new CoreException(JavaUIStatus.createError(
705-
IJavaModelStatusConstants.INVALID_RESOURCE,
706-
JavaEditorMessages.ClassFileEditor_error_classfile_not_on_classpath,
707-
null));
708-
}
709-
throw e;
710-
}
711-
712759
IDocumentProvider documentProvider= getDocumentProvider();
713760
if (documentProvider instanceof ClassFileDocumentProvider) {
714761
((ClassFileDocumentProvider) documentProvider).removeInputChangeListener(this);
@@ -799,23 +846,6 @@ private void createPartControlCached(Composite parent) {
799846
}
800847
}
801848

802-
private JavaModelException probeInputForSource(IEditorInput input) {
803-
if (input == null) {
804-
return null;
805-
}
806-
807-
IClassFileEditorInput classFileEditorInput= (IClassFileEditorInput) input;
808-
IClassFile file= classFileEditorInput.getClassFile();
809-
810-
try {
811-
file.getSourceRange();
812-
} catch (JavaModelException e) {
813-
return e;
814-
}
815-
816-
return null;
817-
}
818-
819849
/**
820850
* Checks if the class file input has no source attached. If so, a source attachment form is shown.
821851
*
@@ -836,7 +866,7 @@ private void verifyInput(IEditorInput input) throws JavaModelException {
836866
boolean wasUsingSourceCopyAction= fSourceCopyAction == getAction(ITextEditorActionConstants.COPY);
837867

838868
// show source attachment form if no source found
839-
if (file.getSourceRange() == null) {
869+
if (!hasSource(file)) {
840870
// dispose old source attachment form
841871
if (fSourceAttachmentForm != null) {
842872
fSourceAttachmentForm.dispose();
@@ -925,6 +955,15 @@ public void run() {
925955
}
926956
}
927957

958+
private static boolean hasSource(IClassFile file) {
959+
try {
960+
return file.getSourceRange() != null;
961+
} catch (JavaModelException e) {
962+
//assume no source then...
963+
return false;
964+
}
965+
}
966+
928967
/*
929968
* @see ClassFileDocumentProvider.InputChangeListener#inputChanged(IClassFileEditorInput)
930969
*/
@@ -973,6 +1012,7 @@ public void doOperation(int operation) {
9731012
*/
9741013
@Override
9751014
public void dispose() {
1015+
disposed = true;
9761016
// http://bugs.eclipse.org/bugs/show_bug.cgi?id=18510
9771017
IDocumentProvider documentProvider= getDocumentProvider();
9781018
if (documentProvider instanceof ClassFileDocumentProvider) {

org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/InternalClassFileEditorInput.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import java.io.IOException;
1919
import java.nio.file.Files;
2020

21-
import org.eclipse.core.runtime.CoreException;
2221
import org.eclipse.core.runtime.IPath;
2322
import org.eclipse.core.runtime.Path;
2423

@@ -45,7 +44,7 @@ public class InternalClassFileEditorInput implements IClassFileEditorInput, IPer
4544

4645
private IClassFile fClassFile;
4746

48-
private IPath fPath;
47+
private volatile IPath fPath;
4948

5049
public InternalClassFileEditorInput(IClassFile classFile) {
5150
fClassFile= classFile;
@@ -182,10 +181,12 @@ private static IPath writeToTempFile(IClassFile classFile) {
182181
return new Path(file.toString());
183182
} catch (IOException e) {
184183
JavaPlugin.log(e);
185-
} catch (CoreException e) {
186-
JavaPlugin.log(e.getStatus());
184+
} catch (JavaModelException ex) {
185+
if (!ex.isDoesNotExist()) {
186+
JavaPlugin.log(ex.getStatus());
187+
}
187188
}
188-
throw new IllegalArgumentException("Could not create temporary file."); //$NON-NLS-1$
189+
return IPath.EMPTY;
189190
}
190191

191192
}

org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,9 +1999,8 @@ private void hideBreadcrumb() {
19991999
/**
20002000
* Sets the breadcrumb input to the given element.
20012001
* @param element the element to use as input for the breadcrumb
2002-
* @since 3.4
20032002
*/
2004-
private void setBreadcrumbInput(ISourceReference element) {
2003+
protected void setBreadcrumbInput(ISourceReference element) {
20052004
if (fBreadcrumb == null)
20062005
return;
20072006

0 commit comments

Comments
 (0)