feat(java): detect Spring @EventListener/publishEvent() and emit HANDLES/PUBLISHES edges#591
Merged
tirth8205 merged 1 commit intoJul 17, 2026
Conversation
…ES/PUBLISHES edges Spring Application Events create implicit caller-callee relationships that are invisible to static analysis: a publisher calls publishEvent(new XxxEvent()) and Spring routes it to all methods annotated @eventlistener for that event type. This change adds two-phase resolution: Parse phase: @eventlistener method → HANDLES edge to virtual event:XxxEvent node publishEvent() call → PUBLISHES edge to virtual event:XxxEvent node Event type is inferred from: 1. @eventlistener(OrderEvent.class) annotation argument 2. @eventlistener(classes = {...}) named argument (multi-type) 3. First method parameter type (implicit / no-arg form) Post-build resolver (event_resolver.py): For each PUBLISHES edge, find all HANDLES edges with matching event_type → emit CALLS edge from publisher to listener. Tests: TestSpringEventListenerParsing (6 assertions) in test_multilang.py Fixture: tests/fixtures/SpringEvents.java
Owner
|
Thanks — Spring application events would be valuable, but the post-build resolver is not functional. The edges table requires updated_at, while the new INSERT OR IGNORE omits it; SQLite ignores every derived CALLS row even though calls_emitted increments. Current tests inspect parser edges only and never verify a stored publisher-to-listener call. Please write through the graph-store API or include every required column, then add full-build and incremental tests. Listener add/remove/type changes must rebuild or delete derived calls rather than permanently skipping event_resolved publishers. Match events with import/package-qualified identity so same-named events do not cross-link. Rebase and run approved current CI. |
tirth8205
added a commit
that referenced
this pull request
Jul 17, 2026
Ported from PR #591 with package-qualified identities, addressable event nodes, lifecycle-safe derived calls, and event-specific queries. Co-authored-by: YutenC <yuten.c.tcg@tc168.cloud>
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.
Problem
Spring Application Events create implicit caller-callee relationships invisible to static analysis: a publisher calls
publishEvent(new XxxEvent())and Spring routes it to all@EventListenermethods for that event type. CRG had no way to trace this path.Solution
Two-phase resolution following the existing Spring DI / Temporal patterns:
Parse phase (parser.py):
@EventListenermethod →HANDLESedge to virtualevent:XxxEventnodepublishEvent(new XxxEvent())call →PUBLISHESedge to virtualevent:XxxEventnodeEvent type is inferred from (in priority order):
@EventListener(OrderEvent.class)— explicit annotation arg@EventListener(classes = {A.class, B.class})— multi-type named argPost-build resolver (event_resolver.py):
PUBLISHESandHANDLESedges byevent_typeCALLSedges: publisher method → listener methodUsage after this change
Changes
code_review_graph/parser.py— 2 constants + 3 new methods + 2 hooks in_extract_functionscode_review_graph/event_resolver.py— new post-build resolvercode_review_graph/incremental.py—_run_event_resolverwired into build pipelinetests/fixtures/SpringEvents.java— fixture with publisher + 2 listener patternstests/test_multilang.py—TestSpringEventListenerParsing(6 assertions)