Skip to content

Restore Type Hierarchy triggers rebuild #2305

@steffenschmitt1

Description

@steffenschmitt1

In org.eclipse.jdt.internal.ui.typehierarchy.TypeHierarchyViewPart.restoreState(IMemento), the Java model is accessed before it has been properly initialized. This premature access causes the affected ICompilationUnit to be compiled, which inadvertently triggers a rebuild of all dependent projects.

I implemented a prototype that delays accesses to the Java model, which resolves the rebuild issue. However, I have two open questions:

  1. How can I reliably check if the Java model is initialized, without risking deadlocks or freezes? My current approach avoids the rebuild, but I'm unsure what the canonical or safest check is. Is there a recommended way to ensure the model is ready before accessing it?

Probably just add a waitForInitialization method to JavaCore?

  1. How can I retrieve the label shown in the Type Hierarchy view for the type to be resolved?
	private void restoreState(final IMemento memento) {
		List<String> ids = new ArrayList<>();

		String elementId= memento.getString(TAG_INPUT);
		int i= 0;
		while (elementId != null) {
			ids.add(elementId);
			elementId= memento.getString(TAG_INPUT + ++i);
		}

		if (ids.isEmpty()) {
			doRestoreState(memento, new IJavaElement[0]);
		} else {
			synchronized (this) {

				String label= Messages.format(TypeHierarchyMessages.TypeHierarchyViewPart_restoreinput, resolveLabels(ids));
				fNoHierarchyShownLabel.setText(label);

				fRestoreStateJob= new Job(label) {
					@Override
					protected IStatus run(IProgressMonitor monitor) {
						try {
							while(!JavaCore.INITIALIZED) {
								try {
									Thread.sleep(100);
								} catch (InterruptedException e) {
									Thread.currentThread().interrupt();
								}
							}
							final IJavaElement[] hierarchyInput= ids.stream().map(JavaCore::create).filter(IJavaElement::exists).toArray(length -> new IJavaElement[length]);
							if(hierarchyInput.length == 0) {
								doRestoreState(memento, new IJavaElement[0]);
							} else {
								doRestoreInBackground(memento, hierarchyInput, monitor);
							}
						} catch (JavaModelException e) {
							return e.getStatus();
						} catch (OperationCanceledException e) {
							if (fRestoreJobCanceledExplicitly) {
								showEmptyViewer();
							}
							return Status.CANCEL_STATUS;
						}
						return Status.OK_STATUS;
					}
				};
				fRestoreStateJob.schedule();
			}
		}
	}

	private String resolveLabels(List<String> ids) {
 		switch (ids.size()) {
			case 0:
				throw new IllegalArgumentException();
			case 1:
				return Messages.format(TypeHierarchyMessages.HistoryAction_inputElements_1,
						new String[] { resolveLabel(ids.get(0)) });
			case 2:
				return Messages.format(TypeHierarchyMessages.HistoryAction_inputElements_2,
						new String[] { resolveLabel(ids.get(0)), resolveLabel(ids.get(1)) });
			default:
				return Messages.format(TypeHierarchyMessages.HistoryAction_inputElements_more,
						new String[] { resolveLabel(ids.get(0)), resolveLabel(ids.get(1)), resolveLabel(ids.get(2)) });
		}
	}

	private String resolveLabel(String id) {
		String packageName = "notFound"; //$NON-NLS-1$
		String typeName = "notFound"; //$NON-NLS-1$

		if(id != null && id.contains("[")) { //$NON-NLS-1$
			String[] splitType = id.split("\\["); //$NON-NLS-1$
			typeName = splitType[1];
			if(splitType[0].contains("<")) { //$NON-NLS-1$
				String[] splitBundle  = splitType[0].split("<"); //$NON-NLS-1$
				if(splitBundle[1].contains("{")) { //$NON-NLS-1$
					packageName = splitBundle[1].split("\\{")[0]; //$NON-NLS-1$
				}
			}
		}
		return packageName + "." + typeName; //$NON-NLS-1$
	}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions