Skip to content

Commit 60e66ff

Browse files
RoiSoleilHannesWell
authored andcommitted
Add ability to add source/resource folder outside of the project
Such source/resource folders outside of the project are made accessible using linked folder. Furthermore fix handling of absolute paths pointing to project-directory in AbstractJavaProjectConfigurator.getFolder().
1 parent 045f3cb commit 60e66ff

File tree

14 files changed

+191
-28
lines changed

14 files changed

+191
-28
lines changed

org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/M2EUtils.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.eclipse.core.resources.IFile;
2626
import org.eclipse.core.resources.IFolder;
2727
import org.eclipse.core.resources.IResource;
28-
import org.eclipse.core.resources.IResourceStatus;
2928
import org.eclipse.core.resources.ResourcesPlugin;
3029
import org.eclipse.core.runtime.CoreException;
3130
import org.eclipse.core.runtime.IPath;
@@ -47,13 +46,17 @@ public class M2EUtils {
4746
* @param monitor the progress monitor
4847
* @throws CoreException if creating the given <code>folder</code> or any of its parents fails.
4948
*/
50-
public static void createFolder(IFolder folder, boolean derived, IProgressMonitor monitor) throws CoreException {
49+
public static void createFolder(IContainer container, boolean derived, IProgressMonitor monitor)
50+
throws CoreException {
51+
if(!(container instanceof IFolder folder)) {
52+
return; // don't create projects
53+
}
5154
// Recurse until we find a parent folder which already exists.
5255
if(!folder.exists()) {
5356
IContainer parent = folder.getParent();
5457
// First, make sure that all parent folders exist.
5558
if(parent != null && !parent.exists()) {
56-
createFolder((IFolder) parent, false, monitor);
59+
createFolder(parent, false, monitor);
5760
}
5861
try {
5962
if(!folder.exists()) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import java.io.Serializable;
2+
3+
class A implements Serializable {
4+
5+
}

org.eclipse.m2e.jdt.tests/projects/add-source-resource/parent/src/main/resources/res.txt

Whitespace-only changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import java.io.Serializable;
2+
3+
class ATest implements Serializable {
4+
5+
}

org.eclipse.m2e.jdt.tests/projects/add-source-resource/parent/src/test/resources/test.txt

Whitespace-only changes.
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+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<groupId>foo.bar</groupId>
7+
<artifactId>add-source-resource</artifactId>
8+
<version>0.0.1-SNAPSHOT</version>
9+
<packaging>pom</packaging>
10+
<modules>
11+
<module>submoduleA</module>
12+
</modules>
13+
</project>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<groupId>foo.bar</groupId>
7+
<artifactId>submoduleA</artifactId>
8+
<version>0.0.1-SNAPSHOT</version>
9+
<build>
10+
<pluginManagement>
11+
<plugins>
12+
<plugin>
13+
<groupId>org.apache.maven.plugins</groupId>
14+
<artifactId>maven-compiler-plugin</artifactId>
15+
<version>3.10.1</version>
16+
</plugin>
17+
</plugins>
18+
</pluginManagement>
19+
<plugins>
20+
<plugin>
21+
<groupId>org.codehaus.mojo</groupId>
22+
<artifactId>build-helper-maven-plugin</artifactId>
23+
<executions>
24+
<execution>
25+
<id>java</id>
26+
<phase>generate-sources</phase>
27+
<goals>
28+
<goal>add-source</goal>
29+
</goals>
30+
<configuration>
31+
<sources>
32+
<source>../parent/src/main/java</source>
33+
</sources>
34+
</configuration>
35+
</execution>
36+
<execution>
37+
<id>test</id>
38+
<phase>generate-sources</phase>
39+
<goals>
40+
<goal>add-test-source</goal>
41+
</goals>
42+
<configuration>
43+
<sources>
44+
<source>../parent/src/test/java</source>
45+
</sources>
46+
</configuration>
47+
</execution>
48+
<execution>
49+
<id>resources</id>
50+
<phase>generate-resources</phase>
51+
<goals>
52+
<goal>add-resource</goal>
53+
</goals>
54+
<configuration>
55+
<resources>
56+
<resource>
57+
<directory>../parent/src/main/resources</directory>
58+
</resource>
59+
</resources>
60+
</configuration>
61+
</execution>
62+
<execution>
63+
<id>test-resources</id>
64+
<phase>generate-resources</phase>
65+
<goals>
66+
<goal>add-test-resource</goal>
67+
</goals>
68+
<configuration>
69+
<resources>
70+
<resource>
71+
<directory>../parent/src/test/resources</directory>
72+
</resource>
73+
</resources>
74+
</configuration>
75+
</execution>
76+
</executions>
77+
</plugin>
78+
</plugins>
79+
</build>
80+
</project>

org.eclipse.m2e.jdt.tests/src/org/eclipse/m2e/jdt/tests/JavaConfigurationTest.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import java.nio.file.Files;
2121
import java.nio.file.Path;
2222
import java.util.Arrays;
23+
import java.util.List;
24+
import java.util.Set;
2325
import java.util.function.Predicate;
2426

2527
import org.eclipse.core.resources.IFile;
@@ -29,12 +31,14 @@
2931
import org.eclipse.core.resources.IncrementalProjectBuilder;
3032
import org.eclipse.core.runtime.CoreException;
3133
import org.eclipse.core.runtime.FileLocator;
34+
import org.eclipse.core.runtime.IPath;
3235
import org.eclipse.jdt.core.IClasspathEntry;
3336
import org.eclipse.jdt.core.IJavaProject;
3437
import org.eclipse.jdt.core.JavaCore;
3538
import org.eclipse.jdt.core.JavaModelException;
3639
import org.eclipse.m2e.core.MavenPlugin;
3740
import org.eclipse.m2e.core.internal.preferences.MavenConfigurationImpl;
41+
import org.eclipse.m2e.core.project.ResolverConfiguration;
3842
import org.eclipse.m2e.tests.common.AbstractMavenProjectTestCase;
3943
import org.junit.Before;
4044
import org.junit.Test;
@@ -124,14 +128,39 @@ public void testSkipNone() throws CoreException, IOException, InterruptedExcepti
124128
assertEquals(1, classpathEntriesCount(project, TEST_RESOURCES));
125129
}
126130

127-
128131
@Test
129132
public void testComplianceVsEnablePreviewSettings() throws CoreException, IOException, InterruptedException {
130133
IJavaProject project = importResourceProject("/projects/compilerEnablePreviewSettings/pom.xml");
131134
assertEquals("11", project.getOption(JavaCore.COMPILER_COMPLIANCE, false));
132135
assertEquals(JavaCore.ENABLED, project.getOption(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, false));
133136
assertEquals(JavaCore.IGNORE, project.getOption(JavaCore.COMPILER_PB_REPORT_PREVIEW_FEATURES, false));
134137
}
138+
139+
@Test
140+
public void testAddSourceResource() throws CoreException, IOException, InterruptedException {
141+
File baseDir = new File(FileLocator
142+
.toFileURL(JavaConfigurationTest.class.getResource("/projects/add-source-resource/submoduleA/pom.xml"))
143+
.getFile()).getParentFile().getParentFile();
144+
waitForJobsToComplete();
145+
IProject project = importProjects(baseDir.getAbsolutePath(), new String[] { "submoduleA/pom.xml" },
146+
new ResolverConfiguration())[0];
147+
waitForJobsToComplete();
148+
IJavaProject javaProject = JavaCore.create(project);
149+
150+
List<String> srcEntryPaths = Arrays.stream(javaProject.getRawClasspath())
151+
.filter(cp -> IClasspathEntry.CPE_SOURCE == cp.getEntryKind()).filter(cp -> !cp.isTest())
152+
.map(IClasspathEntry::getPath).map(IPath::toString).toList();
153+
assertEquals(Set.of("/submoduleA/src/main/java", "/submoduleA/src/main/resources", //
154+
"/submoduleA/.._parent_src_main_java", "/submoduleA/.._parent_src_main_resources"),
155+
Set.copyOf(srcEntryPaths));
156+
List<String> testEntryPaths = Arrays.stream(javaProject.getRawClasspath())
157+
.filter(cp -> IClasspathEntry.CPE_SOURCE == cp.getEntryKind()).filter(cp -> cp.isTest())
158+
.map(IClasspathEntry::getPath).map(IPath::toString).toList();
159+
assertEquals(Set.of("/submoduleA/src/test/java", "/submoduleA/src/test/resources", //
160+
"/submoduleA/.._parent_src_test_java", "/submoduleA/.._parent_src_test_resources"),
161+
Set.copyOf(testEntryPaths));
162+
}
163+
135164
// --- utility methods ---
136165

137166
private static final Predicate<IClasspathEntry> TEST_SOURCES = cp -> cp.isTest()

org.eclipse.m2e.jdt/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
22
Bundle-ManifestVersion: 2
33
Bundle-Name: %Bundle-Name
44
Bundle-SymbolicName: org.eclipse.m2e.jdt;singleton:=true
5-
Bundle-Version: 2.3.3.qualifier
5+
Bundle-Version: 2.3.400.qualifier
66
Bundle-Localization: plugin
77
Export-Package: org.eclipse.m2e.jdt,
88
org.eclipse.m2e.jdt.internal;x-friends:="org.eclipse.m2e.jdt.ui",

org.eclipse.m2e.jdt/src/org/eclipse/m2e/jdt/internal/AbstractJavaProjectConfigurator.java

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
package org.eclipse.m2e.jdt.internal;
1515

1616
import java.io.File;
17+
import java.io.IOException;
18+
import java.nio.file.Files;
19+
import java.nio.file.Path;
1720
import java.util.ArrayList;
1821
import java.util.Collections;
1922
import java.util.HashMap;
@@ -30,9 +33,11 @@
3033
import org.eclipse.core.resources.IFolder;
3134
import org.eclipse.core.resources.IProject;
3235
import org.eclipse.core.resources.IResource;
36+
import org.eclipse.core.resources.ResourcesPlugin;
3337
import org.eclipse.core.runtime.CoreException;
3438
import org.eclipse.core.runtime.IPath;
3539
import org.eclipse.core.runtime.IProgressMonitor;
40+
import org.eclipse.core.runtime.QualifiedName;
3641
import org.eclipse.core.runtime.SubMonitor;
3742
import org.eclipse.jdt.core.IAccessRule;
3843
import org.eclipse.jdt.core.IClasspathAttribute;
@@ -134,6 +139,9 @@ public abstract class AbstractJavaProjectConfigurator extends AbstractProjectCon
134139

135140
protected static final String DEFAULT_COMPILER_LEVEL = "1.5"; //$NON-NLS-1$
136141

142+
private static final QualifiedName LINKED_MAVEN_RESOURCE = new QualifiedName(MavenJdtPlugin.PLUGIN_ID,
143+
"linkedSource");
144+
137145
@Override
138146
public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException {
139147
IProject project = request.mavenProjectFacade().getProject();
@@ -282,8 +290,8 @@ protected void addProjectSourceFolders(IClasspathDescriptor classpath, Map<Strin
282290
MavenProject mavenProject = request.mavenProject();
283291
IMavenProjectFacade projectFacade = request.mavenProjectFacade();
284292

285-
IFolder classes = getFolder(project, mavenProject.getBuild().getOutputDirectory());
286-
IFolder testClasses = getFolder(project, mavenProject.getBuild().getTestOutputDirectory());
293+
IContainer classes = getFolder(project, mavenProject.getBuild().getOutputDirectory());
294+
IContainer testClasses = getFolder(project, mavenProject.getBuild().getTestOutputDirectory());
287295

288296
M2EUtils.createFolder(classes, true, mon.newChild(1));
289297
M2EUtils.createFolder(testClasses, true, mon.newChild(1));
@@ -361,6 +369,9 @@ protected void addProjectSourceFolders(IClasspathDescriptor classpath, Map<Strin
361369
isTestResourcesSkipped.add(Boolean.FALSE);
362370
}
363371
}
372+
373+
cleanLinkedSourceDirs(project, monitor);
374+
364375
addSourceDirs(classpath, project, mavenProject.getCompileSourceRoots(), classes.getFullPath(), inclusion,
365376
exclusion, mainSourceEncoding, mon.newChild(1), false);
366377
addResourceDirs(classpath, project, mavenProject, mavenProject.getBuild().getResources(), classes.getFullPath(),
@@ -429,7 +440,7 @@ protected void addSourceDirs(IClasspathDescriptor classpath, IProject project, L
429440
boolean addTestFlag) throws CoreException {
430441

431442
for(String sourceRoot : sourceRoots) {
432-
IFolder sourceFolder = getFolder(project, sourceRoot);
443+
IContainer sourceFolder = getFolder(project, sourceRoot);
433444

434445
if(sourceFolder == null) {
435446
// this cannot actually happen, unless I misunderstand how project.getFolder works
@@ -468,6 +479,14 @@ protected void addSourceDirs(IClasspathDescriptor classpath, IProject project, L
468479

469480
}
470481

482+
private void cleanLinkedSourceDirs(IProject project, IProgressMonitor monitor) throws CoreException {
483+
for(IResource resource : project.members()) {
484+
if(resource instanceof IFolder && "true".equals(resource.getPersistentProperty(LINKED_MAVEN_RESOURCE))) {
485+
resource.delete(false, monitor);
486+
}
487+
}
488+
}
489+
471490
private IClasspathEntryDescriptor getEnclosingEntryDescriptor(IClasspathDescriptor classpath, IPath fullPath) {
472491
for(IClasspathEntryDescriptor cped : classpath.getEntryDescriptors()) {
473492
if(cped.getPath().isPrefixOf(fullPath)) {
@@ -495,9 +514,13 @@ private void addResourceDirs(IClasspathDescriptor classpath, IProject project, M
495514
if(directory == null) {
496515
continue;
497516
}
498-
File resourceDirectory = new File(directory);
499-
IPath relativePath = getProjectRelativePath(project, directory);
500-
IResource r = project.findMember(relativePath);
517+
File resourceDirectory = null;
518+
try {
519+
resourceDirectory = new File(directory).getCanonicalFile();
520+
} catch(IOException ex) {
521+
resourceDirectory = new File(directory).getAbsoluteFile();
522+
}
523+
IContainer r = getFolder(project, resourceDirectory.getPath());
501524
if(r == project) {
502525
/*
503526
* Workaround for the Java Model Exception:
@@ -517,10 +540,6 @@ private void addResourceDirs(IClasspathDescriptor classpath, IProject project, M
517540
log.error("Skipping resource folder " + r.getFullPath());
518541
return;
519542
}
520-
if(r == null) {
521-
//this means the resources does not exits (yet) but might be created later on!
522-
r = project.getFolder(relativePath);
523-
}
524543
if(project.equals(r.getProject())) {
525544
IPath path = r.getFullPath();
526545
IClasspathEntryDescriptor enclosing = getEnclosingEntryDescriptor(classpath, path);
@@ -533,12 +552,11 @@ private void addResourceDirs(IClasspathDescriptor classpath, IProject project, M
533552
addResourceFolder(classpath, path, outputPath, addTestFlag);
534553
}
535554
// Set folder encoding (null = platform default)
536-
IFolder resourceFolder = project.getFolder(relativePath);
537-
if(resourceFolder.exists()) {
538-
resourceFolder.setDefaultCharset(resourceEncoding, monitor);
555+
if(r.exists()) {
556+
r.setDefaultCharset(resourceEncoding, monitor);
539557
}
540558
} else {
541-
log.info("Not adding resources folder " + resourceDirectory.getAbsolutePath());
559+
log.info("Not adding resources folder " + resourceDirectory);
542560
}
543561
}
544562
}
@@ -864,11 +882,22 @@ private void removeMavenClasspathContainer(IProject project) throws JavaModelExc
864882
}
865883
}
866884

867-
protected IFolder getFolder(IProject project, String absolutePath) {
868-
if(project.getLocation().makeAbsolute().equals(IPath.fromOSString(absolutePath))) {
869-
return project.getFolder(project.getLocation());
885+
protected IContainer getFolder(IProject project, String absolutePath) throws CoreException {
886+
Path projectLocation = project.getLocation().toPath().toAbsolutePath();
887+
Path folderPath = Path.of(absolutePath);
888+
if(projectLocation.equals(folderPath)) {
889+
return project;
890+
}
891+
IPath relativePath = getProjectRelativePath(project, absolutePath);
892+
if(!project.exists(relativePath) && Files.exists(folderPath)
893+
&& !ResourcesPlugin.getWorkspace().getRoot().getLocation().toPath().equals(folderPath)) {
894+
String linkName = projectLocation.relativize(folderPath).toString().replace("/", "_");
895+
IFolder folder = project.getFolder(linkName);
896+
folder.createLink(folderPath.toUri(), IResource.REPLACE, null);
897+
folder.setPersistentProperty(LINKED_MAVEN_RESOURCE, "true");
898+
return folder;
870899
}
871-
return project.getFolder(getProjectRelativePath(project, absolutePath));
900+
return project.getFolder(relativePath);
872901
}
873902

874903
protected IPath getProjectRelativePath(IProject project, String absolutePath) {

0 commit comments

Comments
 (0)