Skip to content

feat: 解析 Eclipse 服务器运行时和 JUnit 容器,老 Web 项目能跳进 Servlet/JSP/JUnit(0.0.2) - #8

Merged
1lck merged 1 commit into
mainfrom
feat/eclipse-classpath-containers
Nov 13, 2026
Merged

1lck merged 1 commit into
mainfrom
feat/eclipse-classpath-containers

Conversation

@1lck

@1lck 1lck commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

为什么

补测老式 JSP/Eclipse 项目时发现:Eclipse 动态 Web 项目 javaee-blog(Servlet + JSP,没有 pom)1500 个随机位置只有 91.7% 能跳,124 个没跳到的绝大多数是 HttpServletRequest、getParameter、@WebServlet 这类 Servlet API,以及 JUnit 的 @Test。原因是这类项目的 .classpath 用容器(kind="con")声明这些库:

<classpathentry kind="con" path="org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/Apache Tomcat v7.0"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>

Eclipse 在开发者机器上把容器解析成服务器和 JUnit 的 jar,所以 jar 不在仓库里,插件此前直接忽略了这些条目。

改动

解析 Eclipse 容器(新文件 internal/deps/containers.go)

  • 服务器运行时容器 org.eclipse.jst.server.core.container/...:按运行时名字里的大版本判断包名,Tomcat 10+、Jetty 11+、WildFly 27+、GlassFish/Payara 6+、TomEE 9+ 用 jakarta.servlet,更早的用 javax.servlet。MyEclipse 的 J2EE 1.4 / Java EE 5–7 容器按 javax.servlet。org.eclipse.jst.j2ee.*(Web App Libraries、EAR 模块)不处理,WEB-INF/lib 本来就会读。
  • 先找本机装的服务器:CATALINA_HOME/CATALINA_BASE、Homebrew、/opt、/usr/share、Windows Program Files、~/apache-tomcat-* 下的 lib,servlet-api.jar 里包名对得上(确认有 <ns>/http/HttpServlet.class)才用,加上同目录的 jsp-api.jar、el-api.jar。
  • 没有装服务器时从本地 Maven 仓库取最新的、确实含该包名的 Servlet API 和 JSP API。javax 依次找 javax.servlet-api、servlet-api,最后才找 jakarta.servlet-api(它的 4.x 仍然是 javax 包,所以按 jar 内容判断,不按 artifact 名猜)。
  • JUnit 容器 JUNIT_CONTAINER/3|4|5:取本地仓库里对应大版本最新的 junit(4 再加 hamcrest-core)或 junit-jupiter-api,不写版本时按 4。
  • 项目自己已经带了 Servlet 或 JUnit 的 jar(比如提交在 WEB-INF/lib)时不再补,避免同一个类出现两份。
  • 没有构建文件的 Web 项目:仓库里有 WEB-INF/web.xml、但没有 pom.xml 和 Gradle 构建文件时(MyEclipse、NetBeans、直接部署到 Tomcat 的项目),同样补 Servlet/JSP API;web.xml 用 Jakarta EE 命名空间时取 jakarta.servlet。Maven 和 Gradle 项目的 Servlet 依赖由构建文件声明,不补。
  • 不联网下载,本机都没有就跳过;这些 jar 只读。容器补出的 jar 用 Maven 坐标作为 Coord,所以副本按坐标放进 ${stateDir}/dependency-sources。

internal/deps/tree.go

  • .classpath 里的 kind="con" 条目交给 container 记下,等树里的 jar 都列完后由 resolveContainers 补,所以只有项目自己没带时才补。
  • add 拆出 addAs(jar, sources, coord) bool,容器的 jar 用 Maven 坐标,并能知道是否真的加进去了(用于“取最新且能用的版本”的回退)。

文档和发布

  • README:功能表加“Eclipse 容器”一行,“怎么工作”说明解析顺序,实测表加 javaee-blog 和 OpenCms,限制里写明 .jsp 文件里还不能跳转。
  • plugin.json 版本 0.0.2,docs/releases/v0.0.2.md,release.yml 把 v0.0.2 列为预发布。
  • 顺带修正 release.yml 预发布说明里过时的“暂不收录 Store”:0.0.1 已经按约定手工收录进 Lithe Store,改成说明条目手工提交、合并后可在插件市场安装。

测试

  • 新增 internal/deps/containers_test.go:
    • TestEclipseContainersResolveToLocalJars:Tomcat 7 → javax.servlet-api 4.0.1 + jsp-api 2.1 + junit 4.13.2 + hamcrest 1.3;Tomcat 10.1 → jakarta.servlet-api 6.0.0 + jakarta jsp-api 3.1.0(不会选到 javax 包的 jakarta.servlet-api 4.0.4)。
    • TestContainersDoNotDuplicateTheTreesJars:WEB-INF/lib 里已有 servlet-api 和 junit 时不补。
    • TestAnInstalledServerProvidesTheAPIs:装了包名对得上的 Tomcat 时用它的 lib,包名不对时跳过。
    • TestAWebAppWithoutABuildFileGetsTheServletAPI:只有 web.xml 的项目按命名空间取 javax/jakarta,Maven Web 项目不补。
    • TestServerRuntimeContainers:各服务器、版本和 MyEclipse 容器的判断。
  • go vet ./...、go test ./...、go test -race ./internal/deps ./internal/lsp 通过;node scripts/package.mjs --expect-tag v0.0.2 本地打包四个平台通过。

实测(Apple M4,cmd/nav-bench,种子 2,1500 个位置,main 4bc54ea 对比本分支)

项目 改动前 改动后 跳转 p50 / p99 第一次跳转 内存(物理占用)
javaee-blog(Eclipse 动态 Web,Tomcat 7 容器,没有 pom) 91.7% 100% 0.08 ms / 0.94 ms 34 ms 17 MiB
OpenCms(Gradle,JSP CMS) 94.1% 94.1% 0.20 ms / 2.0 ms 0.13 s 54 MiB

javaee-blog 新命中的目标逐个看过:Servlet 的类型和方法都落在 javax.servlet-api 4.0.1 源码对应的声明行,@Test 落在 JUnit 4.13.2 的 org/junit/Test.java。OpenCms 的未命中是没在本地构建过的 Gradle 依赖、全限定名里的包名段和 .length,与容器无关。

没做的

.jsp 文件本身还不能跳转(插件只声明 java),JSP 脚本、EL 和标签库的跳转是单独的大功能,README 限制里已写明。

🤖 Generated with Claude Code

An Eclipse .classpath names the Servlet/JSP APIs and JUnit by container
(kind="con"), so old dynamic web projects could not navigate into
HttpServletRequest, @WebServlet or @test. Resolve the server runtime
container to an installed server's lib jars, else the newest matching
javax/jakarta API in the local Maven repository, and JUNIT_CONTAINER/3,4,5
to the matching JUnit. A WEB-INF/web.xml project without a build file gets
the Servlet API too. Nothing is downloaded.

javaee-blog (Eclipse dynamic web, Tomcat 7 container, no pom): 91.7% -> 100%.

Release 0.0.2 as a pre-release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@1lck
1lck merged commit 364f2c5 into main Nov 13, 2026
3 checks passed
@1lck
1lck deleted the feat/eclipse-classpath-containers branch November 13, 2026 06:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant