nerdlyist
nerdlyist

Reputation: 2857

Neovim setting up jdtls with lsp-zero/mason

As part of the upcoming 2023 new year I wanted to try and move my development environment to vim or neovim. I have gone through a bit of setup already and have go and js/ts setup and appearing to work just fine. Autocomplete, linting and import management.

Trying to get lsp-zero and java working though is turning out to be a nightmare (because of course java would be a problem child). I opened a java file lsp-zero was baller and asked to install the jdtls which appears to have worked and voila nothing... I just have code highlighting. No auto-complete or importing management.

Mason LSP Servers

I added the following to test

-- configure an individual server
lsp.configure('jdtls', {
  flags = {
    debounce_text_changes = 150,
  },
  on_attach = function(client, bufnr)
    print('lsp server (jdtls) attached')
  end
})

lsp.configure('gopls', {
  flags = {
    debounce_text_changes = 150,
  },
  on_attach = function(client, bufnr)
    print('lsp server (gopls) attached')
  end
})

Java is not picking up the lsp server enter image description here

Go picks up just fine enter image description here

Does anyone know of additional configs that are needed. I am not seeing anything specifically called out.

--- Config edit ---

I updated the config to call the windows version of the scripts. I also added a data path and root_dir. The lsp still never triggers.

require'lspconfig'.jdtls.setup{
 cmd = {
        'jdtls-win.cmd',
        "-configuration",
        "C:\\Users\\Coury\\AppData\\Local\\nvim-data\\mason\\packages\\jdtls\\config_win",
        "-jar",
        "C:\\Users\\Coury\\AppData\\Local\\nvim-data\\mason\\packages\\jdtls\\plugins\\org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar",
        "-data",
        "C:\\Users\\Coury\\Documents\\Code\\interviews\\truleo\\app",
    },
    single_file_support = true,
    root_dir = function() 
        return "C:\\Users\\Coury\\Documents\\Code\\interviews\\truleo\\app"
    end,
    flags = {
        debounce_text_changes = 150,
    },
    on_attach = function(client, bufnr)
        print('lsp server (jdtls) attached')
    end
}

Upvotes: 3

Views: 27963

Answers (2)

Saheed
Saheed

Reputation: 312

Be sure to add your java path to your bashrc file and retry the installation via Mason

If you're still encountering with issue setting up mason/jdlts, continue with the below instructions

  1. Install eclipse.jdt.ls by following their Installation instructions.

  2. Add the plugin: Plug mfussenegger/nvim-jdtls and packer.nvim: mfussenegger/nvim-jdtls

  3. Create your personal jdlts config file in your plugins directory with the below code.

  4. Source the new config and open any java file.


-- Java.lua

local config = {
    cmd = {
        --
        "java", -- Or the absolute path '/path/to/java11_or_newer/bin/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",
        "/path/to/jdtls_install_location/plugins/org.eclipse.equinox.launcher_VERSION_NUMBER.jar",
        "-configuration", "/path/to/jdtls_install_location/config_SYSTEM",
        "-data", "/Users/YOUR_MACHINE_NAME/local/share/nvim/java"
    },
    settings = {
        java = {
            signatureHelp = {enabled = true},
            import = {enabled = true},
            rename = {enabled = true}
        }
    },
    init_options = {
        bundles = {}
    }
}

Upvotes: 2

JayBoCC2
JayBoCC2

Reputation: 91

I recommend using mfussenegger/nvim-jdtls to run and configure the language server.

Its simply a matter of setting up a FTPlugin for java that calls jdtls.start_or_attach(jdtls_config) whenever a java file/repo is opened which will start the language server and attach it to your buffer which can be verified by :LspInfo.

ftplugin/java.lua:

local jdtls_config = require("myconfig.lsp.jdtls").setup()
local pkg_status, jdtls = pcall(require,"jdtls")
if not pkg_status then
  vim.notify("unable to load nvim-jdtls", "error")
  return
end
jdtls.start_or_attach(jdtls_config)

and the corresponding config using jdtls (installed via mason) You may want to provide your own capabilities and on_attach functions but otherwise it should give you a good nudge in the right direction.

myconfig/lsp/jdtls.lua

local opts = {
  cmd = {},
  settings = {
    java = {
      signatureHelp = { enabled = true },
      completion = {
        favoriteStaticMembers = {},
        filteredTypes = {
          -- "com.sun.*",
          -- "io.micrometer.shaded.*",
          -- "java.awt.*",
          -- "jdk.*",
          -- "sun.*",
        },
      },
      sources = {
        organizeImports = {
          starThreshold = 9999,
          staticStarThreshold = 9999,
        },
      },
      codeGeneration = {
        toString = {
          template = "${object.className}{${member.name()}=${member.value}, ${otherMembers}}",
        },
        useBlocks = true,
      },
      configuration = {
        runtimes = {
          {
            name = "JavaSE-1.8",
            path = "/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home",
            default = true,
          },
          {
            name = "JavaSE-17",
            path = "/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home",
          },
          {
            name = "JavaSE-19",
            path = "/Library/Java/JavaVirtualMachines/jdk-19.jdk/Contents/Home",
          },
        },
      },
    },
  },
}

local function setup()
  local pkg_status, jdtls = pcall(require,"jdtls")
  if not pkg_status then
    vim.notify("unable to load nvim-jdtls", "error")
    return {}
  end

  -- local jdtls_path = vim.fn.stdpath("data") .. "/mason/packages/jdtls"
  local jdtls_bin = vim.fn.stdpath("data") .. "/mason/bin/jdtls"

  local root_markers = { ".gradle", "gradlew", ".git" }
  local root_dir = jdtls.setup.find_root(root_markers)
  local home = os.getenv("HOME")
  local project_name = vim.fn.fnamemodify(root_dir, ":p:h:t")
  local workspace_dir = home .. "/.cache/jdtls/workspace/" .. project_name

  opts.cmd = {
    jdtls_bin,
    "-data",
    workspace_dir,
  }


  local on_attach = function(client, bufnr)
    jdtls.setup.add_commands() -- important to ensure you can update configs when build is updated
    -- if you setup DAP according to https://github.com/mfussenegger/nvim-jdtls#nvim-dap-configuration you can uncomment below
    -- jdtls.setup_dap({ hotcodereplace = "auto" })
    -- jdtls.dap.setup_dap_main_class_configs()

    -- you may want to also run your generic on_attach() function used by your LSP config
  end

  opts.on_attach = on_attach
  opts.capabilities = vim.lsp.protocol.make_client_capabilities()

  return opts
end

return { setup = setup }

These examples are yanked from my personal neovim config (jdtls config). Hope this helps get you rolling.

Also make sure you have jdk17+ available for jdtls (i launch neovim with JAVA_HOME set to my jdk17 install) (your code can still be compiled by and run on jdk8 -- I successfully work on gradle projects that are built with jdk8 no problems w/ this config)

Upvotes: 3

Related Questions