Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFred Bricon2018-02-22 23:49:41 +0000
committerFred Bricon2018-03-13 22:14:46 +0000
commite671e63165d6de3bfd39c455fbf6f5600cb989eb (patch)
tree87da0c3f586f380e5d4756c4365ac75945469d2c
parent34867d6eecf3cc1a44aa14021f88ba95b55efb96 (diff)
downloadm2e-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>
-rw-r--r--org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/MavenJdtPlugin.java3
-rw-r--r--org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/BuildPathManager.java108
-rw-r--r--org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/InternalModuleSupport.java28
-rw-r--r--org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/Messages.java2
-rw-r--r--org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/ModuleSupport.java28
-rw-r--r--org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/messages.properties1
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

Back to the top