Wondering how to get Java setup in Neovim? Here’s what I have learned and configured so far.
What do we want?
With Java development, there are some expectations that an editor should fullfill so that we can be productive.
Here are a few items that I have come to expect when developing software in Java:
smart code completion
diagnostics (tell me when I have syntax errors)
hover information
definition lookup
method signature help
automatic imports (who really remembers all the package names?!)
There are other items, like running & debugging tests that I also expect but will revisit that in a future article.
Now that we have a list of what we want to enable in Neovim, let’s see some of our options.
Options
chris@machine video using COC
This is a great video explaining how to use CoC.nvim to connect Neovim with the JDTLS.
This video is a bit old now, so I would only recommend this path if you are already using CoC.nvim and know your way around advanced configurations.
Most folks are using the LSP Client in Neovim now, which is my preferred option.
Manually Configuring jdtls
If you want to setup all the pieces yourself and need to edit things like the Java command that gets executed when attaching to a buffer, then this is the path for you.
This option targets users with some experience with Neovim, Java and its build tools who prefer configuration as code over GUI configuration.
The pieces we will need with this option are:
JDTLS
Java JDK
nvim-jdtls
configuration for nvim-jdtls
GitHub - mfussenegger/nvim-jdtls: Extensions for the built-in LSP support in Neovim for…
Extensions for the built-in LSP support in Neovim for eclipse.jdt.ls - GitHub - mfussenegger/nvim-jdtls: Extensions for…github.com
Install JDTLS
Install this using Mason by adding “jdtls” to your list of servers.
Install Java JDK
There are a number of options for downloading and configuring the Java JDK on your machine. I personally recommend sdkman or asdf to install and version your JDKs.
To configure using asdf:
asdf plugin-add java https://github.com/halcyon/asdf-java.git
asdf install java temurin-21.0.2+13.0.LTS
asdf use java temurin-21.0.2+13.0.LTS
You will also need mvn
installed:
brew install mvn
Setup Neovim
If you are using something like kickstart.nvim, then you should add “java” under your list of treesitter.nvim grammars to install.
After that add jdtls to your Mason and Mason-lspconfig
If this doesn’t quite make sense then check out my previous blog on LSPs:
Next, create a java.lua file underneath your ftplugins directory (this is at the root level if you don’t have an ftplugins directory already).
Add this quickstart configuration to that file, which will attach JDTLS to our buffer when it detects a file type of java.
local config = {
cmd = {vim.fn.expand("~/.local/share/nvim/mason/bin/jdtls")},
root_dir = vim.fs.dirname(vim.fs.find({'gradlew', '.git', 'mvnw'}, { upward = true })[1]),
}
require('jdtls').start_or_attach(config)
If you need to do other customizations, then check out the full documentation for nvim-jdtls.
If you want to configure lombok you will need to use the full customization and add something like this into the cmd:
local home = os.getenv 'HOME'
local workspace_path = home .. '/.local/share/KickstartNvim/jdtls-workspace/'
local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ':p:h:t')
local workspace_dir = workspace_path .. project_name
local status, jdtls = pcall(require, 'jdtls')
if not status then
return
end
local extendedClientCapabilities = jdtls.extendedClientCapabilities
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',
'-Xmx1g',
'--add-modules=ALL-SYSTEM',
'--add-opens',
'java.base/java.util=ALL-UNNAMED',
'--add-opens',
'java.base/java.lang=ALL-UNNAMED',
'-javaagent:' .. home .. '/.local/share/KickstartNvim/mason/packages/jdtls/lombok.jar',
'-jar',
vim.fn.glob(home .. '/.local/share/KickstartNvim/mason/packages/jdtls/plugins/org.eclipse.equinox.launcher_*.jar'),
'-configuration',
home .. '/.local/share/KickstartNvim/mason/packages/jdtls/config_mac',
'-data',
workspace_dir,
},
root_dir = require('jdtls.setup').find_root { '.git', 'mvnw', 'gradlew', 'pom.xml', 'build.gradle' },
settings = {
java = {
signatureHelp = { enabled = true },
extendedClientCapabilities = extendedClientCapabilities,
maven = {
downloadSources = true,
},
referencesCodeLens = {
enabled = true,
},
references = {
includeDecompiledSources = true,
},
inlayHints = {
parameterNames = {
enabled = 'all', -- literals, all, none
},
},
format = {
enabled = false,
},
},
},
init_options = {
bundles = {},
},
}
require('jdtls').start_or_attach(config)
If you run into issues with lombok then you probably want to install the nightly version, see this Github issue.
Finally, add nvim-jdtls to your lazy.nvim config (either in a separate file under plugins or inline in a Lua table)
{'mfussenegger/nvim-jdtls'}
If you restart Neovim, you should see our plugins and JDTLS install without errors.
From this point you should be able to open up a Java project and see everything from our items list working in Neovim.
If you need an example Java project, you can generate one using
gradle init
or spring-initializr.
Using nvim-java
If you prefer ease of use over everything else and just want to add a new plugin and get off the ground with Java Development, then this is the option for you.
Out of the box you will get support for Lombok, Running Tests, Debugging Tests, and all the items we listed in the beginning.
The plugin we will install is nvim-java.
GitHub - nvim-java/nvim-java: Painless Java in Neovim
Painless Java in Neovim. Contribute to nvim-java/nvim-java development by creating an account on GitHub.github.com
First, add this either as a new file under plugins or in your lazy.nvim plugins section (omit the return if you are doing this inline).
return {
'nvim-java/nvim-java',
dependencies = {
'nvim-java/lua-async-await',
'nvim-java/nvim-java-core',
'nvim-java/nvim-java-test',
'nvim-java/nvim-java-dap',
'MunifTanjim/nui.nvim',
'neovim/nvim-lspconfig',
'mfussenegger/nvim-dap',
{
'williamboman/mason.nvim',
opts = {
registries = {
'github:nvim-java/mason-registry',
'github:mason-org/mason-registry',
},
},
}
},
}
Next, add this line before your lspconfig setup:
require('java').setup()
Finally, add this line after your lspconfig:
require('lspconfig').jdtls.setup({})
APIs
To make use of the run tests and debug tests functionality, make sure to add some keymaps for these two functions:
vim.keymap.set("n", "<leader>rjt", "<cmd>require('java').test.run_current_class()<CR>", { desc = "Run Java Test" })
vim.keymap.set("n", "<leader>djt", "<cmd>require('java').test.debug_current_class()<CR>", { desc = "Debug Java Test" })
Conclusion
If you can get away with a simpler approach then nvim-java is a pretty nice setup. JDTLS is not too bad to configure manually but you should know a little about Neovim configurations and Java project setup. I hope this video helped, let me know in the comments if you find another way to configure Neovim for Java Development.
Here are a few other Neovim articles you might be interested in:
If you enjoy topics like this then you might also like my Youtube channel. Have a great day!