From b0d7fdbd978f282e4b5e9fa7b75e9f8d86cdf24a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Wed, 23 Jul 2025 12:15:00 +0200 Subject: [PATCH] Update the project with an empty classpath container on initialize Currently there are some cases where an open JavaEditor is not updated, even though the build of the project is fine with that. Strange enough one can make it "work" by simply make some actions slower(!) e.g. setting breakpoints somewhere in the code that initialize classpath containers. The reason is that if initialize happens "too fast" it leads to missing classpath change notification because it looks like the saved to disk state is up-to-date with the new state and no event happens. This now set an empty intermediate container state to the JDT model so that any code arising at this point in time will see something has changed (from n > empty), and if then at any later time an update is performed from empty > n. --- .../core/RequiredPluginsInitializer.java | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsInitializer.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsInitializer.java index eb018e961d3..20022bc77bd 100644 --- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsInitializer.java +++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/RequiredPluginsInitializer.java @@ -27,6 +27,7 @@ import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.core.ClasspathContainerInitializer; import org.eclipse.jdt.core.IClasspathContainer; +import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; @@ -43,6 +44,30 @@ public class RequiredPluginsInitializer extends ClasspathContainerInitializer { private static final DeferredClasspathContainerInitializerJob deferredClasspathContainerInitializerJob = new DeferredClasspathContainerInitializerJob(); + private static final IClasspathContainer EMPTY_CLASSPATH_CONTAINER = new IClasspathContainer() { + + @Override + public IPath getPath() { + return PDECore.REQUIRED_PLUGINS_CONTAINER_PATH; + } + + @Override + public int getKind() { + return K_APPLICATION; + } + + @Override + public String getDescription() { + return PDECoreMessages.RequiredPluginsClasspathContainer_description; + } + + @Override + public IClasspathEntry[] getClasspathEntries() { + // nothing yet, will be updated soon + return new IClasspathEntry[0]; + } + }; + private static class DeferredClasspathContainerInitializerJob extends Job { private final Set projects = new LinkedHashSet<>(); @@ -86,10 +111,20 @@ public boolean belongsTo(Object family) { @Override public void initialize(IPath containerPath, IJavaProject javaProject) throws CoreException { if (Job.getJobManager().isSuspended()) { - // if the jobmanager is currently suspended we can't use the + // If the jobmanager is currently suspended we can't use the // schedule/join pattern here, instead we must retry the requested // action once jobs are enabled again, this will the possibly // trigger a rebuild if required or notify other listeners. + // + // Second as JDT is caching the container state, it might happens + // that the final results are the same and if PDE is too fast, it + // then happens that there is no delta event send to the model + // listeners leading to odd results. + // We explicitly set an empty classpath container here, so JDT will + // always see a delta when we later update the container to its + // final entries. + JavaCore.setClasspathContainer(PDECore.REQUIRED_PLUGINS_CONTAINER_PATH, new IJavaProject[] { javaProject }, + new IClasspathContainer[] { EMPTY_CLASSPATH_CONTAINER }, null); deferredClasspathContainerInitializerJob.initialize(javaProject); } else { setupClasspath(javaProject);