7373import org .eclipse .ui .texteditor .ITextEditorActionConstants ;
7474
7575import org .eclipse .jdt .core .ClasspathContainerInitializer ;
76+ import org .eclipse .jdt .core .ElementChangedEvent ;
7677import org .eclipse .jdt .core .IClassFile ;
7778import org .eclipse .jdt .core .IClasspathAttribute ;
7879import org .eclipse .jdt .core .IClasspathContainer ;
7980import org .eclipse .jdt .core .IClasspathEntry ;
81+ import org .eclipse .jdt .core .IElementChangedListener ;
8082import org .eclipse .jdt .core .IJavaElement ;
8183import org .eclipse .jdt .core .IJavaModelStatusConstants ;
8284import org .eclipse .jdt .core .IJavaProject ;
8385import org .eclipse .jdt .core .IOrdinaryClassFile ;
8486import org .eclipse .jdt .core .IPackageFragmentRoot ;
87+ import org .eclipse .jdt .core .ISourceReference ;
8588import org .eclipse .jdt .core .IType ;
8689import org .eclipse .jdt .core .JavaCore ;
8790import org .eclipse .jdt .core .JavaModelException ;
111114 * Java specific text editor.
112115 */
113116public 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 ) {
0 commit comments