redhat-developer / redhat-developer/vscode-java
Multi-Release JARs (MRJARs) pick the wrong class on higher Java versions
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.3k
- Forks
- 546
- Avg merge
- 20h 1m
- Merged PRs (30d)
- 11
Description
Libraries in the classpath with a Multi-Release structure work fine when using the lowest allowed Java version. However, when using a higher version that provides a replacement class, VSCode loads the lower version instead of the replacement. Another interesting thing is that when looking at the library on the Java Project Explorer using a higher Java version, classes with a replacement show duplicates, but they all switch back to the lowest when opened.
Environment
- Operating System: Windows 11 - 22H2 (build 22621.2283)
- JDK version: v20.0.2 (Gradle Java Toolchain for 11 and 17)
- Visual Studio Code version: v1.82.2
- Java extension version: v1.22.1
Steps To Reproduce
- Add a Multi-Release JAR dependency to a project.
- For these steps, I'm using Maybe for Java, which is a library of my authoring. This way, I know the
Eitherinterface has a replacement for Java 17, which makes the interface sealed, plus it uses record classes for the implementations. - This means that on Java 11, you could make any class implement
Either. But on Java 17, trying to implementEithershould show a compilation error.
- For these steps, I'm using Maybe for Java, which is a library of my authoring. This way, I know the
- Make sure to use the lowest allowed Java version for the library (e.g., Java 11)
- Use the Java Project Explorer to ensure the MRJAR lib has the
META-INF/versionsfolder with replacement classes - Import a class with replacement (e.g.,
import io.github.joselion.maybe.utils.Either;) - Go to the definition of the imported class. It should show its lowest version (e.g., interface without sealed keyword and no records)
- Switch to a higher Java version (e.g., Java 17)
- Using Gradle and the Java Toolchain can be useful
- You may need to run the
Java: Clean Java Language Servercommand
- Use the Java Project Explorer to verify the
META-INFdirectory does not containversionsanymore - Go to the definition of the imported class again. It still shows the lowest version (e.g., it should show a sealed interface and records instead)
Sample project: java-sandbox.zip
Logs: Nothing is logged during the process
Current Result
MRJAR references the lowest version class when using a higher Java version
Expected Result
MRJAR references should use the matching class based on the current Java version.
Additional Information
I'm willing to help with a PR if someone can point me in the right direction. Knowing where and how this should be handled will be of great help 🙂
I'm also adding some screenshots of the Java Project Explorer with an MRJAR dependency expanded.
With Java 11:
With Java 17:
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the issue with the linked java-sandbox.zip, the Maybe for Java MRJAR, and Java toolchains 11 and 17. Start with the Java Project Explorer and the Java: Clean Java Language Server command, then trace how the imported class definition is selected after switching versions. Done means the matching MRJAR class is shown for the current Java version.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, typescript, vscode
- Domain
- developer-experience, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100