Skip to content

[Bug] Spring Endpoint 将自定义 Mapping 注解前缀误识别为端点 #316

Description

@1lck

Platform / 平台

Rust Core(macOS / Windows 共用)

Lithe version / Lithe 版本

0cdc30b#306 合并提交)

OS and architecture / 操作系统与架构

平台无关,问题位于 rust/lithe-core/src/languages/spring.rsendpoint_index / mapping() 路径。

Environment / 环境信息

这是 #299#306 的后续解析正确性问题。#306 为 Spring 索引中的固定正则增加了缓存,并为 Bean、组件和注入等已登记注解建立了准确名称边界;Endpoint Mapping 仍保留合并前的朴素 contains 检测。

该行为在 #306 之前已经存在,不代表性能修复需要回滚。由于它属于端点索引而非 Bean 命名,单独跟踪,避免与 #315 混在一个修复中。

Steps to reproduce / 复现步骤

在一个可被 Spring 端点索引识别的 Controller 中使用名称带标准注解前缀的自定义注解:

@RestController
public class DemoController {
    @GetMappingCustom("/x")
    public String custom() { return ""; }
}

也可以直接对 mapping() 验证:

mapping("@GetMappingCustom(\"/x\")")

当前实现依次执行:

if annotation_text.contains("@GetMapping") { ... }

因此返回:

methods = ["GET"]
routes = ["/x"]

@RequestMappingFoo@PostMappingCustom@PutMappingCustom@DeleteMappingCustom@PatchMappingCustom 存在同类风险。

Expected behavior / 预期行为

只有准确的 Spring Mapping 注解名称才应生成端点:

  • @GetMapping@PostMapping@PutMapping@DeleteMapping@PatchMapping
  • @RequestMapping

名称只是以这些字符串开头的自定义注解不应被当作端点。示例中的 @GetMappingCustom 应返回 None,并且不出现在 spring.index 的 endpoints 中。

Actual behavior / 实际行为

mapping() 使用子字符串包含判断,@GetMappingCustom("/x") 被当成真实 @GetMapping,生成一个不存在的 GET /x 端点。

同一路径中的类级判断也使用 annotation.contains("@RequestMapping"),自定义前缀注解可能错误更新 Controller 的 base_routes

Root cause / 根因

Endpoint Mapping 没有使用 #306 中的准确注解边界能力:

  1. HTTP 方法注解通过字符串数组加 contains 判断。
  2. @RequestMappingmapping() 和类级 base route 判断中分别使用 contains
  3. 检测、HTTP 方法映射和路由参数提取没有由同一个封闭定义驱动,后续新增或修改注解时容易再次分叉。

Recommended fix / 推荐修补方案

推荐新增一个文件内私有的封闭 Mapping 注解类型,沿用 #306 的单一声明思路,例如由一份声明生成:

  • 注解名称
  • 准确边界模式 @Name 后只能接空白、左括号或上下文结尾
  • 对应 HTTP 方法;RequestMapping 使用其参数中的 RequestMethod.*
  • 测试所需的完整列表

mapping() 应先找到准确匹配的 Mapping 注解,再解析该注解自己的参数,不能继续使用 contains。类级 base route 判断也应复用同一匹配结果,而不是单独搜索 @RequestMapping

实现约束:

  1. 固定模式继续使用 LazyLock<Regex>,不能恢复逐行 Regex::new
  2. 若一个上下文存在多个 Mapping 注解,应按源码位置选择并记录明确策略,避免依赖枚举或 alternation 声明顺序。
  3. annotation_routes 只能接收已隔离的真实 Mapping 注解文本,不能从相邻自定义注解中提取路径。
  4. 保留 @RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }) 的数组和排序、去重行为。

Required tests / 必需测试

边界反例:

  • @GetMappingCustom("/x") 返回 None
  • @PostMappingCustom@PutMappingCustom@DeleteMappingCustom@PatchMappingCustom 返回 None
  • @RequestMappingFoo("/base") 不产生类级 base route,也不产生方法端点。

正常行为:

  • 五种标准方法 Mapping 仍返回正确 HTTP 方法和路径。
  • @RequestMapping 未指定 method 时仍返回 ANY
  • @RequestMapping 的单个和数组 RequestMethod 继续正确排序、去重。
  • value =path =、字符串数组和直接字符串参数的现有路由解析继续通过。
  • 完整 spring.index fixture 中,自定义前缀注解不出现在 endpoints。

Acceptance criteria / 验收标准

  • 所有标准 Mapping 注解保持现有正确行为。
  • 名称更长的自定义注解不再生成端点或 base route。
  • cargo test -p lithe-core 通过。
  • ./scripts/verify-rust-core-comments.sh 通过。
  • 热路径没有新增运行期正则编译。
  • 使用包含标准注解和前缀诱饵的固定语料比较输出,除错误端点被移除外没有无关变化。

Related / 关联

Checklist / 提交前检查

  • I searched existing issues for duplicates. / 我已搜索现有 Issue,确认没有重复报告。
  • I removed secrets and personal data from the report. / 我已从报告中移除敏感信息和个人数据。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions