diff options
author | Fred Bricon | 2018-02-22 23:49:41 +0000 |
---|---|---|
committer | Fred Bricon | 2018-03-13 22:14:46 +0000 |
commit | e671e63165d6de3bfd39c455fbf6f5600cb989eb (patch) | |
tree | 87da0c3f586f380e5d4756c4365ac75945469d2c | |
parent | 34867d6eecf3cc1a44aa14021f88ba95b55efb96 (diff) | |
download | m2e-core-e671e63165d6de3bfd39c455fbf6f5600cb989eb.tar.gz m2e-core-e671e63165d6de3bfd39c455fbf6f5600cb989eb.tar.xz m2e-core-e671e63165d6de3bfd39c455fbf6f5600cb989eb.zip |
Bug 531280 : update classpath on module-info.java changes
Change-Id: Ifc524dee7ef516f0bf7e6bd024fb00372ffb46ca
Signed-off-by: Fred Bricon <fbricon@gmail.com>
6 files changed, 153 insertions, 17 deletions
diff --git a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/MavenJdtPlugin.java b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/MavenJdtPlugin.java index 59cfd023..cc21a0d7 100644 --- a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/MavenJdtPlugin.java +++ b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/MavenJdtPlugin.java @@ -97,7 +97,8 @@ public class MavenJdtPlugin extends Plugin { File stateLocationDir = getStateLocation().toFile(); this.buildpathManager = new BuildPathManager(projectManager, indexManager, bundleContext, stateLocationDir); - workspace.addResourceChangeListener(buildpathManager, IResourceChangeEvent.PRE_DELETE); + workspace.addResourceChangeListener(buildpathManager, + IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.POST_CHANGE); projectManager.addMavenProjectChangedListener(this.buildpathManager); diff --git a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/BuildPathManager.java b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/BuildPathManager.java index 19790d2a..2667cad9 100644 --- a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/BuildPathManager.java +++ b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/BuildPathManager.java @@ -32,6 +32,8 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -43,7 +45,10 @@ import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; @@ -51,12 +56,14 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.core.IClasspathAttribute; import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaModel; import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IModuleDescription; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; @@ -130,6 +137,8 @@ public class BuildPathManager implements IMavenProjectChangedListener, IResource final File stateLocationDir; + final Map<String, Set<String>> requiredModulesMap = new ConcurrentHashMap<String, Set<String>>(); + private final DownloadSourcesJob downloadSourcesJob; private final DefaultClasspathManagerDelegate defaultDelegate; @@ -589,16 +598,90 @@ public class BuildPathManager implements IMavenProjectChangedListener, IResource int type = event.getType(); if(IResourceChangeEvent.PRE_DELETE == type) { // remove custom source and javadoc configuration - File attachmentProperties = getSourceAttachmentPropertiesFile((IProject) event.getResource()); + IProject project = (IProject) event.getResource(); + File attachmentProperties = getSourceAttachmentPropertiesFile(project); if(attachmentProperties.exists() && !attachmentProperties.delete()) { log.error("Can't delete " + attachmentProperties.getAbsolutePath()); //$NON-NLS-1$ } // remove classpath container state - File containerState = getContainerStateFile((IProject) event.getResource()); + File containerState = getContainerStateFile(project); if(containerState.exists() && !containerState.delete()) { log.error("Can't delete " + containerState.getAbsolutePath()); //$NON-NLS-1$ } + + requiredModulesMap.remove(project.getLocation().toString()); + + } else if(IResourceChangeEvent.POST_CHANGE == type) { + + IResourceDelta delta = event.getDelta(); // workspace delta + IResourceDelta[] resourceDeltas = delta.getAffectedChildren(); + final Set<IProject> affectedProjects = new LinkedHashSet<IProject>(resourceDeltas.length); + ModuleInfoDetector visitor = new ModuleInfoDetector(affectedProjects); + for(IResourceDelta d : resourceDeltas) { + IProject project = (IProject) d.getResource(); + if(!ModuleSupport.isMavenJavaProject(project)) { + continue; + } + try { + d.accept(visitor, false); + } catch(CoreException ex) { + log.error(ex.getMessage(), ex); + } + } + if(affectedProjects.isEmpty()) { + return; + } + + Job job = new WorkspaceJob(Messages.BuildPathManager_update_module_path_job_name) { + @Override + public IStatus runInWorkspace(IProgressMonitor monitor) { + SubMonitor subMonitor = SubMonitor.convert(monitor, affectedProjects.size()); + for(IProject p : affectedProjects) { + if(monitor.isCanceled()) { + return Status.CANCEL_STATUS; + } + if(requiresUpdate(p, subMonitor)) { + monitor.setTaskName(p.getName()); + updateClasspath(p, subMonitor.newChild(1)); + } + } + return Status.OK_STATUS; + } + + private boolean requiresUpdate(IProject p, IProgressMonitor monitor) { + if(!ModuleSupport.isMavenJavaProject(p)) { + return false; + } + + IJavaProject jp = JavaCore.create(p); + try { + IModuleDescription moduleDescription = jp.getModuleDescription(); + if(moduleDescription == null) { + return false; + } + String location = p.getLocation().toString(); + Set<String> requiredModules = new TreeSet<>(ModuleSupport.getRequiredModules(jp, monitor)); + if(monitor.isCanceled()) { + return false; + } + // Probably not the best way to detect if module path has changed, like, on the very 1st time a + // module-info.java is modified, there will be no previous state to compare to, but should work + // well enough the rest of the time, for cases that don't involve obscure module path configs + Set<String> oldRequiredModules = requiredModulesMap.get(location); + if(requiredModules.equals(oldRequiredModules)) { + return false; + } + requiredModulesMap.put(location, requiredModules); + return true; + } catch(JavaModelException ex) { + log.error(ex.getMessage(), ex); + } + return false; + } + }; + job.setRule(MavenPlugin.getProjectConfigurationManager().getRule()); + job.schedule(); } } @@ -860,4 +943,25 @@ public class BuildPathManager implements IMavenProjectChangedListener, IResource log.error(e.getMessage(), e); } } + + static class ModuleInfoDetector implements IResourceDeltaVisitor { + + private Collection<IProject> affectedProjects; + + public ModuleInfoDetector(Collection<IProject> affectedProjects) { + this.affectedProjects = affectedProjects; + } + + public boolean visit(IResourceDelta delta) { + if(delta.getResource() instanceof IFile) { + IFile file = (IFile) delta.getResource(); + if(ModuleSupport.MODULE_INFO_JAVA.equals(file.getName())) { + affectedProjects.add(file.getProject()); + } + return false; + } + return true; + } + + } } diff --git a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/InternalModuleSupport.java b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/InternalModuleSupport.java index c0da59c1..1e4f9310 100644 --- a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/InternalModuleSupport.java +++ b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/InternalModuleSupport.java @@ -110,7 +110,7 @@ class InternalModuleSupport { if(monitor.isCanceled()) { return; } - String moduleName = getModuleName(entry, monitor); + String moduleName = getModuleName(entry.getEntryKind(), entry.getPath(), monitor); moduleMap.put(moduleName, entry);//potentially suppresses duplicate entries from the same workspace project, with different classifiers descriptorsMap.put(entry, moduleName); } @@ -163,12 +163,12 @@ class InternalModuleSupport { return Collections.emptySet(); } - private static Set<String> getRequiredModules(IJavaProject project, IProgressMonitor monitor) + public static Set<String> getRequiredModules(IJavaProject project, IProgressMonitor monitor) throws JavaModelException { IModuleDescription moduleDescription = project.getModuleDescription(); if(moduleDescription != null) { String[] reqModules = JavaModelAccess.getRequiredModules(moduleDescription); - return new LinkedHashSet<>(Arrays.asList(reqModules)); + return Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(reqModules))); } return Collections.emptySet(); } @@ -196,13 +196,13 @@ class InternalModuleSupport { return Collections.emptySet(); } - private static String getModuleName(IClasspathEntryDescriptor entry, IProgressMonitor monitor) { + public static String getModuleName(int entryKind, IPath entryPath, IProgressMonitor monitor) { String module = null; - if(entry != null) { - if(IClasspathEntry.CPE_LIBRARY == entry.getEntryKind()) { - module = getModuleName(entry.getPath().toFile()); - } else if(IClasspathEntry.CPE_PROJECT == entry.getEntryKind()) { - module = getModuleName(getJavaProject(entry.getPath()), monitor); + if(entryPath != null) { + if(IClasspathEntry.CPE_LIBRARY == entryKind) { + module = getModuleName(entryPath.toFile()); + } else if(IClasspathEntry.CPE_PROJECT == entryKind) { + module = getModuleName(getJavaProject(entryPath), monitor); } } return module; @@ -271,11 +271,13 @@ class InternalModuleSupport { return new String(moduleName); } - public static int determineModularClasspathProperty(IClasspathEntry entry) { + public static boolean isModuleEntry(IClasspathEntry entry) { return Arrays.stream(entry.getExtraAttributes()) - .anyMatch(p -> p.getName().equals(IClasspathAttribute.MODULE) && "true".equals(p.getValue())) - ? IRuntimeClasspathEntry.MODULE_PATH - : IRuntimeClasspathEntry.CLASS_PATH; + .anyMatch(p -> IClasspathAttribute.MODULE.equals(p.getName()) && "true".equals(p.getValue())); + } + + public static int determineModularClasspathProperty(IClasspathEntry entry) { + return isModuleEntry(entry) ? IRuntimeClasspathEntry.MODULE_PATH : IRuntimeClasspathEntry.CLASS_PATH; } public static IRuntimeClasspathEntry createRuntimeClasspathEntry(IFolder folder, int classpathProperty, diff --git a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/Messages.java b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/Messages.java index 21e89cf9..be0c754e 100644 --- a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/Messages.java +++ b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/Messages.java @@ -26,6 +26,8 @@ public class Messages extends NLS { public static String BuildPathManager_monitor_setting_cp; + public static String BuildPathManager_update_module_path_job_name; + public static String DownloadSourcesJob_job_download; public static String MavenClasspathContainer_description; diff --git a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/ModuleSupport.java b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/ModuleSupport.java index 33672823..387a4af7 100644 --- a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/ModuleSupport.java +++ b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/ModuleSupport.java @@ -11,6 +11,11 @@ package org.eclipse.m2e.jdt.internal; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; @@ -18,9 +23,12 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.launching.IRuntimeClasspathEntry; import org.eclipse.jdt.launching.JavaRuntime; +import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.jdt.IClasspathDescriptor; @@ -33,10 +41,14 @@ import org.eclipse.m2e.jdt.IClasspathDescriptor; */ public class ModuleSupport { + public static final String MODULE_INFO_JAVA = "module-info.java"; + static final boolean IS_MODULE_SUPPORT_AVAILABLE; static final boolean IS_PATCH_MODULE_SUPPORT_AVAILABLE; + private static final Logger log = LoggerFactory.getLogger(ModuleSupport.class); + static { boolean isModuleSupportAvailable = false; boolean isPatchModuleSupportAvailable = false; @@ -64,7 +76,7 @@ public class ModuleSupport { */ public static void configureClasspath(IMavenProjectFacade facade, IClasspathDescriptor classpath, IProgressMonitor monitor) throws CoreException { - if(!IS_MODULE_SUPPORT_AVAILABLE) { + if(!IS_MODULE_SUPPORT_AVAILABLE || classpath == null) { return; } InternalModuleSupport.configureClasspath(facade, classpath, monitor); @@ -105,4 +117,18 @@ public class ModuleSupport { } return InternalModuleSupport.newModularProjectRuntimeClasspathEntry(javaProject); } + + public static boolean isMavenJavaProject(IProject project) { + try { + return project != null && project.isOpen() && project.hasNature(IMavenConstants.NATURE_ID) + && project.hasNature(JavaCore.NATURE_ID); + } catch(CoreException ex) { + log.error(ex.getMessage(), ex); + } + return false; + } + + public static Set<String> getRequiredModules(IJavaProject jp, IProgressMonitor monitor) throws JavaModelException { + return InternalModuleSupport.getRequiredModules(jp, monitor); + } } diff --git a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/messages.properties b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/messages.properties index 676bcaf6..c058c84a 100644 --- a/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/messages.properties +++ b/org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/messages.properties @@ -1,5 +1,6 @@ AbstractJavaProjectConfigurator_task_name=Configuring java project BuildPathManager_monitor_setting_cp=Setting classpath containers +BuildPathManager_update_module_path_job_name=Updating module path DownloadSourcesJob_job_download=Download sources and javadoc MavenClasspathContainer_description=Maven Dependencies MavenClasspathContainerInitializer_error_cannot_persist=Can't persist classpath container |