Skip to content

Feat/webflux entrypoints test linkage config#462

Open
jaissebastian wants to merge 6 commits into
tirth8205:mainfrom
jaissebastian:feat/webflux-entrypoints-test-linkage-config
Open

Feat/webflux entrypoints test linkage config#462
jaissebastian wants to merge 6 commits into
tirth8205:mainfrom
jaissebastian:feat/webflux-entrypoints-test-linkage-config

Conversation

@jaissebastian
Copy link
Copy Markdown
Contributor

Summary

This PR adds comprehensive Spring Boot and Spring WebFlux support to the code graph, addressing the core gap where callers_of returned 0 for field-injected Spring service calls.

Spring DI Resolution (two-pass)

  • Two-pass resolver (spring_resolver.py): Pass 1 collects all field/type declarations across Java files; Pass 2 rewrites CALLS edges using the type map — resolves @Autowired, @RequiredArgsConstructor (Lombok), and explicit constructor injection
  • @Bean parameter injection: @Bean factory method parameters now emit INJECTS edges so method-reference receivers (handler::method) resolve to their declared type
  • Confidence scoring: edges tagged EXTRACTED with confidence 0.95 (constructor), 0.70 (autowired), 0.60 (constant reference)

HTTP Endpoint Indexing

  • Annotation-based routing: @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping, @RequestMapping on @RestController methods emit Endpoint nodes (http:GET:/path) and HANDLES edges
  • WebFlux functional routing: route().GET("/path", handler::method) chains now emit the same Endpoint nodes — fixed _get_call_name to return the method name for chained Java method invocations (was returning None, silently skipping the entire call block)

Config File Indexing

  • YAML / .properties parsing: .yml, .yaml, .properties files are now parsed into ConfigProperty nodes
  • Config key normalization: kebab-case (gateway-url) and camelCase (gatewayUrl) and @Value("${payment.gatewayUrl}") all normalize to the same key so edges resolve
  • @Value and @ConfigurationProperties emit DEPENDS_ON_CONFIG edges

Graph Traversal Fixes (BFS edge bridging)

  • query_graph consumers_of: new pattern — "which classes/methods read this config property?" Works even without a ConfigProperty node (only @Value annotations parsed)
  • traverse_graph config-aware BFS: ConfigProperty nodes now have BFS neighbours; config:key edge targets resolve to actual nodes
  • traverse_graph Endpoint-aware BFS: traverse_graph("POST /bulk-calculation") now walks HANDLES edges to the handler method (depth 1) rather than returning only the Endpoint node. Same bridge pattern as config: get_edges_by_endpoint_key("http:POST:/path") maps the virtual key to real node QNs
  • get_edges_by_config_key / get_edges_by_endpoint_key: new GraphStore methods that bridge virtual edge targets to graph nodes

Java Parser Improvements

  • method_reference (handler::process) added to _CALL_TYPES — emits CALLS edges with receiver stored for DI resolution
  • object_creation_expression (new Foo()) now correctly extracts the type name from type_identifier child (was returning None)
  • Chained method invocation call name extraction — route().GET(...) now returns "GET" instead of None

Execution Flow Detection (flows.py)

  • Entry point patterns: @RestController, @KafkaListener, @WorkflowMethod, @ActivityMethod, @Scheduled
  • WebFlux RouterFunction return type detected as entry point
  • Decorators stored in node extra dict so flow detection can read them

Token Efficiency (from merged branches)

  • detail_level parameter on all major tools
  • Review bundle tool
  • Graph staleness indicators, omitted counts, symbol disambiguation
  • Java FQN resolution in query_graph

Test plan

  • Run uv run pytest tests/ --tb=short -q — 1269 tests pass (6 pre-existing test_main.py::TestApplyToolFilter failures unrelated to this PR)
  • uv tool run ruff check code_review_graph/ — clean
  • Build against a Spring Boot project and verify callers_of(ServiceA.fieldInjectedMethod) returns callers with resolution="spring_di_*"
  • traverse_graph("POST /my-endpoint", depth=3) reaches the handler method
  • query_graph("consumers_of", "some.config.key") returns the Java class that reads it
  • New fixture files: tests/fixtures/SampleJava.java, tests/fixtures/SpringDI.java, tests/fixtures/application.yml, tests/fixtures/app.properties

jaissebastian and others added 6 commits May 10, 2026 16:34
…l extraction

Fix three gaps identified in Spring Boot / WebFlux usage:

1. Decorators were extracted in parser.py but never written to the node extra
   dict, so flows.py always received None and skipped Spring mapping annotations.
   Store deco_list under the decorators key for all languages.

2. @KafkaListener and @WorkflowMethod were stored in parser extra but absent
   from _FRAMEWORK_DECORATOR_PATTERNS in flows.py. Add both plus RestController.

3. WebFlux functional routing: @bean methods returning RouterFunction<ServerResponse>
   are now detected as entry points via return_type inspection in flows.py.
   Add RouterFunction and HandlerFunction decorator patterns as a fallback.

4. tests_for in query.py performed only direct TESTED_BY lookups. Switch to
   get_transitive_tests(depth=3) which already existed in graph.py, surfacing
   tests that cover the target indirectly through call chains.

5. Add @value("${property.key}") and @ConfigurationProperties(prefix=...)
   extraction in parser.py, emitting DEPENDS_ON_CONFIG edges with
   resolution=value_annotation or resolution=configuration_properties.

Tests: 6 new assertions across test_flows.py and test_multilang.py; full suite
remains at same failure count (6 pre-existing unrelated test_main failures).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…g file indexing

Four parser gaps addressed based on Spring Boot / WebFlux usage observations:

1. Java method_reference nodes (handler::method) were absent from _CALL_TYPES
   and _get_call_name(). Add method_reference to _CALL_TYPES["java"] and handle
   it in both _get_call_name() and _extract_calls() so a CALLS edge is emitted
   with the receiver stored in extra, enabling Spring DI resolver rewriting.

2. object_creation_expression (new Foo()) was visited but _get_call_name()
   returned None because its first child is the `new` keyword, not an identifier.
   Add a Java-specific branch that reads the type_identifier child directly,
   making switch-based factory methods (return new ConcreteType()) visible.

3. HTTP path literals from @GetMapping/@PostMapping etc. are now first-class
   graph content. Add _HTTP_MAPPING_ANNOTATIONS constant, _get_http_annotation_path()
   extraction, and _emit_http_endpoint_nodes_and_edges() producing Endpoint nodes
   with HANDLES edges. Endpoints are searchable via semantic_search_nodes.

4. YAML and .properties config files are now indexed. Add .yml, .yaml, .properties
   to EXTENSION_TO_LANGUAGE and implement _parse_yaml_config() and
   _parse_properties_config() — regex-based, no extra dependency. Nested YAML
   keys are flattened to dotted paths (spring.datasource.url). These ConfigProperty
   nodes cross-link with existing DEPENDS_ON_CONFIG edges from @value annotations.

Tests: 16 new assertions across TestJavaMethodReferenceAndConstructorCalls,
TestJavaHttpEndpointExtraction, TestYamlConfigParsing, TestPropertiesConfigParsing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…fig key normalization

- @bean method parameters now emit INJECTS edges so the Spring DI resolver
  can map field receivers to their declared types for method references
- WebFlux route().GET/POST/PUT/DELETE/PATCH calls now emit Endpoint nodes
  and HANDLES edges; fix _get_call_name to return method name for chained
  Java method invocations (was returning None, skipping the call block)
- YAML and @value config keys normalized to camelCase (kebab-case and
  snake_case variants all map to the same node name so edges resolve)
- Add fixture examples and tests covering all three improvements

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add GraphStore.get_edges_by_config_key() to find DEPENDS_ON_CONFIG edges
  by the config: prefix key (bridges the gap between edge targets stored as
  'config:key' and node qualified names stored as 'file.yml::key')
- Add query_graph pattern 'consumers_of': returns all classes/methods that
  read a given config property, working even when no ConfigProperty node
  exists yet (e.g. only @value annotations parsed, no YAML file indexed)
- Fix traverse_graph BFS to resolve config edges in both directions:
  - Starting from ConfigProperty: augments in_edges with get_edges_by_config_key
  - Following out_edges: resolves 'config:key' targets to real ConfigProperty nodes
- Add 'consumers_of' to query_graph_tool docstring in main.py
- Add integration tests covering all three code paths

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
HANDLES edges store targets as 'http:METHOD:path' while Endpoint nodes
are stored with qualified names like 'file.java::Class.METHOD path'.
BFS had no way to bridge this, so traverse_graph from an Endpoint node
returned only that one node.

- Add GraphStore.get_edges_by_endpoint_key(key) to find HANDLES edges
  by their 'http:METHOD:path' target key
- Fix traverse_graph BFS in both directions:
  - Starting from an Endpoint: augments in_edges via get_edges_by_endpoint_key
    so the handler method is found at depth 1
  - Following out_edges: resolves 'http:*' targets to actual Endpoint nodes
- Add integration tests covering the new traversal behaviour

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…pattern

The variable 't' was first inferred as dict (from get_transitive_tests)
and then reused as GraphNode in the naming-convention fallback loop,
causing mypy to flag incompatible type assignments and missing attributes.
Rename the second loop variable to 'candidate' to give each binding a
distinct, unambiguous type.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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