Skip to content

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

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions