Skip to content

dap-java discards module paths from resolveClasspath causing JPMS-modular projects fail to launch #511

@systemhalted

Description

@systemhalted

Describe the bug

dap-java cannot launch or debug a main class that lives inside a JPMS module (any project containing a module-info.java). dap-java--populate-launch-args discards the module-path half of vscode.java.resolveClasspath's result and pins :modulePaths to an empty vector, so the class is launched in classpath mode with a module-qualified main class and dies with ClassNotFoundException.

For a class inside a declared module, vscode.java.resolveMainClass returns the module-qualified main class (e.g. kisoku.api/in.systemhalted.kisoku.api.Test), and vscode.java.resolveClasspath returns a two-element sequence [modulePaths classPaths]. But the launch populator keeps only (cl-second …) and forces :modulePaths empty:

(dap--put-if-absent :modulePaths (vector))
(dap--put-if-absent :classPaths
                    (or (cl-second (… "vscode.java.resolveClasspath" …))
                        (error "Unable to resolve classpath")))

The module paths (cl-first) are never used. The adapter then launches in classpath mode, and the Java launcher rewrites /.:

java -cp … kisoku.api/in.systemhalted.kisoku.api.Test
Error: Could not find or load main class kisoku.api.in.systemhalted.kisoku.api.Test
Caused by: java.lang.ClassNotFoundException: kisoku.api.in.systemhalted.kisoku.api.Test
Debugger failed to attach: handshake failed - connection prematurely closed

(The handshake failure is downstream — the JVM exits before jdwp attaches.)

Note

The defect is in dap-java--populate-launch-args itself and does not depend on user configuration, so it reproduces with the latest MELPA lsp-java/dap-mode and with a clean config — any project with a module-info.java triggers it.

To Reproduce

  1. Open a Maven (or Gradle) project containing a module-info.java declaring a module, e.g. module kisoku.api;, with a class in.systemhalted.kisoku.api.Test that has a public static void main(String[] args).
  2. M-x lsp to start JDT-LS; let the project import.
  3. M-x dap-debugJava Run Configuration → select the Test main class.

Expected behavior

The debug session launches via the module path (java --module-path … -m kisoku.api/in.systemhalted.kisoku.api.Test) and stops at breakpoints — the way IntelliJ and the VS Code Java debugger run modular projects.

Screenshots

N/A — the console error is reproduced above.

Logs

The failing JVM command and error are shown above. Environment: lsp-java 20260510 (MELPA), JDK 21, LSP_USE_PLISTS=true.

Root cause and proposed fix: in dap-java--populate-launch-args, resolve the classpath once and set :modulePaths from (cl-first …) when it is non-empty (keep :classPaths from (cl-second …)). With real module paths present, the bundled java-debug adapter assembles --module-path … -m module/Class itself. Happy to send a PR.

(let ((resolved-classpath
       (with-lsp-workspace (lsp-find-workspace 'jdtls)
         (lsp-send-execute-command
          "vscode.java.resolveClasspath"
          (vector main-class project-name)))))
  (-> conf
      ...
      (dap--put-if-absent :modulePaths
                          (or (cl-first resolved-classpath) (vector)))
      (dap--put-if-absent :classPaths
                          (or (cl-second resolved-classpath)
                              (error "Unable to resolve classpath")))))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions