Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Missing System Library" exception in ASTParser #3298

Open
ptziegler opened this issue Nov 12, 2024 · 15 comments · May be fixed by #3560
Open

"Missing System Library" exception in ASTParser #3298

ptziegler opened this issue Nov 12, 2024 · 15 comments · May be fixed by #3560
Labels
bug Something isn't working good first issue Good for newcomers help wanted Extra attention is needed regression Something was broken by a previous change

Comments

@ptziegler
Copy link
Contributor

This seems to be a regression introduced by 74d062b

To reproduce: Make sure compiler compliance is set to > 1.8 and open a Java file from a project without Java nature.

image

Stack Trace:

java.lang.IllegalStateException: Missing system library
	at org.eclipse.jdt.core.dom.ASTParser.checkForSystemLibrary(ASTParser.java:311)
	at org.eclipse.jdt.core.dom.ASTParser.getClasspath(ASTParser.java:272)
	at org.eclipse.jdt.core.dom.ASTParser.internalCreateASTCached(ASTParser.java:1299)
	at org.eclipse.jdt.core.dom.ASTParser.lambda$1(ASTParser.java:1178)
	at org.eclipse.jdt.internal.core.JavaModelManager.cacheZipFiles(JavaModelManager.java:5694)
	at org.eclipse.jdt.core.dom.ASTParser.internalCreateAST(ASTParser.java:1178)
	at org.eclipse.jdt.core.dom.ASTParser.createAST(ASTParser.java:918)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider$1.run(CoreASTProvider.java:294)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:47)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider.createAST(CoreASTProvider.java:286)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider.getAST(CoreASTProvider.java:199)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider.getAST(CoreASTProvider.java:189)
	at org.eclipse.jdt.core.manipulation.SharedASTProviderCore.getAST(SharedASTProviderCore.java:138)
	at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup.calculateASTandInform(SelectionListenerWithASTManager.java:167)
	at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup$1.lambda$0(SelectionListenerWithASTManager.java:149)
	at org.eclipse.jdt.internal.core.JavaModelManager.cacheZipFiles(JavaModelManager.java:5694)
	at org.eclipse.jdt.internal.core.JavaModelManager.callReadOnly(JavaModelManager.java:5683)
	at org.eclipse.jdt.core.JavaCore.callReadOnly(JavaCore.java:6150)
	at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup$1.run(SelectionListenerWithASTManager.java:149)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)
Caused by: Java Model Exception: Error in Java Model (code 969): TestProject does not exist
	at org.eclipse.jdt.internal.core.JavaElement.newJavaModelException(JavaElement.java:556)
	at org.eclipse.jdt.internal.core.Openable.generateInfos(Openable.java:234)
	at org.eclipse.jdt.internal.core.JavaElement.openWhenClosed(JavaElement.java:569)
	at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:292)
	at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:278)
	at org.eclipse.jdt.internal.core.JavaProject.getJavaProjectElementInfo(JavaProject.java:2040)
	at org.eclipse.jdt.internal.core.JavaProject.newNameLookup(JavaProject.java:2775)
	at org.eclipse.jdt.internal.core.JavaProject.newNameLookup(JavaProject.java:2769)
	at org.eclipse.jdt.internal.core.JavaProject.newNameLookup(JavaProject.java:2787)
	at org.eclipse.jdt.internal.core.JavaProject.newNameLookup(JavaProject.java:2779)
	at org.eclipse.jdt.internal.core.JavaProject.findType(JavaProject.java:1681)
	at org.eclipse.jdt.internal.core.JavaProject.findType(JavaProject.java:1582)
	at org.eclipse.jdt.core.dom.ASTParser.checkForSystemLibrary(ASTParser.java:304)
	... 19 more
@ptziegler
Copy link
Contributor Author

See #3047 for context.

@ptziegler
Copy link
Contributor Author

This check should probably only be done for proper Java projects?

@jukzi jukzi added bug Something isn't working regression Something was broken by a previous change labels Nov 12, 2024
@jukzi
Copy link
Contributor

jukzi commented Nov 12, 2024

This seems to be a regression introduced by 74d062b

@stephan-herrmann can you take a look?

@jukzi jukzi added good first issue Good for newcomers help wanted Extra attention is needed labels Jan 8, 2025
@jukzi
Copy link
Contributor

jukzi commented Jan 8, 2025

This issue can still be reproduced.

java.lang.IllegalStateException: Missing system library
	at org.eclipse.jdt.core.dom.ASTParser.checkForSystemLibrary(ASTParser.java:311)
	at org.eclipse.jdt.core.dom.ASTParser.getClasspath(ASTParser.java:272)
	at org.eclipse.jdt.core.dom.ASTParser.internalCreateASTCached(ASTParser.java:1299)
	at org.eclipse.jdt.core.dom.ASTParser.lambda$1(ASTParser.java:1178)
	at org.eclipse.jdt.internal.core.JavaModelManager.cacheZipFiles(JavaModelManager.java:5708)
	at org.eclipse.jdt.core.dom.ASTParser.internalCreateAST(ASTParser.java:1178)
	at org.eclipse.jdt.core.dom.ASTParser.createAST(ASTParser.java:918)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider$1.run(CoreASTProvider.java:294)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:47)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider.createAST(CoreASTProvider.java:286)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider.getAST(CoreASTProvider.java:199)
	at org.eclipse.jdt.core.manipulation.CoreASTProvider.getAST(CoreASTProvider.java:189)
	at org.eclipse.jdt.core.manipulation.SharedASTProviderCore.getAST(SharedASTProviderCore.java:138)
	at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup.calculateASTandInform(SelectionListenerWithASTManager.java:167)
	at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup$1.lambda$0(SelectionListenerWithASTManager.java:149)
	at org.eclipse.jdt.internal.core.JavaModelManager.cacheZipFiles(JavaModelManager.java:5708)
	at org.eclipse.jdt.internal.core.JavaModelManager.callReadOnly(JavaModelManager.java:5697)
	at org.eclipse.jdt.core.JavaCore.callReadOnly(JavaCore.java:6150)
	at org.eclipse.jdt.internal.ui.viewsupport.SelectionListenerWithASTManager$PartListenerGroup$1.run(SelectionListenerWithASTManager.java:149)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)
Caused by: Java Model Exception: Error in Java Model (code 969): plain does not exist
	at org.eclipse.jdt.internal.core.JavaElement.newJavaModelException(JavaElement.java:556)
	at org.eclipse.jdt.internal.core.Openable.generateInfos(Openable.java:234)
	at org.eclipse.jdt.internal.core.JavaElement.openWhenClosed(JavaElement.java:569)
	at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:292)
	at org.eclipse.jdt.internal.core.JavaElement.getElementInfo(JavaElement.java:278)
	at org.eclipse.jdt.internal.core.JavaProject.getJavaProjectElementInfo(JavaProject.java:2050)
	at org.eclipse.jdt.internal.core.JavaProject.newNameLookup(JavaProject.java:2785)
	at org.eclipse.jdt.internal.core.JavaProject.newNameLookup(JavaProject.java:2779)
	at org.eclipse.jdt.internal.core.JavaProject.newNameLookup(JavaProject.java:2797)
	at org.eclipse.jdt.internal.core.JavaProject.newNameLookup(JavaProject.java:2789)
	at org.eclipse.jdt.internal.core.JavaProject.findType(JavaProject.java:1691)
	at org.eclipse.jdt.internal.core.JavaProject.findType(JavaProject.java:1592)
	at org.eclipse.jdt.core.dom.ASTParser.checkForSystemLibrary(ASTParser.java:304)
	... 19 more
eclipse.buildId=4.35.0.I20250108-0430
java.version=22.0.2

This check should probably only be done for proper Java projects?

@ptziegler can you propose such PR please?

@ptziegler
Copy link
Contributor Author

There is a lot of stuff on my todo list right now, but think an initial draft is done fairly quickly. I'll try to come up with something during the weekend.

@ptziegler
Copy link
Contributor Author

This check should probably only be done for proper Java projects?

After a quick glance, I don't think adding an additional check in the AST parser is not the correct solution. Instead, I believe that the project being converted to a JavaProject is the real problem.

From the documentation:

A Java project represents a view of a project resource in terms of Java elements such as package fragments, types, methods and fields. A project may contain several package roots, which contain package fragments. A package root corresponds to an underlying folder or JAR.

Each Java project has a classpath, defining which folders contain source code and where required libraries are located. Each Java project also has an output location, defining where the builder writes .class files. A project that references packages in another project can access the packages by including the required project in a classpath entry. The Java model will present the source elements in the required project; when building, the compiler will use the corresponding generated class files from the required project's output location(s)). The classpath format is a sequence of classpath entries describing the location and contents of package fragment roots.

This is not the case, unless a project has the Java nature. And if the JavaProject field were to be null, this check would return early, without throwing an exception.

@stephan-herrmann
Copy link
Contributor

Instead, I believe that the project being converted to a JavaProject is the real problem.

Which code creates the JavaProject in your scenario?

@ptziegler
Copy link
Contributor Author

Instead, I believe that the project being converted to a JavaProject is the real problem.

Which code creates the JavaProject in your scenario?

I believe the JavaProject is created by the CompilationUnitDocumentProvider when the Java editor is openend.. More specifically, by the JavaModelManager:

public static IJavaElement create(IFile file, IJavaProject project) {
if (file == null) {
return null;
}
if (project == null) {
project = JavaCore.create(file.getProject());
}
if (file.getFileExtension() != null) {
String name = file.getName();
if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(name))
return createCompilationUnitFrom(file, project);
if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name))
return createClassFileFrom(file, project);
return createJarPackageFragmentRootFrom(file, project);
}
return null;
}

image

However, I get the impression that there is no way around this, as the ICompilationUnit is created by an IPackageFragment, which in returns requires the JavaProject. 😦

@ptziegler
Copy link
Contributor Author

ptziegler commented Jan 13, 2025

I looked deeper into this issue and I believe the underlying problem is that the Java editor is always opened with the RESOLVE_BINDING bit set.

if ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0) {
checkForSystemLibrary(allClasspaths);
}

If I add a check that clears this flag if the Java project doesn't have the Java nature, this exception isn't thrown. Meaning I now have two options: I can either fix it in the ASTParser class, where it would also handle all other combinations I haven't thought of, or in the UI classes for this specific use case.

Given that I'm not overly familiar with either classes, what would be the preferable approach? I'm personally leaning towards the latter option, because I think it's wrong to do a type binding when there are no types to bind with. Depending on that, I would push a PR either to this repository or to JDT UI.

ptziegler added a commit to ptziegler/eclipse.jdt.core that referenced this issue Jan 15, 2025
The validation of the project classpath introduced with
74d062b always fails, if the project
doesn't have a Java nature (and thus usually no .classpath file).

This causes issues when e.g. trying to open a source file with the Java
editor or simply when trying to use the AST parser outside of a Java
project. With this change, the check becomes more conservative and only
fails, if both the Java nature exists and no system library is
configured.

Note that one can avoid this exception by disabling the binding
resolution. But given that this requires changes in user code, it is
more prudent to only fail in cases where this is the desired behavior.

Resolves eclipse-jdt#3298
@ptziegler ptziegler linked a pull request Jan 15, 2025 that will close this issue
3 tasks
@ptziegler
Copy link
Contributor Author

I've created #3560 as a fix, after I noticed that this actively breaks our application, because we parse source code that isn't in a Java project. I therefore believe it's not sufficient to only fix this for the Java editor, as there are many more instances where this problem can and will occur.

@akurtakov
Copy link
Contributor

@ptziegler You might consider adding such a test using ASTParser in non Java project to make sure it doesn't regress again in the future.

ptziegler added a commit to ptziegler/eclipse.jdt.core that referenced this issue Jan 15, 2025
The validation of the project classpath introduced with
74d062b always fails, if the project
doesn't have a Java nature (and thus usually no .classpath file).

This causes issues when e.g. trying to open a source file with the Java
editor or simply when trying to use the AST parser outside of a Java
project. With this change, the check becomes more conservative and only
fails, if both the Java nature exists and no system library is
configured.

Note that one can avoid this exception by disabling the binding
resolution. But given that this requires changes in user code, it is
more prudent to only fail in cases where this is the desired behavior.

Resolves eclipse-jdt#3298
@ptziegler
Copy link
Contributor Author

@ptziegler You might consider adding such a test using ASTParser in non Java project to make sure it doesn't regress again in the future.

Isn't this exactly what I'm doing with this test case?

public void testGH3298() throws Exception {
	Hashtable<String, String> options = JavaCore.getDefaultOptions();
	options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_9);
	options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_9);
	options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_9);

	IProject project = createProject("P");
	IJavaProject javaProject = JavaCore.create(project);
	try {
		ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
		parser.setProject(javaProject);
		parser.setCompilerOptions(options);
		parser.setSource("public class Test{}".toCharArray());
		parser.setResolveBindings(true);
		parser.setKind(ASTParser.K_COMPILATION_UNIT);
		assertNotNull(parser.createAST(null));

		addJavaNature("P");
		parser.setProject(javaProject);
		parser.setCompilerOptions(options);
		parser.setSource("public class Test{}".toCharArray());
		parser.setResolveBindings(true);
		parser.setKind(ASTParser.K_COMPILATION_UNIT);
		assertThrows(IllegalStateException.class, () -> parser.createAST(null));

		parser.setProject(javaProject);
		parser.setCompilerOptions(options);
		parser.setSource("public class Test{}".toCharArray());
		parser.setResolveBindings(false);
		parser.setKind(ASTParser.K_COMPILATION_UNIT);
		assertNotNull(parser.createAST(null));
	} finally {
		deleteProject("P");
	}
}

@ptziegler
Copy link
Contributor Author

As a side note: The IJavaProject object is created quite frequently, even if the project is in-fact not a Java project. As far as I can tell, the deciding factor is only whether it has a Java nature or not.

ptziegler added a commit to ptziegler/eclipse.jdt.core that referenced this issue Jan 15, 2025
The validation of the project classpath introduced with
74d062b always fails, if the project
doesn't have a Java nature (and thus usually no .classpath file).

This causes issues when e.g. trying to open a source file with the Java
editor or simply when trying to use the AST parser outside of a Java
project. With this change, the check becomes more conservative and only
fails, if both the Java nature exists and no system library is
configured.

Note that one can avoid this exception by disabling the binding
resolution. But given that this requires changes in user code, it is
more prudent to only fail in cases where this is the desired behavior.

Resolves eclipse-jdt#3298
@akurtakov
Copy link
Contributor

What I've been thinking of a test without IJavaProject javaProject = JavaCore.create(project); and parser.setProject(javaProject); lines to ensure that ASTParser works in "plain" projects.

ptziegler added a commit to ptziegler/eclipse.jdt.core that referenced this issue Jan 15, 2025
The validation of the project classpath introduced with
74d062b always fails, if the project
doesn't have a Java nature (and thus usually no .classpath file).

This causes issues when e.g. trying to open a source file with the Java
editor or simply when trying to use the AST parser outside of a Java
project. With this change, the check becomes more conservative and only
fails, if both the Java nature exists and no system library is
configured.

Note that one can avoid this exception by disabling the binding
resolution. But given that this requires changes in user code, it is
more prudent to only fail in cases where this is the desired behavior.

Resolves eclipse-jdt#3298
@ptziegler
Copy link
Contributor Author

What I've been thinking of a test without IJavaProject javaProject = JavaCore.create(project); and parser.setProject(javaProject); lines to ensure that ASTParser works in "plain" projects.

Ah, thanks for the clarification I've updated the test case to avoid using the IJavaProject, but I generally won't get around using some of the JDT API. In this case the ICompilationUnit.

ptziegler added a commit to ptziegler/eclipse.jdt.core that referenced this issue Jan 16, 2025
The validation of the project classpath introduced with
74d062b always fails, if the project
doesn't have a Java nature (and thus usually no .classpath file).

This causes issues when e.g. trying to open a source file with the Java
editor or simply when trying to use the AST parser outside of a Java
project. With this change, the check becomes more conservative and only
fails, if both the Java nature exists and no system library is
configured.

Note that one can avoid this exception by disabling the binding
resolution. But given that this requires changes in user code, it is
more prudent to only fail in cases where this is the desired behavior.

Resolves eclipse-jdt#3298
ptziegler added a commit to ptziegler/eclipse.jdt.core that referenced this issue Jan 16, 2025
The validation of the project classpath introduced with
74d062b always fails, if the project
doesn't have a Java nature (and thus usually no .classpath file).

This causes issues when e.g. trying to open a source file with the Java
editor or simply when trying to use the AST parser outside of a Java
project. With this change, the check becomes more conservative and only
fails, if both the Java nature exists and no system library is
configured.

Note that one can avoid this exception by disabling the binding
resolution. But given that this requires changes in user code, it is
more prudent to only fail in cases where this is the desired behavior.

Resolves eclipse-jdt#3298
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working good first issue Good for newcomers help wanted Extra attention is needed regression Something was broken by a previous change
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants