nvim-java icon indicating copy to clipboard operation
nvim-java copied to clipboard

bug: Formatter fails when lombok imports are present

Open vchernetskyi993 opened this issue 5 months ago • 12 comments

Did you check docs and existing issues?

  • [x] I have read all the plugin docs
  • [x] I have searched the existing issues
  • [x] I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

v0.12.0-dev

Operating system/version

Ubuntu 24.04.2 LTS

Describe the bug

Trying to format some of the Java files fails with errors like:

[ERROR][2025-08-10 16:27:23] ...p/_transport.lua:36	"rpc"	"java"	"stderr"	"Aug 10, 2025 4:27:23 PM org.eclipse.lsp4j.jsonrpc.RemoteEndpoint fallbackResponseError
SEVERE: Internal error: java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 64
java.util.concurrent.CompletionException: java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 64
\tat java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315)
\tat java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320)
\tat java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:649)
\tat java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:483)
\tat java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
\tat java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
\tat java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
\tat java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
\tat java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)
Caused by: java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 64
\tat java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100)
\tat java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106)
\tat java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302)
\tat java.base/java.util.Objects.checkIndex(Objects.java:385)
\tat java.base/java.util.ArrayList.get(ArrayList.java:427)
\tat org.eclipse.jdt.internal.formatter.TokenManager.get(TokenManager.java:78)
\tat org.eclipse.jdt.internal.formatter.TokenManager.findIndex(TokenManager.java:172)
\tat org.eclipse.jdt.internal.formatter.TokenManager.lastIndexIn(TokenManager.java:205)
\tat org.eclipse.jdt.internal.formatter.LineBreaksPreparator.handleBracedCode(LineBreaksPreparator.java:664)
\tat org.eclipse.jdt.internal.formatter.LineBreaksPreparator.visit(LineBreaksPreparator.java:229)
\tat org.eclipse.jdt.core.dom.MethodDeclaration.accept0(MethodDeclaration.java:652)
\tat org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:3312)
\tat org.eclipse.jdt.core.dom.ASTNode.acceptChildren(ASTNode.java:3383)
\tat org.eclipse.jdt.core.dom.TypeDeclaration.accept0(TypeDeclaration.java:497)
\tat org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:3312)
\tat org.eclipse.jdt.core.dom.ASTNode.acceptChildren(ASTNode.java:3383)
\tat org.eclipse.jdt.core.dom.CompilationUnit.accept0(CompilationUnit.java:257)
\tat org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:3312)
\tat org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.prepareLineBreaks(DefaultCodeFormatter.java:418)
\tat org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.prepareFormattedCode(DefaultCodeFormatter.java:229)
\tat org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.format(DefaultCodeFormatter.java:185)
\tat org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.format(DefaultCodeFormatter.java:169)
\tat org.eclipse.jdt.ls.core.internal.handlers.FormatterHandler.format(FormatterHandler.java:120)
\tat org.eclipse.jdt.ls.core.internal.handlers.FormatterHandler.format(FormatterHandler.java:107)
\tat org.eclipse.jdt.ls.core.internal.handlers.FormatterHandler.formatting(FormatterHandler.java:78)
\tat org.eclipse.jdt.ls.core.internal.handlers.JDTLanguageServer.lambda$19(JDTLanguageServer.java:840)
\tat org.eclipse.jdt.ls.core.internal.BaseJDTLanguageServer.lambda$0(BaseJDTLanguageServer.java:87)
\tat java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:646)
\t... 6 more"

Removing/commenting parts of the code I've figured out that if I delete/comment lombok imports formatting starts working again.

Steps To Reproduce

I've created minimum reproducible example, using Spring Initializr: DemoApplication.java.

With import lombok.AllArgsConstructor; trying to format this file produces error above for me. When I comment this line - formatting works again.

Expected Behavior

Java files are formatted without an error. The same file formatting works in VS Code, so I assume this is not an issue with a language server itself (maybe an issue with server version though).

vchernetskyi993 avatar Aug 10 '25 13:08 vchernetskyi993

What's probably worth mentioning, is that when I replace my setup configuration:

require("lspconfig").jdtls.setup {
  root_markers = { ".git" },
  settings = {
    java = {
      configuration = {
        runtimes = java_runtimes("21"),
      },
      symbols = {
        includeSourceMethodDeclarations = true,
      },
    },
  },
}

With 0.11+ configuration style:

vim.lsp.config("jdtls", {
  root_markers = { ".git" },
  settings = {
    java = {
      configuration = {
        runtimes = java_runtimes("21"),
      },
      symbols = {
        includeSourceMethodDeclarations = true,
      },
    },
  },
})
vim.lsp.enable("jdtls")

Formatting starts working, but a lot of other features stop (from what I noticed: at least Maven library references, Lombok, Spring Boot).

vchernetskyi993 avatar Aug 11 '25 07:08 vchernetskyi993

Hello, I'm pretty certain it is a configuration issue but I can look into it a little bit later.

Just passing by to let you know you're not talking to yourself :)

logrusx avatar Aug 11 '25 08:08 logrusx

That's definitely possible, but I spent several hours yesterday trying to tweak my configuration to no avail. That's why came here for help :)

Here is a related chunk of my lazy configuration:

local function java_runtimes(default)
  return require("utils").map(
    io.popen("find ~/.sdkman/candidates/java/ -mindepth 1 -maxdepth 1 -type d")
      :lines(),
    function(directory)
      local name = vim.fn.fnamemodify(directory, ":t")
      return {
        name = name,
        path = directory,
        default = name:sub(1, #default) == default,
      }
    end
  )
end

return {
  {
    "williamboman/mason.nvim",
    opts = {},
  },
  {
    "neovim/nvim-lspconfig",
    dependencies = {
      "williamboman/mason-lspconfig.nvim",
      "b0o/schemastore.nvim",
      "aznhe21/actions-preview.nvim",
      "lewis6991/hover.nvim",
      "nvim-java/nvim-java",
      "folke/neoconf.nvim",
    },
    config = function()
      require("java").setup {
        root_markers = {
          ".git",
        },
        jdk = {
          auto_install = false,
        },
      }
      require("neoconf").setup {}
      require("lspconfig").jdtls.setup {
        root_markers = { ".git" },
        settings = {
          java = {
            configuration = {
              runtimes = java_runtimes("21"),
            },
            symbols = {
              includeSourceMethodDeclarations = true,
            },
          },
        },
      }
      require("mason-lspconfig").setup {
        ensure_installed = {
          "jsonls",
          "yamlls",
          "cspell_ls",
          "lua_ls",
          "bashls",
        },
      }

     -- ... configs for other LSP-related stuff ...

UPD: here is LspInfo output for jdtls:

- jdtls (id: 2)
  - Version: ? (no serverInfo.version response)
  - Root directory: ~/repo/public/jdtls-formatter-issue
  - Command: { "java", "-Declipse.application=org.eclipse.jdt.ls.core.id1", "-Dosgi.bundles.defaultStartLevel=4", "-Declipse.product=org.eclipse.jdt.ls.core.product", "-Dosgi.checkConfiguration=true", "-Dosgi.sharedConfiguration.area=/home/chernetskyi/.local/share/nvim/mason/share/jdtls/config", "-Dosgi.sharedConfiguration.area.readOnly=true", "-Dosgi.configuration.cascaded=true", "-Xms1G", "--add-modules=ALL-SYSTEM", "--add-opens", "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-javaagent:/home/chernetskyi/.local/share/nvim/mason/share/lombok-nightly/lombok.jar", "-jar", "/home/chernetskyi/.local/share/nvim/mason/share/jdtls/plugins/org.eclipse.equinox.launcher.jar", "-configuration", "/home/chernetskyi/.cache/nvim/jdtls/config", "-data", "/home/chernetskyi/.cache/nvim/jdtls/workspaces/_home_chernetskyi" }
  - Settings: {
      java = {
        configuration = {
          runtimes = { {
              default = false,
              name = "8.0.432-amzn",
              path = "/home/chernetskyi/.sdkman/candidates/java/8.0.432-amzn"
            }, {
              default = true,
              name = "21.0.6-amzn",
              path = "/home/chernetskyi/.sdkman/candidates/java/21.0.6-amzn"
            }, {
              default = false,
              name = "17.0.12-amzn",
              path = "/home/chernetskyi/.sdkman/candidates/java/17.0.12-amzn"
            } }
        },
        symbols = {
          includeSourceMethodDeclarations = true
        }
      }
    }
  - Attached buffers: 20

vchernetskyi993 avatar Aug 11 '25 08:08 vchernetskyi993

Are you expecting to define a runtime for jdtls to run on? If yes, this is not how nvim-java works. It'll use whatever the java command points to. That's what's in the source code. What you're trying to do will only set the source compatibility level.

If you're trying to set source compatibility level, then I suggest trying to hard-code it jut to make sure it's not your java_runtimes function causing it. Also look at my last two comments in #399 for how it's done.

This issue is essentially a duplicate of #399

logrusx avatar Aug 11 '25 13:08 logrusx

Okay, tried without SDKMAN JDKs.

here is new simplified configuration:

require("java").setup {
  root_markers = {
    ".git",
  },
}
require("neoconf").setup {}
require("lspconfig").jdtls.setup {
  root_markers = { ".git" },
  settings = {
    java = {
      symbols = {
        includeSourceMethodDeclarations = true,
      },
    },
  },
}

Mason downloads openjdk-17 successfully:

    ◍ openjdk-17
      The Java Development Kit is a distribution of Java Technology by Oracle Corporation.
      It implements the Java Language Specification and the Java Virtual Machine Specification
      and provides the Standard Edition of the Java Application Programming Interface.


      installed version 17.0.2                                    
      installed purl    pkg:generic/java/[email protected]           
      homepage          https://github.com/eclipse/eclipse.jdt.ls 
      languages         Java                                      
      categories        Runtime                                   
      executables       java                                      

Here is output of new LspInfo:

- jdtls (id: 3)
  - Version: ? (no serverInfo.version response)
  - Root directory: ~/repo/public/jdtls-formatter-issue
  - Command: { "java", "-Declipse.application=org.eclipse.jdt.ls.core.id1", "-Dosgi.bundles.defaultStartLevel=4", "-Declipse.product=org.eclipse.jdt.ls.core.product", "-Dosgi.checkConfiguration=true", "-Dosgi.sharedConfiguration.area=/home/chernetskyi/.local/share/nvim/mason/share/jdtls/config", "-Dosgi.sharedConfiguration.area.readOnly=true", "-Dosgi.configuration.cascaded=true", "-Xms1G", "--add-modules=ALL-SYSTEM", "--add-opens", "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-javaagent:/home/chernetskyi/.local/share/nvim/mason/share/lombok-nightly/lombok.jar", "-jar", "/home/chernetskyi/.local/share/nvim/mason/share/jdtls/plugins/org.eclipse.equinox.launcher.jar", "-configuration", "/home/chernetskyi/.cache/nvim/jdtls/config", "-data", "/home/chernetskyi/.cache/nvim/jdtls/workspaces/_home_chernetskyi" }
  - Settings: {
      java = {
        symbols = {
          includeSourceMethodDeclarations = true
        }
      }
    }
  - Attached buffers: 20

But the formatting issue for DemoApplication.java is still there.

vchernetskyi993 avatar Aug 11 '25 15:08 vchernetskyi993

root_markers = { ".git" }, why is that in jdtls.setup?

Delete it from there and tell me if it works. Also move the neoconf setup before java setup.

Also show the full LspInfo output.

logrusx avatar Aug 11 '25 16:08 logrusx

Using root_markers = { ".git" }, because for multi-module projects, without this language server uses each module as root (since each module contains own pom.xml), while I want single server for all modules. But this specific example is single-module, so I can drop it for testing.

Removed custom configurations completely and moved neoconf before java:

require("neoconf").setup {}
require("java").setup {
}
require("lspconfig").jdtls.setup {
}
require("mason-lspconfig").setup {
  ensure_installed = {
    "jsonls",
    "yamlls",
    "cspell_ls",
    "lua_ls",
    "bashls",
  },
}

Still reproducible for me for DemoApplication.java. Can you try if formatting works for you on this small file?

Full LspInfo output: LspInfo.txt.

vchernetskyi993 avatar Aug 11 '25 17:08 vchernetskyi993

You're right, it doesn't work. I'm sorry for making you try all this unnecessary stuff. However I know the reason it doesn't work.

When I tried your test application I also had to go back to the official release of nvim-java which pulls jdtls 1.43.0 from Mason. And that's the reason. I was with 1.46 and it worked.

You can try to set a newer version for jdtls in nvim-java setup like that:

require("java").setup {
    jdtls = { version = "v1.48.0" },
    -- newer jdk is also necessary, I assume you have it on your computer
    jdk = { auto_install = false },
}

You can also try my fork which installs latest versions by default. There are instructions in the readme.

p.s. while running your test by mistake with nvim-jdtls I also realized there's something wrong with my project, so thank you for asking me do it.

logrusx avatar Aug 11 '25 19:08 logrusx

Tried to use your fork like so:

{
  "logrusx/nvim-java",
  branch = "use-latest-versions-available-in-mason-registry",
  dependencies = {
    {
      "logrusx/nvim-java-core",
      branch = "migrate-to-official-mason-repo",
    },
  },
}

As expected, on the next start-up Mason updated java-test to 0.43.1, vscode-spring-boot-tools to 1.59.0, and jdtls to 1.48.0.

When opening any Java file, I receive the following message:

Client jdtls quit with exit code 13 and signal 0. Check log for errors: /home/chernetskyi/.local/state/nvim/lsp.log

These are the only errors I've found in LspLog, which look related:

[ERROR][2025-08-12 10:49:43] ...p/_transport.lua:36	"rpc"	"java"	"stderr"	"WARNING: Using incubator modules: jdk.incubator.foreign, jdk.incubator.vector\n"
[WARN][2025-08-12 10:49:43] ...m/lsp/client.lua:870	"The language server cspell_ls triggers a registerCapability handler for workspace/didChangeConfiguration despite dynamicRegistration set to false. Report upstream, this warning is harmless"
[WARN][2025-08-12 10:49:43] ...m/lsp/client.lua:870	"The language server cspell_ls triggers a registerCapability handler for workspace/didChangeWorkspaceFolders despite dynamicRegistration set to false. Report upstream, this warning is harmless"
[ERROR][2025-08-12 10:49:44] ...p/_transport.lua:36	"rpc"	"/home/chernetskyi/.sdkman/candidates/java/current/bin/java"	"stderr"	"Disabling server log output. No more output will be sent after this.\n"
[ERROR][2025-08-12 10:49:44] ...p/_transport.lua:36	"rpc"	"java"	"stderr"	"Aug 12, 2025 9:49:44 AM org.apache.aries.spifly.BaseActivator log\nINFO: Registered provider ch.qos.logback.classic.spi.LogbackServiceProvider of service org.slf4j.spi.SLF4JServiceProvider in bundle ch.qos.logback.classic\n"

/home/chernetskyi/.sdkman/candidates/java/current/bin/java from the error above points to my default JDK:

openjdk version "21.0.6" 2025-01-21 LTS
OpenJDK Runtime Environment Corretto-21.0.6.7.1 (build 21.0.6+7-LTS)
OpenJDK 64-Bit Server VM Corretto-21.0.6.7.1 (build 21.0.6+7-LTS, mixed mode, sharing)

vchernetskyi993 avatar Aug 12 '25 07:08 vchernetskyi993

When opening any Java file, I receive the following message:

Client jdtls quit with exit code 13 and signal 0. Check log for errors: /home/chernetskyi/.local/state/nvim/lsp.log

I think I've hit that before. Jdtls cannot deal with its own mess created from previous versions. Try deleting ~/.cache/nvim/jdtls/workspaces/. If that doesn't work, open an issue in my fork, so we don't pollute this one.

logrusx avatar Aug 12 '25 08:08 logrusx

Did clean rebuild as described in https://github.com/nvim-java/nvim-java/wiki/Troubleshooting#no_entry-how-to-clean-rebuild. The same error message.

Let me log an issue in your fork, then.

vchernetskyi993 avatar Aug 12 '25 08:08 vchernetskyi993

In short: either jdtls version should be bumped or lombok should be locked at a specific version, but I don't know which. I'll consider it in more depth in the coming weeks.

logrusx avatar Aug 12 '25 10:08 logrusx