Skip to content

Commit

Permalink
Add ability to add source/resource folder outside of the project
Browse files Browse the repository at this point in the history
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().
  • Loading branch information
RoiSoleil authored and HannesWell committed Feb 2, 2024
1 parent 045f3cb commit 60e66ff
Show file tree
Hide file tree
Showing 14 changed files with 191 additions and 28 deletions.
Expand Up @@ -25,7 +25,6 @@
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
Expand All @@ -47,13 +46,17 @@ public class M2EUtils {
* @param monitor the progress monitor
* @throws CoreException if creating the given <code>folder</code> or any of its parents fails.
*/
public static void createFolder(IFolder folder, boolean derived, IProgressMonitor monitor) throws CoreException {
public static void createFolder(IContainer container, boolean derived, IProgressMonitor monitor)
throws CoreException {
if(!(container instanceof IFolder folder)) {
return; // don't create projects
}
// Recurse until we find a parent folder which already exists.
if(!folder.exists()) {
IContainer parent = folder.getParent();
// First, make sure that all parent folders exist.
if(parent != null && !parent.exists()) {
createFolder((IFolder) parent, false, monitor);
createFolder(parent, false, monitor);
}
try {
if(!folder.exists()) {
Expand Down
@@ -0,0 +1,5 @@
import java.io.Serializable;

class A implements Serializable {

}
Empty file.
@@ -0,0 +1,5 @@
import java.io.Serializable;

class ATest implements Serializable {

}
Empty file.
13 changes: 13 additions & 0 deletions org.eclipse.m2e.jdt.tests/projects/add-source-resource/pom.xml
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>foo.bar</groupId>
<artifactId>add-source-resource</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>submoduleA</module>
</modules>
</project>
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>foo.bar</groupId>
<artifactId>submoduleA</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>java</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>../parent/src/main/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>test</id>
<phase>generate-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>../parent/src/test/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>resources</id>
<phase>generate-resources</phase>
<goals>
<goal>add-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>../parent/src/main/resources</directory>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>test-resources</id>
<phase>generate-resources</phase>
<goals>
<goal>add-test-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>../parent/src/test/resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Expand Up @@ -20,6 +20,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

import org.eclipse.core.resources.IFile;
Expand All @@ -29,12 +31,14 @@
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
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.m2e.core.MavenPlugin;
import org.eclipse.m2e.core.internal.preferences.MavenConfigurationImpl;
import org.eclipse.m2e.core.project.ResolverConfiguration;
import org.eclipse.m2e.tests.common.AbstractMavenProjectTestCase;
import org.junit.Before;
import org.junit.Test;
Expand Down Expand Up @@ -124,14 +128,39 @@ public void testSkipNone() throws CoreException, IOException, InterruptedExcepti
assertEquals(1, classpathEntriesCount(project, TEST_RESOURCES));
}


@Test
public void testComplianceVsEnablePreviewSettings() throws CoreException, IOException, InterruptedException {
IJavaProject project = importResourceProject("/projects/compilerEnablePreviewSettings/pom.xml");
assertEquals("11", project.getOption(JavaCore.COMPILER_COMPLIANCE, false));
assertEquals(JavaCore.ENABLED, project.getOption(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, false));
assertEquals(JavaCore.IGNORE, project.getOption(JavaCore.COMPILER_PB_REPORT_PREVIEW_FEATURES, false));
}

@Test
public void testAddSourceResource() throws CoreException, IOException, InterruptedException {
File baseDir = new File(FileLocator
.toFileURL(JavaConfigurationTest.class.getResource("/projects/add-source-resource/submoduleA/pom.xml"))
.getFile()).getParentFile().getParentFile();
waitForJobsToComplete();
IProject project = importProjects(baseDir.getAbsolutePath(), new String[] { "submoduleA/pom.xml" },
new ResolverConfiguration())[0];
waitForJobsToComplete();
IJavaProject javaProject = JavaCore.create(project);

List<String> srcEntryPaths = Arrays.stream(javaProject.getRawClasspath())
.filter(cp -> IClasspathEntry.CPE_SOURCE == cp.getEntryKind()).filter(cp -> !cp.isTest())
.map(IClasspathEntry::getPath).map(IPath::toString).toList();
assertEquals(Set.of("/submoduleA/src/main/java", "/submoduleA/src/main/resources", //
"/submoduleA/.._parent_src_main_java", "/submoduleA/.._parent_src_main_resources"),
Set.copyOf(srcEntryPaths));
List<String> testEntryPaths = Arrays.stream(javaProject.getRawClasspath())
.filter(cp -> IClasspathEntry.CPE_SOURCE == cp.getEntryKind()).filter(cp -> cp.isTest())
.map(IClasspathEntry::getPath).map(IPath::toString).toList();
assertEquals(Set.of("/submoduleA/src/test/java", "/submoduleA/src/test/resources", //
"/submoduleA/.._parent_src_test_java", "/submoduleA/.._parent_src_test_resources"),
Set.copyOf(testEntryPaths));
}

// --- utility methods ---

private static final Predicate<IClasspathEntry> TEST_SOURCES = cp -> cp.isTest()
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.m2e.jdt/META-INF/MANIFEST.MF
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.m2e.jdt;singleton:=true
Bundle-Version: 2.3.3.qualifier
Bundle-Version: 2.3.400.qualifier
Bundle-Localization: plugin
Export-Package: org.eclipse.m2e.jdt,
org.eclipse.m2e.jdt.internal;x-friends:="org.eclipse.m2e.jdt.ui",
Expand Down
Expand Up @@ -14,6 +14,9 @@
package org.eclipse.m2e.jdt.internal;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -30,9 +33,11 @@
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IClasspathAttribute;
Expand Down Expand Up @@ -134,6 +139,9 @@ public abstract class AbstractJavaProjectConfigurator extends AbstractProjectCon

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

private static final QualifiedName LINKED_MAVEN_RESOURCE = new QualifiedName(MavenJdtPlugin.PLUGIN_ID,
"linkedSource");

@Override
public void configure(ProjectConfigurationRequest request, IProgressMonitor monitor) throws CoreException {
IProject project = request.mavenProjectFacade().getProject();
Expand Down Expand Up @@ -282,8 +290,8 @@ protected void addProjectSourceFolders(IClasspathDescriptor classpath, Map<Strin
MavenProject mavenProject = request.mavenProject();
IMavenProjectFacade projectFacade = request.mavenProjectFacade();

IFolder classes = getFolder(project, mavenProject.getBuild().getOutputDirectory());
IFolder testClasses = getFolder(project, mavenProject.getBuild().getTestOutputDirectory());
IContainer classes = getFolder(project, mavenProject.getBuild().getOutputDirectory());
IContainer testClasses = getFolder(project, mavenProject.getBuild().getTestOutputDirectory());

M2EUtils.createFolder(classes, true, mon.newChild(1));
M2EUtils.createFolder(testClasses, true, mon.newChild(1));
Expand Down Expand Up @@ -361,6 +369,9 @@ protected void addProjectSourceFolders(IClasspathDescriptor classpath, Map<Strin
isTestResourcesSkipped.add(Boolean.FALSE);
}
}

cleanLinkedSourceDirs(project, monitor);

addSourceDirs(classpath, project, mavenProject.getCompileSourceRoots(), classes.getFullPath(), inclusion,
exclusion, mainSourceEncoding, mon.newChild(1), false);
addResourceDirs(classpath, project, mavenProject, mavenProject.getBuild().getResources(), classes.getFullPath(),
Expand Down Expand Up @@ -429,7 +440,7 @@ protected void addSourceDirs(IClasspathDescriptor classpath, IProject project, L
boolean addTestFlag) throws CoreException {

for(String sourceRoot : sourceRoots) {
IFolder sourceFolder = getFolder(project, sourceRoot);
IContainer sourceFolder = getFolder(project, sourceRoot);

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

}

private void cleanLinkedSourceDirs(IProject project, IProgressMonitor monitor) throws CoreException {
for(IResource resource : project.members()) {
if(resource instanceof IFolder && "true".equals(resource.getPersistentProperty(LINKED_MAVEN_RESOURCE))) {
resource.delete(false, monitor);
}
}
}

private IClasspathEntryDescriptor getEnclosingEntryDescriptor(IClasspathDescriptor classpath, IPath fullPath) {
for(IClasspathEntryDescriptor cped : classpath.getEntryDescriptors()) {
if(cped.getPath().isPrefixOf(fullPath)) {
Expand Down Expand Up @@ -495,9 +514,13 @@ private void addResourceDirs(IClasspathDescriptor classpath, IProject project, M
if(directory == null) {
continue;
}
File resourceDirectory = new File(directory);
IPath relativePath = getProjectRelativePath(project, directory);
IResource r = project.findMember(relativePath);
File resourceDirectory = null;
try {
resourceDirectory = new File(directory).getCanonicalFile();
} catch(IOException ex) {
resourceDirectory = new File(directory).getAbsoluteFile();
}
IContainer r = getFolder(project, resourceDirectory.getPath());
if(r == project) {
/*
* Workaround for the Java Model Exception:
Expand All @@ -517,10 +540,6 @@ private void addResourceDirs(IClasspathDescriptor classpath, IProject project, M
log.error("Skipping resource folder " + r.getFullPath());
return;
}
if(r == null) {
//this means the resources does not exits (yet) but might be created later on!
r = project.getFolder(relativePath);
}
if(project.equals(r.getProject())) {
IPath path = r.getFullPath();
IClasspathEntryDescriptor enclosing = getEnclosingEntryDescriptor(classpath, path);
Expand All @@ -533,12 +552,11 @@ private void addResourceDirs(IClasspathDescriptor classpath, IProject project, M
addResourceFolder(classpath, path, outputPath, addTestFlag);
}
// Set folder encoding (null = platform default)
IFolder resourceFolder = project.getFolder(relativePath);
if(resourceFolder.exists()) {
resourceFolder.setDefaultCharset(resourceEncoding, monitor);
if(r.exists()) {
r.setDefaultCharset(resourceEncoding, monitor);
}
} else {
log.info("Not adding resources folder " + resourceDirectory.getAbsolutePath());
log.info("Not adding resources folder " + resourceDirectory);
}
}
}
Expand Down Expand Up @@ -864,11 +882,22 @@ private void removeMavenClasspathContainer(IProject project) throws JavaModelExc
}
}

protected IFolder getFolder(IProject project, String absolutePath) {
if(project.getLocation().makeAbsolute().equals(IPath.fromOSString(absolutePath))) {
return project.getFolder(project.getLocation());
protected IContainer getFolder(IProject project, String absolutePath) throws CoreException {
Path projectLocation = project.getLocation().toPath().toAbsolutePath();
Path folderPath = Path.of(absolutePath);
if(projectLocation.equals(folderPath)) {
return project;
}
IPath relativePath = getProjectRelativePath(project, absolutePath);
if(!project.exists(relativePath) && Files.exists(folderPath)
&& !ResourcesPlugin.getWorkspace().getRoot().getLocation().toPath().equals(folderPath)) {
String linkName = projectLocation.relativize(folderPath).toString().replace("/", "_");
IFolder folder = project.getFolder(linkName);
folder.createLink(folderPath.toUri(), IResource.REPLACE, null);
folder.setPersistentProperty(LINKED_MAVEN_RESOURCE, "true");
return folder;
}
return project.getFolder(getProjectRelativePath(project, absolutePath));
return project.getFolder(relativePath);
}

protected IPath getProjectRelativePath(IProject project, String absolutePath) {
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.m2e.mavenarchiver/META-INF/MANIFEST.MF
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: m2e connector for the mavenarchiver and pom properties
Bundle-SymbolicName: org.eclipse.m2e.mavenarchiver;singleton:=true
Bundle-Version: 2.0.401.qualifier
Bundle-Version: 2.0.500.qualifier
Bundle-Vendor: Eclipse.org - m2e
Bundle-RequiredExecutionEnvironment: JavaSE-17
Require-Bundle: org.eclipse.core.resources;bundle-version="[3.4.0,4.0.0)",
Expand Down
2 changes: 1 addition & 1 deletion org.eclipse.m2e.pde.connector/META-INF/MANIFEST.MF
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: M2E PDE Connector
Bundle-SymbolicName: org.eclipse.m2e.pde.connector;singleton:=true
Bundle-Version: 2.1.500.qualifier
Bundle-Version: 2.1.600.qualifier
Automatic-Module-Name: org.eclipse.m2e.pde.connector
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-Vendor: Eclipse.org - m2e
Expand Down
Expand Up @@ -20,7 +20,6 @@
import org.apache.maven.project.MavenProject;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
Expand Down Expand Up @@ -96,7 +95,7 @@ protected void addProjectSourceFolders(IClasspathDescriptor classpath, Map<Strin
} else {
outputDirectory = mavenProject.getBuild().getOutputDirectory();
}
IFolder outputFolder = getFolder(project, outputDirectory);
IContainer outputFolder = getFolder(project, outputDirectory);
M2EUtils.createFolder(outputFolder, true, subMonitor.split(10));
IPath[] inclusion = new IPath[0];
IPath[] exclusion = new IPath[0];
Expand Down

0 comments on commit 60e66ff

Please sign in to comment.