# jdtls (Java Language Server) 使用指南 > 通过 Serena MCP 工具调用 jdtls 进行 Java 代码分析 ## 前置条件 ### 1. 确保 jdtls 已安装 jdtls 通常通过 VS Code 的 Java 扩展自动安装,或者手动安装: ```bash # 检查 jdtls 路径 which jdtls # 或 ls ~/.vscode/extensions/redhat.java-*/server/ ``` ### 2. 项目结构要求 jdtls 需要以下文件来识别 Java 项目: - Maven: `pom.xml` - Gradle: `build.gradle` 或 `build.gradle.kts` - Eclipse: `.project` 和 `.classpath` --- ## 通过 Serena 使用 jdtls ### 激活项目 ```yaml # Step 1: 激活 Java 项目 tool: mcp__serena__activate_project params: project: "/path/to/java/project" # 返回: 项目已激活,jdtls 已初始化 ``` ### 验证配置 ```yaml # 检查当前配置 tool: mcp__serena__get_current_config # 确认输出包含: # - active_project: /path/to/java/project # - language_server: jdtls ``` --- ## 符号提取操作 ### 获取文件符号概览 ```yaml # 获取单个文件的符号列表(不含代码体) tool: mcp__serena__get_symbols_overview params: relative_path: "src/main/java/com/example/OrderController.java" depth: 1 # 0=仅顶层, 1=含直接成员, 2=含嵌套成员 # 返回示例: # Classes: # - OrderController (class) [59-1241] # Methods: # - getOrderList (method) [120-145] # - createOrder (method) [150-180] # - updateOrder (method) [185-210] ``` ### 查找符号 ```yaml # 按名称模式查找符号 tool: mcp__serena__find_symbol params: name_path_pattern: "OrderController" # 可以是部分名称 relative_path: "src/main/java/" # 限定搜索范围 include_body: false # 是否包含代码体 include_info: true # 是否包含 hover 信息 depth: 1 # 包含成员的深度 # 名称模式规则: # - "OrderController" -> 匹配任何包含此名称的符号 # - "controller/OrderController" -> 匹配此路径后缀 # - "/com.example.OrderController" -> 精确匹配完整路径 # - "OrderController/getOrderList" -> 匹配类中的方法 # - "OrderController[0]" -> 匹配重载方法的第一个 ``` ### 获取符号详情(含代码体) ```yaml # 获取完整的符号定义(含代码) tool: mcp__serena__find_symbol params: name_path_pattern: "OrderService/saveOrder" relative_path: "src/main/java/com/example/service/OrderService.java" include_body: true depth: 0 # 返回包含: # - 方法签名 # - Javadoc 注释 # - 完整方法体 # - 行号范围 ``` --- ## 引用分析操作 ### 查找符号引用 ```yaml # 查找某个符号被哪些地方引用 tool: mcp__serena__find_referencing_symbols params: name_path: "OrderService/saveOrder" relative_path: "src/main/java/com/example/service/OrderService.java" include_info: true # 返回示例: # References (5 found): # - OrderController.createOrder [180:12-180:35] # snippet: "orderService.saveOrder(dto)" # - OrderController.updateOrder [210:12-210:35] # snippet: "orderService.saveOrder(updated)" # - OrderServiceTest.testSave [45:8-45:30] # snippet: "service.saveOrder(testDto)" ``` ### 模式搜索(补充 LSP) ```yaml # 当 LSP 无法找到时,使用模式搜索 tool: mcp__serena__search_for_pattern params: substring_pattern: "orderService\\.save" paths_include_glob: "**/*.java" restrict_search_to_code_files: true context_lines_before: 2 context_lines_after: 2 # 适用场景: # - 动态调用 (反射) # - 字符串拼接的方法名 # - 注解中的引用 ``` --- ## 调用链构建 ### 构建向下调用链 (callee) ```python # 伪代码: 递归构建调用链 def build_callee_chain(symbol_path, file_path, depth, max_depth): if depth > max_depth: return None # Step 1: 获取方法体 symbol = find_symbol( name_path_pattern=symbol_path, relative_path=file_path, include_body=True ) # Step 2: 在方法体中查找调用 # 使用 LSP 或正则匹配 calls = extract_method_calls(symbol.body) # Step 3: 对每个调用递归 callees = [] for call in calls: # 尝试定位被调用方法 target = find_symbol( name_path_pattern=call.method_name, relative_path=call.potential_file ) if target: callees.append({ 'symbol': target, 'evidence': call.location, 'children': build_callee_chain( target.path, target.file, depth + 1, max_depth ) }) return { 'symbol': symbol, 'callees': callees } ``` ### 实际操作步骤 ```yaml # 1. 获取入口方法 tool: mcp__serena__find_symbol params: name_path_pattern: "OrderController/createOrder" relative_path: "src/main/java/com/example/controller/" include_body: true depth: 0 # 2. 分析方法体中的调用 # 从返回的 body 中提取: orderService.saveOrder(dto) # 3. 定位被调用方法 tool: mcp__serena__find_symbol params: name_path_pattern: "OrderService/saveOrder" relative_path: "src/main/java/" include_body: true # 4. 查找该方法的引用(验证调用关系) tool: mcp__serena__find_referencing_symbols params: name_path: "OrderService/saveOrder" relative_path: "src/main/java/com/example/service/OrderService.java" # 5. 递归处理下一层 ``` --- ## Java 特有处理 ### 注解识别 ```yaml # 常见注解及其语义含义 API 入口点注解: - "@RestController": REST API 控制器 - "@Controller": MVC 控制器 - "@RequestMapping": 请求映射 - "@GetMapping": GET 请求 - "@PostMapping": POST 请求 - "@PutMapping": PUT 请求 - "@DeleteMapping": DELETE 请求 服务层注解: - "@Service": 业务服务 - "@Component": 通用组件 - "@Transactional": 事务方法 数据层注解: - "@Repository": 数据访问 - "@Mapper": MyBatis Mapper - "@Table": JPA 表映射 - "@Entity": JPA 实体 数据对象注解: - "@Data": Lombok 数据类 - "@Getter/@Setter": Lombok 访问器 - "@Builder": Lombok 构建器 ``` ### MyBatis Mapper 处理 ```yaml # MyBatis Mapper 接口无法通过 LSP 追踪到 SQL # 需要关联 XML 文件 # 1. 找到 Mapper 接口 tool: mcp__serena__find_symbol params: name_path_pattern: "OrderMapper" relative_path: "src/main/java/" # 2. 查找对应的 XML tool: mcp__serena__search_for_pattern params: substring_pattern: "OrderMapper" paths_include_glob: "**/*.xml" # 3. 读取 XML 获取 SQL 定义 tool: mcp__serena__list_dir params: relative_path: "src/main/resources/mapper/" ``` --- ## LSP SymbolKind 映射 ```yaml # jdtls 返回的 SymbolKind 数值对照 1: File 2: Module 3: Namespace 4: Package 5: Class # 类 6: Method # 方法 7: Property 8: Field # 字段 9: Constructor # 构造函数 10: Enum # 枚举 11: Interface # 接口 12: Function # 函数 13: Variable # 变量 14: Constant # 常量 15: String 16: Number 17: Boolean 18: Array 19: Object 20: Key 21: Null 22: EnumMember # 枚举值 23: Struct 24: Event 25: Operator 26: TypeParameter # 泛型参数 ``` --- ## 常见问题 ### Q: jdtls 启动慢 ``` A: 首次打开项目时,jdtls 需要构建索引。 - Maven 项目: 会下载依赖 - 大项目: 索引可能需要几分钟 建议: 等待 Serena 报告项目就绪 ``` ### Q: 找不到符号 ``` A: 可能原因: 1. 项目未正确识别 (缺少 pom.xml 或 build.gradle) 2. 编译错误导致索引不完整 3. 符号在排除目录中 解决: 1. 确保项目根目录正确 2. 先执行 mvn compile 或 gradle build 3. 使用 search_for_pattern 作为备选 ``` ### Q: 引用结果不完整 ``` A: jdtls 的 references 可能遗漏: 1. 反射调用 2. 字符串拼接的方法名 3. 动态代理 解决: 使用 search_for_pattern 补充搜索 ``` --- ## 最佳实践 1. **先概览后详细** - 用 `get_symbols_overview` 了解文件结构,再用 `find_symbol` 获取详情 2. **限定搜索范围** - 总是传入 `relative_path` 以提高效率 3. **分批处理** - 大项目分模块处理,避免一次性加载全部 4. **缓存结果** - 符号信息变化不频繁,可以缓存复用 5. **结合搜索** - LSP 不足时用 `search_for_pattern` 补充