eclipse-jdt / eclipse-jdt/eclipse.jdt.core
NullPointerException when listing a missing package in a system module
- Dominant language
- Java
- Stars
- 237
- Forks
- 195
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 47
Description
## Description
`EclipseFileManager.list()` throws when asked to list a package that does not exist in a system module.
`JrtFileSystem.list()` initializes its intermediate `files` variable to `null`. When `Files.list(resolve)` throws `NoSuchFileException`, the default error path logs the exception and continues. The subsequent iteration over `files` then throws a secondary `NullPointerException`.
Source: https://github.com/eclipse-jdt/eclipse.jdt.core/blob/80fa9fa3e994d5f7b8d97ff1fcc88179efbe59f9/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/JrtFileSystem.java#L73-L100
## Reproducer
```java
JavaCompiler compiler = new EclipseCompiler();
try (StandardJavaFileManager fileManager =
compiler.getStandardFileManager(null, null, null)) {
JavaFileManager.Location javaBase =
fileManager.getLocationForModule(
StandardLocation.SYSTEM_MODULES,
"java.base");
boolean found = fileManager.list(
javaBase,
"org.eclipse.jdt.__missing_package__",
Set.of(JavaFileObject.Kind.CLASS),
false)
.iterator()
.hasNext();
System.out.println(found);
}
```
## Expected behavior
The lookup returns an empty iterable and prints `false`.
A nonexistent package is an ordinary negative lookup. The directory-backed implementation returns when its package directory does not exist, and the archive-backed implementation returns when the archive contains no types for the requested package.
## Actual behavior
With the default value of `org.eclipse.jdt.propagate_io_errors` (`false`), ECJ logs `NoSuchFileException` and then throws `NullPointerException` while iterating over the null `files` variable.
With `-Dorg.eclipse.jdt.propagate_io_errors=true`, the missing package instead produces `IllegalStateException`.
## Suggested fix
- Catch `NoSuchFileException` and `NotDirectoryException` before the general `IOException` handler.
- Treat those two exceptions as negative lookups and return an empty list without writing to `System.err`.
- Preserve the existing propagation policy for other checked `IOException`s.
- When propagation is disabled, return an empty list after logging the original checked I/O failure instead of producing a secondary NPE.
- Avoid a nullable intermediate list so every normal return path produces a valid result.
This intentionally changes the behavior for missing packages when `org.eclipse.jdt.propagate_io_errors=true`: these lookups would return an empty list instead of throwing `IllegalStateException`.
## Scope
Kind filtering remains in `EclipseFileManager.collectAllMatchingFiles()`. `JrtFileSystem.list()` does not currently use its `kinds` parameter, and this issue does not propose changing that behavior.
Recursive enumeration is also separate. The current implementation does not use the `recurse` parameter, but a missing package should produce an empty result for either value. Correct recursive traversal has different enumeration and performance implications and can be addressed independently.
An `UncheckedIOException` raised during lazy stream traversal currently propagates past the checked `IOException` handler and is outside the scope of this issue.
## Version
Reproduced from current master at `80fa9fa3e994d5f7b8d97ff1fcc88179efbe59f9`.
Contributor guide
Research direction
Start in org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/tool/JrtFileSystem.java at JrtFileSystem.list(), then review EclipseFileManager.collectAllMatchingFiles() for the existing filtering boundary. Run the provided EclipseCompiler reproducer against a missing package in java.base; done means both recurse values return an empty iterable without a secondary NPE, while other I/O errors retain the stated propagation behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100