Skip to content

Create Maven nested project Test Case - Reproduce the Issue ".java is not on the classpath of project"#3460

Open
AnqiHuangQiQi wants to merge 20 commits intoeclipse-jdtls:mainfrom
AnqiHuangQiQi:patch-1
Open

Create Maven nested project Test Case - Reproduce the Issue ".java is not on the classpath of project"#3460
AnqiHuangQiQi wants to merge 20 commits intoeclipse-jdtls:mainfrom
AnqiHuangQiQi:patch-1

Conversation

@AnqiHuangQiQi
Copy link

@AnqiHuangQiQi AnqiHuangQiQi commented Jun 2, 2025

Providing a reproducible case for this issue:
#3447

Error Message:

.java is not on the classpath of project, only syntax errors are reported

When opening this project in Vscode, 2 Java projects are recognized(This part is ok.):

  1. workspace_root
  2. mypackage_mytarget

The only real Java file is under /com/packages/foo/File.java.
There is 1 Java project which is under /.eclipse/projects/mypackage_mytarget.
Within .project file, we have a Link which is linking the real java file to .eclipse/projects/mypackage_mytarget/linked-srcs/com/packages/foo/File.java.

	<linkedResources>
		<link>
			<name>linked-srcs/com/packages/foo/File.java</name>
			<type>1</type>
			<location>/Users/anqihuang/code/nestedprojectlinked/com/packages/foo/File.java</location>
		</link>
	</linkedResources>

Here workspace_root only means it's the root folder.
The nested project mypackage_mytarget is the project we care and it has all the necessary class paths.

Then opening File.java in Vscode editor.
Got the error.
Screenshot 2025-06-02 at 3 37 07 PM

So I did live debug through Eclipse Jdtls and found the line of code which causing this error.
JDTUtils.findResource

					if (resource == null || f.getProjectRelativePath().segmentCount() < resource.getProjectRelativePath().segmentCount()) {
						resource = f;
				}

When there are 2 IResources are found, it will simply choose the shorter path one(with lower number of segments)
image

In this case, /workspace_root is chosen.
But /mypackage_mytarget should be chosen.
If I changed the code in JDTUtils and return Resource(/mypackage_mytarget), the error is gone.

Let's work together to fix this issue.

Create maven nested project test case
@eclipse-ls-bot
Copy link
Contributor

Can one of the admins verify this patch?

@AnqiHuangQiQi AnqiHuangQiQi changed the title Create Maven nested project Reproduce the Issue .java is not on the classpath of project Create Maven nested project Test Case - Reproduce the Issue ".java is not on the classpath of project" Jun 2, 2025
@rgrunber
Copy link
Contributor

rgrunber commented Jun 2, 2025

The project doesn't work correctly even from CLI. If I run mvn clean verify, and then inspect the contents of the resulting artifact, none of the classes are present :

$ jar -tf target/workspace_root-1.0-SNAPSHOT.jar 
META-INF/
META-INF/MANIFEST.MF
META-INF/maven/
META-INF/maven/com.package/
META-INF/maven/com.package/workspace_root/
META-INF/maven/com.package/workspace_root/pom.xml
META-INF/maven/com.package/workspace_root/pom.properties

Part of this is that the default source location is set to src/main/java/ and that doesn't exist here. I'm not sure what the purpose of the .eclipse folder is.

If you create the folder structure, src/main/java and move com/ into there, then things will probably start working.

$ mkdir -p src/main/java
$ mv com/ src/main/java/

@guw
Copy link
Contributor

guw commented Jun 2, 2025

@rgrunber This is not supposed to be a valid MAVEN project. Please ignore the Maven part. This should be a setup how the Bazel extension generates projects. It works nicely in Eclipse but fails in JDTLS. This is an outcome of her investigations in salesforce/bazel-vscode-java#143.

The problem is suspected in this code:

//find closest project containing that file, in case of nested projects
if (resource == null || f.getProjectRelativePath().segmentCount() < resource.getProjectRelativePath().segmentCount()) {
resource = f;
}

TLDR; JDTLS is picking the wrong project to pick the IFile from. The picked IFile is not part of IPackageFragmentRoot

@rgrunber
Copy link
Contributor

rgrunber commented Jun 3, 2025

Ok, so we should probably have some kind of check to determine if the file is a linked resource, and prefer the original file as opposed to the shortest path.

@guw
Copy link
Contributor

guw commented Jun 3, 2025

Ok, so we should probably have some kind of check to determine if the file is a linked resource, and prefer the original file as opposed to the shortest path.

The opposite is true in this case. The links are setup to simulate a project structure that JDT can understand. I think a check is needed that the picked resource is actually part of a source directory (IPackageFragmentRoot).

Where it probably gets challenging is overlapping source files. It is possible to define different targets with different set of sources from the same Java package. Some classes might appear in both. Thus, there could be two nested projects both linking to the same file. I think this case should be explicitly ignored (eg., first one wins) because it is actually not encouraged.


IPackageFragmentRoot[] packageFragmentRoots = unit.getJavaProject().getPackageFragmentRoots();
boolean containsPackageFragmentRoot = Arrays.stream(packageFragmentRoots)
.anyMatch(root -> root.getClass().equals(PackageFragmentRoot.class)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's odd. Don't use getClass().equals(..). Use isInstance. Don't use internal classes (eg., PackageFragmentRoot). Use official JDT API only. Also, this check is unnecessary. The array is already IPackageFragmentRoot

Comment on lines 1187 to 1188
//find the resource which has PackageFragmentRoot
//find closest project containing that file, in case of nested projects
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//find the resource which has PackageFragmentRoot
//find closest project containing that file, in case of nested projects
//find closest project containing that file, in case of nested projects
//ignore files outside a source folder (https://github.com/eclipse-jdtls/eclipse.jdt.ls/issues/3447)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, the method name findResource no longer matches the contract now. This should be addressed.

@tsmaeder
Copy link
Member

tsmaeder commented Nov 6, 2025

Ok, so we should probably have some kind of check to determine if the file is a linked resource, and prefer the original file as opposed to the shortest path.

The opposite is true in this case. The links are setup to simulate a project structure that JDT can understand. I think a check is needed that the picked resource is actually part of a source directory (IPackageFragmentRoot).

With Bazel, it's impossible to know which path to the file is the right one because that depends on which "target" you're looking at. Files can be on the build path for different targets at the same time. You can't resolve this without either

  1. Introducing some kind of "active target" notion
  2. Using some kind of heuristic to chose one target if a file can be found through different targets
  3. Using some kind of "lenient" parsing that handles the ambiguity (but that will not work with JDT/Eclipse)

IMO, the best thing we can do is to (optionally) delegate the resolution of URIs to Java elements to the build tool. Only Bazel knows which solution is the right one.

@snjeza
Copy link
Contributor

snjeza commented Nov 6, 2025

This issue is related to salesforce/bazel-vscode-java#159

  1. Bazel Eclipse creates duplicate links for all of the three source files in linked-srcs and linked-test-srcs
    The related issue - .java is not on the class path of project A, only syntax errors are reported Adjust to latest lsp4j changes. Fixes #142 #143

that has been fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants