feat(java): trace Spring/MyBatis enterprise flow end-to-end (#389)#468
Merged
Conversation
Closes three gaps that broke `trace(controller, mapper-xml)` on real Spring +
MyBatis projects:
1. **Field-injected concrete-bean trace.** Java `this.<field>.method()` is
unwrapped at extraction (was surfaced as `this.<field>.method` and dropped
through every name-matcher strategy). The receiver name is then looked up
in the enclosing class's field declarations to get the declared type and
resolve the method on it. Closes the controller→bean hop when the field
name doesn't capitalize to the type (`userbo` → `UserBO`). General Java
fix, not Spring-specific.
2. **MyBatis XML mapper as a first-class language.** New extractor parses
`<mapper namespace="..."><select|insert|update|delete|sql id="X">` and
emits method-shaped nodes qualified as `<namespace>::<id>`, plus
`<include refid="X"/>` references to `<sql>` fragments. Non-mapper XML
(pom, log4j, web.xml) → file node only. A new synthesizer
(`mybatisJavaXmlEdges`) joins Java mapper methods to XML statements by
suffix-matching qualified names. Ambiguous simple-name collisions dropped
for precision.
3. **Spring `@Value`/`@ConfigurationProperties` → application config.**
`application.{yml,yaml,properties}` + profile variants parse on the
framework path; each leaf key becomes a `constant` node qualified by its
dotted path. `@Value("${k}")` / `@Value("${k:default}")` and
`@ConfigurationProperties(prefix="X")` emit binding nodes that resolve
with Spring's relaxed binding (kebab↔camel↔snake).
Validated on macrozheng/mall-tiny: full chain
`UmsRoleController.listResource → UmsRoleService.listResource → impl →
UmsResourceMapper.getResourceListByRoleId → XML <select>` connects across 5
hops via static + synthesized edges. 11/11 @value annotations resolved
(incl. `@ConfigurationProperties(prefix="secure.ignored")`); 6/6 custom-SQL
mapper methods bridge to XML.
Tests: 4 new integration tests in frameworks-integration.test.ts. Full
suite: 1005 passed.
Docs: CHANGELOG `[Unreleased]` entry + dynamic-dispatch-coverage-playbook
narrative + matrix row.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the three threads of #389 so an agent can trace
HTTP route → @Controller → field-injected service → impl → DAO/Mapper → MyBatis XML SQLend-to-end on real Spring + MyBatis projects, with no Read/Grep fallback.this.<field>.method()is unwrapped at extraction (was emitted verbatim asthis.userbo.methodand dropped through every name-matcher strategy). The receiver name is then looked up in the enclosing class's field declarations to get the declared type and resolve the method on it — closes the controller→bean hop when the field name doesn't capitalize to the type (userbo→UserBO). General Java fix, not Spring-specific.mybatis-extractor.tsparses<mapper namespace="..."><select|insert|update|delete|sql id="X">and emits method-shaped nodes qualified<namespace>::<id>, plus<include refid="X"/>refs to<sql>fragments. Non-mapper XML (pom, log4j, web.xml) → file node only. NewmybatisJavaXmlEdgessynthesizer joins Java mapper methods to XML statements by suffix-matching qualified names; ambiguous simple-name collisions dropped for precision.@Value/@ConfigurationProperties→ application config.application.{yml,yaml,properties}+ profile variants parse on the framework path; each leaf key becomes aconstantnode qualified by its dotted path.@Value("${k}")/@Value("${k:default}")and@ConfigurationProperties(prefix="X")emit binding nodes resolved with Spring's relaxed binding (kebab↔camel↔snake).Validation
Real-world repo: macrozheng/mall-tiny (Spring MVC + MyBatis Plus).
Full chain
trace(UmsRoleController.listResource → UmsResourceMapper.getResourceListByRoleId-xml)connects across 5 hops via static + synthesized edges. 11/11@Valueannotations resolve (incl.@ConfigurationProperties(prefix="secure.ignored")); 6/6 custom-SQL mapper methods bridge to XML.Test plan
@Resource(name="userBO") UserBO) on a temp Spring project — confirmUserAction.toLogin2 → UserBO.toLogin2edge appears (was missing)__tests__/frameworks-integration.test.ts(bean injection, MyBatis bridge,@Value/relaxed binding, non-MyBatis XML noise-free)Docs
CHANGELOG.md[Unreleased]entry (Added section)docs/design/dynamic-dispatch-coverage-playbook.mdmatrix row + narrativeCloses #389.
🤖 Generated with Claude Code