Setting Up Java LSP and Debugger in Neovim with Lazy.nvim
In this guide, we will cover the step-by-step process to set up Java Language Server Protocol (LSP) and debugging capabilities in Neovim using the lazy.nvim
plugin manager. We’ll use the nvim-jdtls
plugin for LSP functionalities and nvim-dap
for debugging support, ensuring an efficient Java development environment within Neovim.
Prerequisites
- Neovim: Ensure that you have Neovim installed (version 0.8 or later).
- Java Development Kit (JDK): Install a compatible version of the JDK.
- Maven/Gradle: Preferred build tool for Java projects.
mason.nvim
: For managing LSP servers, DAPs, and other tooling.lazy.nvim
: For plugin management.
If not already installed, you can install lazy.nvim
as follows:
git clone https://github.com/folke/lazy.nvim.git ~/.config/nvim/lazy.nvim
Step 1: Plugin Configuration with lazy.nvim
Initial Plugin Setup
In your Neovim configuration, create a lua/plugins.lua
file (if it doesn’t already exist) and add the following content for the Java LSP and Debugger setup:
return {
-- Java Language Server
'mfussenegger/nvim-jdtls',
-- Debug Adapter Protocol (DAP)
'mfussenegger/nvim-dap',
dependencies = {
'rcarriga/nvim-dap-ui',
'williamboman/mason.nvim',
'jay-babu/mason-nvim-dap.nvim',
'leoluz/nvim-dap-go', -- Go debugger
{ 'mfussenegger/nvim-dap-python', ft = 'python' }, -- Python debugger
},
}
DAP Configuration
Create a file named debug.lua
and add the following content:
return {
'mfussenegger/nvim-dap',
dependencies = {
'rcarriga/nvim-dap-ui',
'nvim-neotest/nvim-nio',
'williamboman/mason.nvim',
'jay-babu/mason-nvim-dap.nvim',
'leoluz/nvim-dap-go',
{ 'mfussenegger/nvim-dap-python', ft = 'python' },
},
keys = function(_, keys)
local dap = require 'dap'
local dapui = require 'dapui'
return {
{ '<F5>', dap.continue, desc = 'Debug: Start/Continue' },
{ '<F1>', dap.step_into, desc = 'Debug: Step Into' },
{ '<F2>', dap.step_over, desc = 'Debug: Step Over' },
{ '<F3>', dap.step_out, desc = 'Debug: Step Out' },
{ '<leader>b', dap.toggle_breakpoint, desc = 'Debug: Toggle Breakpoint' },
{ '<leader>B', function() dap.set_breakpoint(vim.fn.input 'Breakpoint condition: ') end, desc = 'Debug: Set Breakpoint' },
{ '<F7>', dapui.toggle, desc = 'Debug: See last session result.' },
unpack(keys),
}
end,
config = function()
local dap = require 'dap'
local dapui = require 'dapui'
dap.configurations.java = {
{ type = 'java', name = 'Integration', request = 'launch', main = '', console = 'internalConsole', args = '${command:SpecifyProgramArgs}', vmArgs = '-Dspring.profiles.active=integration' },
{ type = 'java', name = 'local', request = 'launch', main = '', console = 'internalConsole', args = '${command:SpecifyProgramArgs}', vmArgs = '-Dspring.profiles.active=local' },
{ type = 'java', name = 'test', request = 'launch', main = '', console = 'internalConsole', args = '${command:SpecifyProgramArgs}', vmArgs = '-Dspring.profiles.active=test' },
}
require('mason-nvim-dap').setup {
automatic_installation = true,
ensure_installed = { 'delve', 'debugpy' },
}
dapui.setup { icons = { expanded = '▾', collapsed = '▸', current_frame = '*' } }
dap.listeners.after.event_initialized['dapui_config'] = dapui.open
dap.listeners.before.event_terminated['dapui_config'] = dapui.close
dap.listeners.before.event_exited['dapui_config'] = dapui.close
require('dap-go').setup { delve = { detached = vim.fn.has 'win32' == 0 } }
require('dap-python').setup '~/.pyenv/versions/3.12.1/bin/python'
end,
}
JDTLS Configuration
Create a java-lsp.lua
file to handle the LSP setup for Java:
local jdtls = require 'jdtls'
local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ':p:h:t')
local workspace_dir = '/home/rahul/neo-java/' .. project_name
local lsp_capabilities = require('cmp_nvim_lsp').default_capabilities()
local bundles = {
vim.fn.glob('/home/rahul/.local/share/nvim/mason/packages/java-debug-adapter/extension/server/com.microsoft.java.debug.plugin-0.53.0.jar', 1),
}
vim.list_extend(bundles, vim.split(vim.fn.glob('/home/rahul/.local/share/nvim/mason/packages/java-test/extension/server/*.jar', 1), '\n'))
local config = {
capabilities = lsp_capabilities,
cmd = {
'/home/rahul/.sdkman/candidates/java/current/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',
'-javaagent:/home/rahul/software/jdtls/lombok.jar',
'-Xmx1g',
'--add-modules=ALL-SYSTEM',
'--add-opens',
'java.base/java.util=ALL-UNNAMED',
'--add-opens',
'java.base/java.lang=ALL-UNNAMED',
'-jar',
'/home/rahul/software/jdtls/plugins/org.eclipse.equinox.launcher_1.6.900.v20240613-2009.jar',
'-configuration',
'/home/rahul/software/jdtls/config_linux/',
'-data',
workspace_dir,
},
root_dir = require('jdtls.setup').find_root { '.git', 'mvnw', 'gradlew', 'pom.xml', 'build.gradle' },
settings = {
java = {
signatureHelp = { enabled = true },
contentProvider = { preferred = 'fernflower' },
completion = {
favoriteStaticMembers = { 'org.hamcrest.MatcherAssert.assertThat', 'org.hamcrest.Matchers.*', 'org.junit.jupiter.api.Assertions.*', 'java.util.Objects.requireNonNull' },
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}}' }, hashCodeEquals = { useJava7Objects = true }, useBlocks = true },
},
},
init_options = { extendedClientCapabilities = jdtls.extendedClientCapabilities, bundles = bundles },
}
jdtls.start_or_attach(config)
Step 2: Debugging Java Code
With the DAP setup in place, use the following keybindings to start debugging:
<F5>
: Start/Continue Debugging<F1>
: Step Into<F2>
: Step Over<F3>
: Step Out<leader>b
: Toggle Breakpoint<leader>B
: Set Conditional Breakpoint
Conclusion
This guide shows how to set up a comprehensive Java development environment in Neovim using lazy.nvim
for plugin management. The setup includes LSP configuration through nvim-jdtls
and debugging capabilities using nvim-dap
. With this setup, you can seamlessly develop and debug Java applications within Neovim.
For further customization or advanced features, refer to the respective plugin documentation:
Also refer troubleshooting Jdtls