Skip to content

--add-opens VM args incomplete for modular projects when running a multi-class test suite #1883

Closed

Description

@xmourgues

--add-opens VM args incomplete for modular projects when running a multi-class test suite

Description

When running a test suite at the module level on a JPMS-modular project, VS Code Java Test only generates --add-opens for one package (the first test class selected), leaving all other packages in the module closed to the JUnit runtime. This causes InaccessibleObjectException failures that do not occur when running the same suite in Eclipse IDE.

Steps to reproduce

  1. Have a Maven multi-module project with JPMS (module-info.java in the module under test).
  2. In VS Code Test Explorer, run all tests at the module level (click the ▶ button next to the module node).
  3. Observe that some tests fail with:
    java.lang.reflect.InaccessibleObjectException:
    Unable to make ... accessible: module com.example.mymodule does not opens com.example.mymodule.somepackage to unnamed module
    
  4. Run the exact same suite in Eclipse IDE → all tests pass.

Root cause

The issue is in JUnitLaunchConfigurationDelegate.java.

The launch argument resolution follows this sequence:

Step 1 – getJUnitLaunchArguments calls the parent JDT delegate's getVMRunnerConfiguration via reflection (acknowledged by the TODO comment in the code):

// TODO: Make the getVMRunnerConfiguration() in super class protected.
final Method getVMRunnerConfiguration = getClass().getSuperclass().getDeclaredMethod(
    "getVMRunnerConfiguration", ILaunchConfiguration.class, ILaunch.class,
    String.class, IProgressMonitor.class);
getVMRunnerConfiguration.invoke(this, configuration, launch, mode, new NullProgressMonitor());

The parent's collectExecutionArguments runs here. It generates --add-opens com.example.mymodule/<package>=ALL-UNNAMED for each test element in fTestElements. However, at this point the JDT configuration only knows about one class — the "main type" derived from testNames[0] in JUnitLaunchUtils.resolveLaunchArgument. So --add-opens is emitted for exactly one package.

Step 2 – parseParameters strips out the test-selection arguments that the parent produced (-test, -testNameFile, -classNames, -packageNameFile):

private String[] parseParameters(String[] programArguments) throws CoreException {
    for (int i = 0; i < programArguments.length; i++) {
        if (testNameArgs.contains(programArguments[i])) {
            // skip this argument and its value(s)
            while (i + 1 < programArguments.length && !programArguments[i + 1].startsWith("-")) {
                i++;
            }
        } else {
            arguments.add(programArguments[i]);
            ...
        }
    }
    addTestItemArgs(arguments); // re-injects the full class list
}

addTestItemArgs re-injects the complete list of test classes (all selected classes in the module) into -testNameFile. This is correct — the test runner now receives all classes.

Step 3 – The --add-opens VM args were already frozen in Step 1 and are not updated. The full class list added in Step 2 contains classes from many different packages, all of which remain closed.

Result: The JUnit engine can run the first class (its package was opened), but fails with InaccessibleObjectException as soon as it tries to reflectively access any class from a different package.

Why Eclipse IDE does not have this problem

Eclipse IDE uses the upstream JDT JUnitLaunchConfigurationDelegate.collectExecutionArguments directly, which iterates all test elements and emits --add-opens for each package before launching. It also generates more --add-reads directives. There is no two-phase "generate for one class, then replace the list" pattern.

Workaround

Manually add --add-opens for every package in the module to java.test.config.vmArgs in .vscode/settings.json:

"java.test.config": [
  {
    "name": "my-config",
    "vmArgs": [
      "--add-modules", "ALL-MODULE-PATH",
      "--add-opens", "com.example.mymodule/com.example.mymodule.packagea=ALL-UNNAMED",
      "--add-opens", "com.example.mymodule/com.example.mymodule.packageb=ALL-UNNAMED"
    ]
  }
]

Expected behavior

When running a multi-class or module-level test suite, --add-opens should be generated for every package of every test class in the selection, not only for the first class used to set up the JDT launch configuration.

Proposed fix direction

After addTestItemArgs populates the full test class list, re-derive the set of packages from this.args.testNames and append the missing --add-opens entries to vmArguments. Alternatively, expose getVMRunnerConfiguration as protected in the upstream JDT delegate (the TODO comment already flags this) so that the full fTestElements can be populated correctly before collectExecutionArguments runs.

Environment

  • Extension: vscjava.vscode-java-test (replace with your installed version)
  • Java extension: redhat.java
  • Project type: Maven multi-module, JPMS (module-info.java present)
  • JDK: 21

Activity

  1. github-actions commented on Jul 9, 2026

    @github-actions

    Hi xmourgues, I'm an AI Support assistant here to help with your issue. While the team reviews your request, I wanted to provide some possible tips and documentation that might help you in the meantime.

    Issue Analysis and Suggestions

    This is a bug in vscode-java-test where only the first test class’s package gets --add-opens when running a module-level suite on JPMS projects. The extension currently calls the JDT delegate twice—once to collect VM args for a single “main” test type, then strips and re-injects all test names without updating the --add-opens entries.

    Workaround
    • In your .vscode/settings.json, add all needed --add-opens entries manually under your test configuration:

    "java.test.config": [
      {
        "name": "module-suite",
        "vmArgs": [
          "--add-modules", "ALL-MODULE-PATH",
          "--add-opens", "com.example.mymodule/com.example.mymodule.packagea=ALL-UNNAMED",
          "--add-opens", "com.example.mymodule/com.example.mymodule.packageb=ALL-UNNAMED"
        ]
      }
    ]

    Proposed Fix
    • After addTestItemArgs runs, re-compute the set of packages from this.args.testNames and append missing --add-opens to vmArguments before launch.
    • Alternatively, expose the upstream JDT method getVMRunnerConfiguration as protected so all test elements are known before collectExecutionArguments emits VM flags.

    No existing GitHub issues or documentation directly address this problem. A fix will require changes in JUnitLaunchConfigurationDelegate.java in the vscode-java-test extension.

    The team will respond to your issue shortly. I hope these suggestions are helpful in the meantime. If this comment helped you, please give it a 👍. If the suggestion was not helpful or incorrect, please give it a 👎. Your feedback helps us improve!

  2. added a commit that references this issue on Jul 14, 2026
    56feff7
  3. wenytang-ms commented on Jul 14, 2026

    @wenytang-ms
    Contributor

    xmourgues
    we ship the nightly build 0.46.2026071402, please upgrade to the latest pre-release version to verify.

  4. xmourgues commented on Jul 16, 2026

    @xmourgues
    Author

    @wentyang-ms
    I can confirm that the newest build fixes the issue.

    Thanks !

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

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions