Java LSP : Hover definition works but definition doesn't
- Dominant language
- Shell
- Stars
- 11.2k
- Forks
- 1.9k
- Avg merge
- 14h 16m
- Merged PRs (30d)
- 6
Description
### Describe the bug
`goToDefinition` via the LSP tool returns "No definition found" for **all types defined in Maven/Gradle dependency JARs** (e.g., Spring Framework, LangChain4j), even though `hover` at the exact same position correctly returns full type info and Javadoc from those same JARs.
### Root cause
During JDTLS initialization, the Copilot CLI does not send `extendedClientCapabilities.classFileContentsSupport: true` in `initializationOptions`. Without this flag, JDTLS will not return `jdt://` URIs in `textDocument/definition` responses for classes inside JARs — it returns null instead.
The relevant code in `app.js` constructs `initializationOptions` from `this.config.lspInitializationOptions`, but `lsp-config.json` has no such field, so it is `undefined`.
### Steps to reproduce
1. Configure JDTLS in `~/.copilot/lsp-config.json`:
```json
{
"lspServers": {
"java": {
"command": "jdtls",
"args": ["-data", "/tmp/jdtls-workspace"],
"fileExtensions": { ".java": "java" }
}
}
}
```
2. Open any Java project with Maven/Gradle dependencies
3. Run `hover` on a dependency type (e.g., `ChatModel` from LangChain4j, or `@Controller` from Spring):
```
> lsp hover ChatModel on line 43
✅ Returns: "dev.langchain4j.model.chat.ChatModel — Represents a language model..."
Source: langchain4j-core-1.11.0.jar
```
4. Run `goToDefinition` at the **exact same position**:
```
> lsp goToDefinition ChatModel on line 43
❌ Returns: "No definition found at line 43, character 25."
```
This affects all dependency types — Spring (`@Controller`, `@GetMapping`), LangChain4j (`ChatModel`, `UserMessage`), etc. Navigation to project-local classes works fine.
### Proposed fix
**1. Send `extendedClientCapabilities` during JDTLS initialization:**
Add `classFileContentsSupport: true` to the initialization options sent to JDTLS. This could be done via a new `lspInitializationOptions` field in `lsp-config.json`, or hardcoded for the Java/JDTLS server:
```json
{
"initializationOptions": {
"extendedClientCapabilities": {
"classFileContentsSupport": true
}
}
}
```
With this flag, JDTLS will return `LocationLink` objects with `jdt://contents/...` URIs for classes in JARs.
**2. Handle `jdt://` URIs in definition responses:**
When the LSP tool receives a definition result with a `jdt://` URI:
- Send a `java/classFileContents` request to JDTLS with that URI
- JDTLS responds with the decompiled (or source-attached) Java source code
- Display the source at the indicated range, similar to how VS Code shows read-only decompiled class files
### Additional context
The `getClientCapabilities()` method in `app.js` already declares `definition: { linkSupport: true }`, so the LSP protocol side is correct. The only missing piece is the JDTLS-specific `extendedClientCapabilities`.
This would also benefit `goToImplementation` for interfaces defined in JARs, and `findReferences` completeness for dependency types.
Related: #1349 (broader Java/JVM ecosystem awareness)
### Additional context
### Environment
- **Copilot CLI**: 1.0.6
- **JDTLS**: 1.57.0 (via Homebrew)
- **OS**: macOS (Apple Silicon)
- **Java project**: Spring Boot with Maven dependencies
Contributor guide
Assessment
This issue has not been assessed yet.