Skip to content

Commit 42e3c2b

Browse files
committed
Resolve classpath entries also against workspace root
That allows to have both absolute libraries as well as libraries contained in other projects. Also recreate classloader if the classpath of the project changed.
1 parent 7d17f91 commit 42e3c2b

File tree

27 files changed

+284
-13
lines changed

27 files changed

+284
-13
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ You should see 6 projects:
6464
### Debugging
6565
You can run eclipse with debugging enabled and connect to it via remote debugging:
6666

67-
eclipse -data workspace-directory -vmargs -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
67+
eclipse -data workspace-directory -vmargs -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000
6868

6969

7070
### Releasing and updating the official eclipse update site

net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/cmd/JavaProjectClassLoader.java

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44

55
package net.sourceforge.pmd.eclipse.runtime.cmd;
66

7+
import java.io.File;
78
import java.net.MalformedURLException;
89
import java.net.URL;
910
import java.net.URLClassLoader;
1011
import java.util.HashSet;
1112
import java.util.Set;
1213

14+
import org.eclipse.core.resources.IFile;
1315
import org.eclipse.core.resources.IProject;
16+
import org.eclipse.core.resources.IWorkspace;
1417
import org.eclipse.core.runtime.CoreException;
1518
import org.eclipse.core.runtime.IPath;
1619
import org.eclipse.jdt.core.IClasspathEntry;
@@ -20,14 +23,20 @@
2023
import org.slf4j.Logger;
2124
import org.slf4j.LoggerFactory;
2225

26+
import net.sourceforge.pmd.eclipse.core.internal.FileModificationUtil;
27+
2328
/**
2429
* This is a ClassLoader for the Build Path of an IJavaProject.
2530
*/
2631
public class JavaProjectClassLoader extends URLClassLoader {
2732
private static final Logger LOG = LoggerFactory.getLogger(JavaProjectClassLoader.class);
2833

34+
private final IJavaProject javaProject;
35+
private final long lastModTimestamp;
36+
private final IWorkspace workspace;
2937
private Set<IJavaProject> javaProjects = new HashSet<IJavaProject>();
3038

39+
3140
public JavaProjectClassLoader(ClassLoader parent, IProject project) {
3241
super(new URL[0], parent);
3342
try {
@@ -38,15 +47,27 @@ public JavaProjectClassLoader(ClassLoader parent, IProject project) {
3847
throw new IllegalArgumentException("The project " + project + " is not a java project", e);
3948
}
4049

41-
IJavaProject javaProject = JavaCore.create(project);
50+
workspace = project.getWorkspace();
51+
javaProject = JavaCore.create(project);
52+
lastModTimestamp = getClasspathModificationTimestamp();
4253
addURLs(javaProject, false);
4354

4455
// No longer need these things, drop references
4556
javaProjects = null;
4657
}
4758

48-
private static IProject projectFor(IJavaProject javaProject, IClasspathEntry classpathEntry) {
49-
return javaProject.getProject().getWorkspace().getRoot().getProject(classpathEntry.getPath().toString());
59+
public boolean isModified() {
60+
long newTimestamp = getClasspathModificationTimestamp();
61+
return newTimestamp != lastModTimestamp;
62+
}
63+
64+
private long getClasspathModificationTimestamp() {
65+
IFile classpathFile = javaProject.getProject().getFile(IJavaProject.CLASSPATH_FILE_NAME);
66+
return FileModificationUtil.getFileModificationTimestamp(classpathFile.getLocation().toFile());
67+
}
68+
69+
private IProject projectFor(IClasspathEntry classpathEntry) {
70+
return workspace.getRoot().getProject(classpathEntry.getPath().toString());
5071
}
5172

5273
private void addURLs(IJavaProject javaProject, boolean exportsOnly) {
@@ -70,7 +91,7 @@ private void addURLs(IJavaProject javaProject, boolean exportsOnly) {
7091

7192
// Recurse on projects
7293
case IClasspathEntry.CPE_PROJECT:
73-
IProject project = projectFor(javaProject, classpathEntry);
94+
IProject project = projectFor(classpathEntry);
7495
IJavaProject javaProj = JavaCore.create(project);
7596
if (javaProj != null) {
7697
addURLs(javaProj, true);
@@ -101,7 +122,7 @@ private void addURLs(IJavaProject javaProject, boolean exportsOnly) {
101122
}
102123
}
103124
} catch (JavaModelException e) {
104-
LOG.debug("MalformedURLException occurred: " + e.getLocalizedMessage(), e);
125+
LOG.warn("JavaModelException occurred: {}", e.getMessage(), e);
105126
}
106127
}
107128

@@ -111,10 +132,21 @@ private void addURL(IClasspathEntry classpathEntry) {
111132

112133
private void addURL(IPath path) {
113134
try {
114-
URL url = path.toFile().getAbsoluteFile().toURI().toURL();
115-
addURL(url);
135+
File absoluteFile = path.toFile().getAbsoluteFile();
136+
// if the file exists, it is already an absolute path
137+
if (!absoluteFile.exists()) {
138+
// if not, it might have been a workspace relative file reference
139+
absoluteFile = workspace.getRoot().getFile(path).getLocation().toFile().getAbsoluteFile();
140+
}
141+
if (absoluteFile.exists()) {
142+
URL url = absoluteFile.toURI().toURL();
143+
LOG.debug("auxclasspath: Adding url {}", url);
144+
addURL(url);
145+
} else {
146+
LOG.warn("auxclasspath: Resolved file {} does not exist and is ignored", absoluteFile);
147+
}
116148
} catch (MalformedURLException e) {
117-
LOG.debug("MalformedURLException occurred: " + e.getLocalizedMessage(), e);
149+
LOG.warn("MalformedURLException occurred: {}", e.getMessage(), e);
118150
}
119151
}
120152
}

net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/properties/impl/ProjectPropertiesImpl.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class ProjectPropertiesImpl implements IProjectProperties {
6666
private boolean fullBuildEnabled = true; // default in case didn't come from properties
6767
private Set<String> buildPathExcludePatterns = new HashSet<String>();
6868
private Set<String> buildPathIncludePatterns = new HashSet<String>();
69-
private ClassLoader auxclasspath;
69+
private JavaProjectClassLoader auxclasspath;
7070

7171
/**
7272
* The default constructor takes a project as an argument
@@ -495,6 +495,18 @@ public Set<String> getBuildPathIncludePatterns() {
495495
public ClassLoader getAuxClasspath() {
496496
try {
497497
if (project != null && project.hasNature(JavaCore.NATURE_ID)) {
498+
String projectName = project.getName();
499+
if (auxclasspath != null && auxclasspath.isModified()) {
500+
PMDPlugin.getDefault().logInformation("Classpath of project " + projectName
501+
+ " changed - recreating it.");
502+
try {
503+
auxclasspath.close();
504+
} catch (IOException e) {
505+
// ignored
506+
}
507+
auxclasspath = null;
508+
}
509+
498510
if (auxclasspath == null) {
499511
PMDPlugin.getDefault()
500512
.logInformation("Creating new auxclasspath class loader for project " + project.getName());

test-projects/.gitignore

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
eclipse*/
22
ws/
3-
!project*/.project
4-
!project*/.pmd
5-
!project*/.classpath
3+
!project**/.project
4+
!project**/.pmd
5+
!project**/.classpath
6+
!project**/.ruleset
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<classpath>
3+
<classpathentry kind="src" path="src"/>
4+
<classpathentry combineaccessrules="false" kind="src" path="/sample-lib2"/>
5+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
6+
<attributes>
7+
<attribute name="module" value="true"/>
8+
</attributes>
9+
</classpathentry>
10+
<classpathentry kind="lib" path="/sample-lib1/sample-lib1-v1.jar"/>
11+
<classpathentry kind="lib" path="/tmp/sample-lib3-v1.jar"/>
12+
<classpathentry kind="output" path="bin"/>
13+
</classpath>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/bin/
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<pmd>
3+
<useProjectRuleSet>true</useProjectRuleSet>
4+
<ruleSetFile>.ruleset</ruleSetFile>
5+
<includeDerivedFiles>false</includeDerivedFiles>
6+
<violationsAsErrors>true</violationsAsErrors>
7+
<fullBuildEnabled>true</fullBuildEnabled>
8+
</pmd>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>project6</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.jdt.core.javabuilder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
<buildCommand>
14+
<name>net.sourceforge.pmd.eclipse.plugin.pmdBuilder</name>
15+
<arguments>
16+
</arguments>
17+
</buildCommand>
18+
</buildSpec>
19+
<natures>
20+
<nature>org.eclipse.jdt.core.javanature</nature>
21+
<nature>net.sourceforge.pmd.eclipse.plugin.pmdNature</nature>
22+
</natures>
23+
</projectDescription>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ruleset xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
name="pmd-eclipse"
5+
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
6+
<description>PMD Plugin preferences rule set</description>
7+
8+
<rule ref="category/java/bestpractices.xml/MissingOverride"/>
9+
10+
</ruleset>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package project6;
2+
3+
import sample.lib1.MyInterface;
4+
5+
// MyInterface comes in through a jar dependency. The jar file can be created in project sample-lib1
6+
public class Sample1 implements MyInterface {
7+
8+
// missing override should be detected here. This only works, if sample-lib1-v1.jar is resolved correctly.
9+
public void bar(int i) {
10+
System.out.println("test");
11+
}
12+
}

0 commit comments

Comments
 (0)