mfussenegger / nvim-jdtls

Extensions for the built-in LSP support in Neovim for eclipse.jdt.ls
GNU General Public License v3.0
1.09k stars 62 forks source link

Trying to start debug I get “No LSP client that can resolve possible test cases"; Log: "Failed to load extension bundles..." #352

Closed kevinm6 closed 1 year ago

kevinm6 commented 2 years ago

LSP client configuration

if LOADED_JDTLS then return end

local ok, jdtls = pcall(require, "jdtls")
if not ok then
  vim.notify("  Error on starting jdtls ", "Error")
  return
end

-- local home = os.getenv "HOME"

local root_dir = require("jdtls.setup").find_root {".git", "gradlew", "settings.gradle", "build.gradle"}
if root_dir == "" then
 root_dir = vim.fn.getcwd()
end

local capabilities = vim.lsp.protocol.make_client_capabilities()
local extendedClientCapabilities = jdtls.extendedClientCapabilities
extendedClientCapabilities.resolveAdditionalTextEditsSupport = true
extendedClientCapabilities.document_formatting = false

local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ":p:h:t")
local workspace_dir = vim.fn.stdpath "cache" .. "/java/workspace/" .. project_name

local bundles = {}
bundles = {
  vim.fn.expand ("~/.local/share/nvim/mason/packages/java-debug-adapter/extension/server/com.microsoft.java.debug.plugin-*.jar")
}

vim.list_extend(bundles, vim.split(vim.fn.glob( "~/.local/share/nvim/mason/packages/java-test/extension/server/*.jar"), "\n"))

local config = {
  cmd = {
    "java",
    "-Declipse.application=org.eclipse.jdt.ls.core.id1",
    "-Dosgi.bundles.defaultStartLevel=4",
    "-Declipse.product=org.eclipse.jdt.ls.core.product",
    "-Dlog.protocol=true",
    "-Dlog.level=ALL",
    "-Xms1g",
    "--add-modules=ALL-SYSTEM",
    "--add-opens", "java.base/java.util=ALL-UNNAMED",
    "--add-opens", "java.base/java.lang=ALL-UNNAMED",

    "-jar", vim.fn.expand("~/.local/share/nvim/mason/packages/jdtls/plugins/org.eclipse.equinox.launcher_*.jar"),

    "-configuration", vim.fn.expand "~/.local/share/nvim/mason/packages/jdtls/config_mac",

    "-data", workspace_dir,
  },
  capabilities = capabilities,
  root_dir = root_dir,
  single_file_support = true,
  settings = {
    java = {
      eclipse = {
        downloadSources = true,
      },
      maven = {
        downloadSources = true,
      },
      signatureHelp = { enabled = true },
      contentProvider = { preferred = "fernflower" },
      saveActions = {
        organizeImports = true
      },
      sources = {
        organizeImports = {
          starThreshold = 9999,
          staticStarThreshold = 9999,
        }
      },
      configuration = {
        updateBuildConfiguration = "interactive",
        runtimes = {
          {
            name = "JavaSE-11",
            path = "/usr/local/opt/java11/libexec/openjdk.jdk/Contents/Home/"
          },
          {
            name = "JavaSE-17",
            path = "/usr/local/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home/"
          },
          {
            name = "JavaSE-18",
            path = "/usr/local/opt/java/libexec/openjdk.jdk/Contents/Home/"
          },
        }
      },
      implementationsCodeLens = {
        enabled = true,
      },
      referencesCodeLens = {
        enabled = true,
      },
      references = {
        includeDecompiledSources = true,
      },
      inlayHints = {
        parameterNames = {
          enabled = "all",
        },
      },
      format = {
        enabled = true,
      },
    },
    completion = {
      maxResults = 20,
      favoriteStaticMembers = {
        "org.hamcrest.MatcherAssert.assertThat",
        "org.hamcrest.Matchers.*",
        "org.hamcrest.CoreMatchers.*",
        "org.junit.jupiter.api.Assertions.*",
        "java.util.Objects.requireNonNull",
        "java.util.Objects.requireNonNullElse",
        "org.mockito.Mockito.*",
      },
    },
    codeGeneration = {
      generateComments = true,
      toString = {
        template = "${object.className}{${member.name()}=${member.value}, ${otherMembers}}"
      },
      useBlocks = true,
    },
    flags = {
      debounce_text_changes = 150,
      allow_incremental_sync = true,
    },
  },
  on_init = function(client)
    client.notify('workspace/didChangeConfiguration', { settings = client.config.settings })
  end,
  init_options = {
    jvm_args = "-javaagent:" .. vim.fn.expand "~/.local/share/nvim/mason/packages/jdtls/lombok.jar",
    -- workspace = workspace_dir .. project_name,
    bundles = bundles,
    extendedClientCapabilities = extendedClientCapabilities,
  },
  handlers = {
    ["language/status"] = function() end,
    ["workspace/diagnostic/refresh"] = function() end,
    ["textDocument/codeAction"] = function() end,
    ["textDocument/rename"] = function() end,
    ["workspace/applyEdit"] = function() end,
    ["textDocument/documentHighlight"] = function() end,
  },
  on_attach = function ()
    jdtls.setup_dap { hotcodereplace = "auto" }
    require("jdtls.dap").setup_dap_main_class_configs()
    require("jdtls.setup").add_commands()
  end
}

-- -- UI
local finders = require'telescope.finders'
local sorters = require'telescope.sorters'
local actions = require'telescope.actions'
local pickers = require'telescope.pickers'
require('jdtls.ui').pick_one_async = function(items, prompt, label_fn, cb)
  local opts = {}
  pickers.new(opts, {
    prompt_title = prompt,
    finder    = finders.new_table {
      results = items,
      entry_maker = function(entry)
        return {
          value = entry,
          display = label_fn(entry),
          ordinal = label_fn(entry),
        }
      end,
    },
    sorter = sorters.get_generic_fuzzy_sorter(),
    attach_mappings = function(prompt_bufnr)
      actions.goto_file_selection_edit:replace(function()
        local selection = actions.get_selected_entry(prompt_bufnr)
        actions.close(prompt_bufnr)

        cb(selection.value)
      end)

      return true
    end,
  }):find()
end

vim.cmd(
  "command! -buffer -nargs=? -complete=custom,v:lua.require'jdtls'._complete_compile JdtCompile lua require('jdtls').compile(<f-args>)"
)
vim.cmd(
  "command! -buffer -nargs=? -complete=custom,v:lua.require'jdtls'._complete_set_runtime JdtSetRuntime lua require('jdtls').set_runtime(<f-args>)"
)
vim.cmd("command! -buffer JdtUpdateConfig lua require('jdtls').update_project_config()")
-- vim.cmd "command! -buffer JdtJol lua require('jdtls').jol()"
vim.cmd("command! -buffer JdtBytecode lua require('jdtls').javap()")
-- vim.cmd "command! -buffer JdtJshell lua require('jdtls').jshell()"

jdtls.start_or_attach(config)

-- Custom keymaps for Java
local which_key_ok, which_key = pcall(require, "which-key")
if not which_key_ok then return end

local opts = {
  mode = "n",
  prefix = "<leader>",
  buffer = nil,
  silent = true,
  noremap = true,
  nowait = true,
}

local vopts = {
  mode = "v",
  prefix = "<leader>",
  buffer = nil,
  silent = true,
  noremap = true,
  nowait = true,
}

local mappings = {
  J = {
    name = "Java",
    o = { function() require("jdtls").organize_imports() end, "Organize Imports" },
    v = { function() require("jdtls").extract_variable() end, "Extract Variable" },
    c = { function() require("jdtls").extract_constant() end, "Extract Constant" },
    t = {
      name = "Test (DAP)",
      c = { function() require("jdtls").test_class() end, "Class" },
      m = { function() require("jdtls").test_nearest_method() end, "Nearest Method" },
    },
    S = {
      function()
        require "jdtls".setup_dap { hotcodereplace = "auto" }
        require "jdtls.dap".setup_dap_main_class_configs()
        require "jdtls.setup".add_commands()
      end,
      "Setup dap for Java",
    },
  },
}

local vmappings = {
  J = {
    name = "Java",
    v = { function() require("jdtls").extract_variable(true) end, "Extract Variable" },
    c = { function() require("jdtls").extract_constant(true) end, "Extract Constant" },
    m = { function() require("jdtls").extract_method(true) end, "Extract Method" },
    t = {
      name = "Test (DAP)",
      c = { function() require("jdtls").test_class() end, "Class" },
      m = { function() require("jdtls").test_nearest_method() end, "Nearest Method" },
    },
  },
}

which_key.register(mappings, opts)
which_key.register(vmappings, vopts)

LOADED_JDTLS = true

Eclipse.jdt.ls version

1.16.0

Steps to Reproduce

In every Java project, with or without gradle, trying to test some method this is the result.

Expected Result

Just work and give me test evaluation.

Actual Result

Sometimes it worked. Especially after cleaning up workspace, uninstall jdtls and java-{test|debug} packages and reinstall them. After that, I always get the notification: "No LSP found for resolve possible test cases. Did you add the jar files?"

and this is LspLog: Failed to load extension bundles Load bundle list\norg.eclipse.core.runtime.CoreException: Load bundle list\n\tat org.eclipse.jdt.ls.core.internal.handlers.BundleUtils.loadBundles(BundleUtils.java:169)\n\tat org.eclipse.jdt.ls.core.internal.handlers.InitHandler.handleInitializationOptions(InitHandler.java:91)\n\tat org.eclipse.jdt.ls.core.internal.handlers.BaseInitHandler.initialize(BaseInitHandler.java:63)\n\tat org.eclipse.jdt.ls.core.internal.handlers.JDTLanguageServer.initialize(JDTLanguageServer.java:250)\n\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:578)\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.lambda$null$0(GenericEndpoint.java:65)\n\tat org.eclipse.lsp4j.jsonrpc.services.GenericEndpoint.request(GenericEndpoint.java:120)\n\tat org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.handleRequest(RemoteEndpoint.java:261)\n\tat org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.consume(RemoteEndpoint.java:190)\n\tat org.eclipse.jdt.ls.core.internal.ParentProcessWatcher.lambda$0(ParentProcessWatcher.java:130)\n\tat org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer.handleMessage(StreamMessageProducer.java:194)\n\tat org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer.listen(StreamMessageProducer.java:94)\n\tat org.eclipse.lsp4j.jsonrpc.json.ConcurrentMessageProcessor.run(ConcurrentMessageProcessor.java:113)\n\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:577)\n\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)\n\tat java.base/java.lang.Thread.run(Thread.java:1589)\nContains: Failed to get bundleInfo for bundle from /Users/Kevin/.local/share/nvim/mason/packages/java-test/extension/server/com.microsoft.java.test.runner-jar-with-dependencies.jar

kevinm6 commented 2 years ago

For more info, this is the output of ls for the directories I’ve set up on bundles table:

ls ~/.local/share/nvim/mason/packages/java-debug-adapter/extension/server/com.microsoft.java.debug.plugin-*.jar com.microsoft.java.debug.plugin-0.41.0.jar

ls ~/.local/share/nvim/mason/packages/java-test/extension/server/*.jar com.microsoft.java.test.plugin-0.37.1.jar com.microsoft.java.test.runner-jar-with-dependencies.jar junit-jupiter-api_5.9.0.jar junit-jupiter-engine_5.9.0.jar junit-jupiter-migrationsupport_5.9.0.jar junit-jupiter-params_5.9.0.jar junit-platform-commons_1.9.0.jar junit-platform-engine_1.9.0.jar junit-platform-launcher_1.9.0.jar junit-platform-runner_1.9.0.jar junit-platform-suite-api_1.9.0.jar junit-platform-suite-commons_1.9.0.jar junit-platform-suite-engine_1.9.0.jar junit-vintage-engine_5.9.0.jar org.apiguardian.api_1.1.2.jar org.eclipse.jdt.junit4.runtime_1.3.0.v20220609-1843.jar org.eclipse.jdt.junit5.runtime_1.1.0.v20220715-1030.jar org.opentest4j_1.2.0.v20190826-0900.jar

liujoey commented 1 year ago

this just happened to me today. In my case .jar is in my wildignore list, so replace `vim.fn.glob( "~/.local/share/nvim/mason/packages/java-test/extension/server/.jar")to vim.fn.glob( "~/.local/share/nvim/mason/packages/java-test/extension/server/*.jar", 1)` solved my problem.

kevinm6 commented 1 year ago

this just happened to me today. In my case .jar is in my wildignore list, so replace `vim.fn.glob( "~/.local/share/nvim/mason/packages/java-test/extension/server/.jar")to vim.fn.glob( "~/.local/share/nvim/mason/packages/java-test/extension/server/*.jar", 1)` solved my problem.

Thank you @liujoey for sharing your solution. Unfortunately I think there something more in my config going on that is “blocking” the expected behavior.

Could you share your config for java with nvim-jdtls?

liujoey commented 1 year ago

@kevinm6 My java.lua gist I put it under ftplugin folder

kevinm6 commented 1 year ago

With some changes now it works (following your hint @liujoey), thank you. I’ve only noticed that in your implementation at line 64 vim.list_extend(bundles, extra_bundles) is expecting two tables, but in your case bundles is a string, but maybe you are managing it differently!

I’m closing the issue since it’s working.

liujoey commented 1 year ago

Yes, I just removed few lines of unnecessary code.

mfussenegger commented 1 year ago

this just happened to me today. In my case .jar is in my wildignore list, so replace `vim.fn.glob( "~/.local/share/nvim/mason/packages/java-test/extension/server/.jar")tovim.fn.glob( "~/.local/share/nvim/mason/packages/java-test/extension/server/*.jar", 1)` solved my problem.

Thanks for pointing that out. I updated the examples in https://github.com/mfussenegger/nvim-jdtls/pull/359