enrichment schema
This commit is contained in:
41
plan-extended-anaylis/PLAN.md
Normal file
41
plan-extended-anaylis/PLAN.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Execution Plan for Extended Analysis
|
||||
|
||||
## Phase 0: Surgical Refactoring (The Enrichment Hook)
|
||||
- [ ] Create `AnalysisResult` and `CodebaseMetadata` models.
|
||||
- [ ] Update `ExportService.generateOutputs` to accept `AnalysisResult`.
|
||||
- [ ] Implement `EnrichmentService` and `AnalysisEnricher` interface.
|
||||
- [ ] Wrap current parser outputs in `AnalysisResult` within `ExportService`.
|
||||
|
||||
## Phase 1: Foundation
|
||||
- [ ] Implement `JdtIntelligenceProvider` as the primary semantic analyzer.
|
||||
- [ ] Implement `RegexIntelligenceProvider` for fast, lightweight metadata extraction.
|
||||
...
|
||||
|
||||
## Phase 2: Direct Trigger Detection
|
||||
- [ ] Implement `GenericEventDetector` using `ASTVisitor` to find `sendEvent` calls.
|
||||
- [ ] Enhance `CodebaseContext` to provide mapping from `MethodDeclaration` to its callers (within the same codebase).
|
||||
|
||||
## Phase 3: Entry Point Mapping
|
||||
- [ ] Implement `SpringMvcDetector` for REST endpoints.
|
||||
- [ ] Implement `MessageListenerDetector` for Kafka/JMS.
|
||||
- [ ] Implement `ConfigurableTriggerDetector` for user-defined patterns.
|
||||
|
||||
## Phase 4: Call Graph Integration
|
||||
- [ ] Develop a simple call graph builder to link `Entry Points` to `Trigger Points` via intermediate service calls.
|
||||
- [ ] Support inheritance in call graph resolution (e.g., calling a method defined in an interface/base class).
|
||||
|
||||
## Phase 5: Correlation and Visualization
|
||||
- [ ] Update `ExportService` to include trigger information.
|
||||
- [ ] Update DOT exporter to show "external" entry points as boxes pointing to transitions.
|
||||
- [ ] Update SCXML exporter to include trigger metadata in `<transition>` tags.
|
||||
|
||||
## Phase 6: Validation
|
||||
- [ ] Create a "Complex Sample Project" with REST controllers, services, and multiple state machines.
|
||||
- [ ] Add unit tests for each detector and the aggregator.
|
||||
- [ ] Verify that inheritance in both state machine config and controllers is correctly handled.
|
||||
|
||||
## Phase 7: Advanced Value Resolution
|
||||
- [ ] Implement `PropertyResolver` to scan `application.properties/yml`.
|
||||
- [ ] Add support for `@Value` tracking in fields and constructors.
|
||||
- [ ] Implement constant resolution for cross-class references in annotations.
|
||||
- [ ] Integrate value propagation into the call graph analysis (linking injected values to `sendEvent` arguments).
|
||||
56
plan-extended-anaylis/architecture.md
Normal file
56
plan-extended-anaylis/architecture.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Decoupled Analysis Architecture: The "Modular Provider" Approach
|
||||
|
||||
## Core Philosophy
|
||||
We decouple the **State Machine Definition** (what the machine IS) from the **Codebase Intelligence** (how the machine IS USED). This allows for swappable analysis tools and prevents the state machine parser from becoming a monolithic "all-knowing" beast.
|
||||
|
||||
## 1. The Intelligence Interface (The Bridge)
|
||||
We introduce an abstraction layer that provides information about the code without tying us to a specific implementation (like JDT).
|
||||
|
||||
```java
|
||||
public interface CodebaseIntelligenceProvider {
|
||||
// Event Triggers
|
||||
List<TriggerPoint> findTriggerPoints();
|
||||
|
||||
// Entry Points
|
||||
List<EntryPoint> findEntryPoints();
|
||||
|
||||
// Call Graphs
|
||||
List<CallChain> traceCallChain(MethodReference target);
|
||||
|
||||
// Resolution
|
||||
String resolveValue(ExpressionReference ref);
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Swappable Implementations
|
||||
This allows us to offer different "tiers" of analysis or even different tools:
|
||||
- **JdtProvider (Current)**: High-precision, understands hierarchy, but heavy.
|
||||
- **RegexProvider**: Lightweight, fast, good for simple projects or quick scans.
|
||||
- **ExternalLspProvider (Future)**: Could query a running Language Server (like Eclipse JDT.LS) for ultra-accurate cross-project resolution.
|
||||
|
||||
## 3. The "State Machine Model" is the Sink
|
||||
The State Machine Exporter now becomes a "Consumer" of intelligence.
|
||||
1. **SM Parser**: Extracts the core states and transitions.
|
||||
2. **Intelligence Service**: Discovers where events are triggered.
|
||||
3. **Correlation Engine**: Merges the two models based on Event IDs.
|
||||
|
||||
## 4. Benefits
|
||||
- **Testability**: We can mock the `CodebaseIntelligenceProvider` to test state machine rendering without needing a full Java project on disk.
|
||||
- **Maintainability**: Adding support for a new framework (e.g., Micronaut) only requires updating the `IntelligenceProvider`, not touching the core state machine logic.
|
||||
- **Performance**: We can run the SM Parser and the Intelligence Scanner in parallel since they are now independent.
|
||||
|
||||
## Challenges
|
||||
- **Multiple State Machines**: How to know which `StateMachine` instance is being used?
|
||||
- Initial heuristic: If there's only one, assume it's that one.
|
||||
- If multiple, check generic types `StateMachine<S, E>` or variable names.
|
||||
- **Indirect Calls**: Method `A` (Controller) calls `B` (Service), and `B` calls `sendEvent`.
|
||||
- Static analysis might need to follow call graphs.
|
||||
- Use JDT's cross-reference capabilities if possible, or build a simple call graph.
|
||||
- **Inheritance**:
|
||||
- Controllers might extend base classes with common mappings.
|
||||
- State machine configurations already handle inheritance; Trigger detection should too.
|
||||
|
||||
## Next Steps
|
||||
1. Create a PoC `TriggerDetector` for Spring MVC.
|
||||
2. Integrate `TriggerAggregator` into the main analysis pipeline.
|
||||
3. Update the `Exporter` to visualize these links.
|
||||
40
plan-extended-anaylis/decoupled_logic.md
Normal file
40
plan-extended-anaylis/decoupled_logic.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# The Analysis Contract: Decoupling Metadata from Implementation
|
||||
|
||||
## 1. Unified Model
|
||||
Instead of each parser having its own internal model, we move to a "Context-Rich Model".
|
||||
|
||||
```java
|
||||
public record CodebaseMetadata(
|
||||
List<TriggerPoint> triggers,
|
||||
List<EntryPoint> entryPoints,
|
||||
Map<String, String> properties,
|
||||
CallGraph callGraph
|
||||
) {}
|
||||
```
|
||||
|
||||
## 2. Intelligence Provider Lifecycle
|
||||
1. **Initialize**: Provide root paths and configuration.
|
||||
2. **Scan**: The provider builds its internal index (e.g., JDT AST, Regex indices).
|
||||
3. **Extract**: The provider returns a `CodebaseMetadata` object.
|
||||
4. **Dispose**: Cleanup resources.
|
||||
|
||||
## 3. Tool-Specific Strengths
|
||||
|
||||
### JDT Provider (Advanced)
|
||||
- **Strengths**: True semantic understanding, inheritance resolution, precise constant lookups.
|
||||
- **Usage**: Deep analysis where we need to know that `BaseService.notify()` is actually what is being called in `ChildService`.
|
||||
|
||||
### Regex / Tree-Sitter Provider (Light)
|
||||
- **Strengths**: Extremely fast, works even on broken code (doesn't need full classpath), very low memory overhead.
|
||||
- **Usage**: Large monorepos where full JDT analysis would take minutes.
|
||||
|
||||
## 4. Aggregation Logic
|
||||
The `IntelligenceService` can actually combine results from multiple providers!
|
||||
- Use JDT for the State Machine Config (where we need high precision).
|
||||
- Use Regex for a quick scan of 1000+ controllers to find mapping patterns.
|
||||
|
||||
## 5. Refactoring Strategy
|
||||
1. **Extract**: Move current JDT-based transition parsing into a `JdtStateMachineProvider`.
|
||||
2. **Define**: Create the `CodebaseMetadata` model.
|
||||
3. **Bridge**: Update the `ExportService` to accept both a `StateMachineModel` and a `CodebaseMetadata` object.
|
||||
4. **Implement**: Create the `CodebaseIntelligenceProvider` interface and its first implementation (wrapping the existing JDT logic).
|
||||
67
plan-extended-anaylis/enrichment_strategy.md
Normal file
67
plan-extended-anaylis/enrichment_strategy.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Low-Impact Abstraction: The Enrichment Pipeline
|
||||
|
||||
## 1. Goal
|
||||
Support enhanced codebase analysis (Endpoints, Listeners, etc.) without a massive refactor of the existing JDT state machine parsers.
|
||||
|
||||
## 2. The Core Model: `AnalysisResult`
|
||||
We wrap the existing output into a container that can hold optional metadata.
|
||||
|
||||
```java
|
||||
public class AnalysisResult {
|
||||
// Current Core Data
|
||||
private final String name;
|
||||
private final List<Transition> transitions;
|
||||
private final Set<String> startStates;
|
||||
private final Set<String> endStates;
|
||||
|
||||
// Optional Enhanced Data
|
||||
private CodebaseMetadata metadata = CodebaseMetadata.empty();
|
||||
|
||||
public AnalysisResult(String name, List<Transition> transitions, Set<String> startStates, Set<String> endStates) {
|
||||
this.name = name;
|
||||
this.transitions = transitions;
|
||||
this.startStates = startStates;
|
||||
this.endStates = endStates;
|
||||
}
|
||||
|
||||
public void setMetadata(CodebaseMetadata metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. The "Enricher" Abstraction
|
||||
Instead of modifying the parser, we "enrich" the result after it's produced.
|
||||
|
||||
```java
|
||||
public interface AnalysisEnricher {
|
||||
/**
|
||||
* Examines the core analysis result and the codebase context
|
||||
* to add extra metadata (triggers, endpoints, etc.).
|
||||
*/
|
||||
void enrich(AnalysisResult result, CodebaseContext context);
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Implementation Tiers
|
||||
|
||||
### Tier 1: Current State (No-Op)
|
||||
The `ExportService` calls `enrich()`, but since no enrichers are registered, it just returns the core data. This is zero-impact refactoring.
|
||||
|
||||
### Tier 2: Enhanced Analysis
|
||||
Once we implement `SpringMvcEnricher` or `RabbitMqEnricher`, we register them. They will:
|
||||
1. Scan the `CodebaseContext`.
|
||||
2. Find `TriggerPoints`.
|
||||
3. Link them to the `transitions` already present in the `AnalysisResult`.
|
||||
4. Update the `metadata` field.
|
||||
|
||||
## 5. Why this is "Good":
|
||||
- **Non-Breaking**: `StateMachineAggregator` remains untouched.
|
||||
- **Pluggable**: You can add/remove "Intelligence" without changing the core parser.
|
||||
- **Future-Proof**: If you switch from JDT to another tool for code analysis, you only change the `Enricher` implementation.
|
||||
|
||||
## 6. Refactoring Steps
|
||||
1. **Create `AnalysisResult`** and **`CodebaseMetadata`** classes.
|
||||
2. **Update `ExportService.generateOutputs`** to take an `AnalysisResult` object instead of 4 separate parameters.
|
||||
3. **Introduce `EnrichmentService`** that holds a list of `AnalysisEnricher`s.
|
||||
4. **Modify `ExportService`** to call `enrichmentService.enrich(result, context)` before passing the result to exporters.
|
||||
92
plan-extended-anaylis/generic_extensibility.md
Normal file
92
plan-extended-anaylis/generic_extensibility.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Generic and Extensible Endpoint Finder
|
||||
|
||||
## The Need for Genericity
|
||||
Applications use various frameworks and patterns to trigger state machine events. While Spring MVC and Kafka are common, others like Micronuat, Jakarta EE, or custom internal event buses might be used.
|
||||
|
||||
## Configuration-Driven Detection
|
||||
We can allow users to define "Entry Point" patterns via a configuration file (e.g., `analysis-config.json`).
|
||||
|
||||
```json
|
||||
{
|
||||
"entryPoints": [
|
||||
{
|
||||
"name": "SpringMVC",
|
||||
"classAnnotations": ["RestController", "Controller"],
|
||||
"methodAnnotations": ["PostMapping", "GetMapping", "PutMapping", "DeleteMapping", "RequestMapping"],
|
||||
"metadataExtractors": {
|
||||
"path": ["value", "path"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Kafka",
|
||||
"methodAnnotations": ["KafkaListener"],
|
||||
"metadataExtractors": {
|
||||
"topic": ["topics", "topicPartitions"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Abstract EntryPoint Detector
|
||||
A generic detector that uses the above configuration to identify entry points.
|
||||
|
||||
```java
|
||||
public class ConfigurableTriggerDetector implements TriggerDetector {
|
||||
private final AnalysisConfig config;
|
||||
|
||||
@Override
|
||||
public List<TriggerPoint> detect(CompilationUnit cu, CodebaseContext context) {
|
||||
// 1. Find all classes
|
||||
// 2. If class has any of config.classAnnotations
|
||||
// 3. Scan methods for any of config.methodAnnotations
|
||||
// 4. If found, look for sendEvent calls inside the method or its call tree
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Indirect Flow Detection (Call Tree Analysis)
|
||||
Oftentimes, the `sendEvent` call is not directly in the controller method but in a service called by the controller.
|
||||
|
||||
### Simple Call Tree Analysis
|
||||
1. Find all methods that call `sendEvent(E)`. Let's call them "Direct Triggers".
|
||||
2. Find all methods that call "Direct Triggers".
|
||||
3. Recursively build this "Trigger Path".
|
||||
4. If a "Trigger Path" starts at an "Entry Point" (Controller/Listener), we have a complete flow.
|
||||
|
||||
Example:
|
||||
`OrderController.submitOrder()` -> `OrderService.processOrder()` -> `StateMachine.sendEvent(SUBMIT)`
|
||||
|
||||
Analysis:
|
||||
1. `OrderService.processOrder()` is a Direct Trigger for `SUBMIT`.
|
||||
2. `OrderController.submitOrder()` calls `OrderService.processOrder()`.
|
||||
3. `OrderController.submitOrder()` is an Entry Point (annotated with `@PostMapping`).
|
||||
4. Result: `POST /order` -> `SUBMIT` transition.
|
||||
|
||||
## Handling Reactive Chains Statically
|
||||
In WebFlux/Project Reactor, the logic is decoupled into a pipeline. Static analysis must "connect the dots" across operators.
|
||||
|
||||
**Strategy**:
|
||||
1. When analyzing a method, identify if it returns a reactive type (`Mono`, `Flux`).
|
||||
2. If so, inspect all lambdas within that method.
|
||||
3. If a lambda calls `sendEvent`, treat the method as a "Trigger Point".
|
||||
4. If the method is also an "Entry Point" (via annotations or `RouterFunction`), we have a direct reactive flow.
|
||||
|
||||
## Supporting Inheritance in Listeners
|
||||
Often, base classes or interfaces define generic listeners:
|
||||
```java
|
||||
public interface BaseConsumer<T> {
|
||||
@RabbitListener(queues = "${app.queue}")
|
||||
void handle(T payload);
|
||||
}
|
||||
```
|
||||
The `CodebaseContext` must resolve the `${app.queue}` if possible (via `application.properties` scanning) or at least note that it's a parameterized listener.
|
||||
|
||||
## Advanced Call Graph: The "Data Flow"
|
||||
For a truly detailed analysis, we should track NOT just method calls, but also how the "Event" object is passed around.
|
||||
- Is the event hardcoded? `sm.sendEvent(Events.CREATE)`
|
||||
- Is it derived from a payload field? `sm.sendEvent(payload.getEvent())`
|
||||
- Is it mapped via a `switch` or `Map`?
|
||||
|
||||
**Static Mapping Inference**:
|
||||
If we see a `switch` statement on a payload field that leads to different `sendEvent` calls, we can report multiple possible flows from the same endpoint.
|
||||
102
plan-extended-anaylis/implementation_details.md
Normal file
102
plan-extended-anaylis/implementation_details.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# Implementation Details: Trigger Detection with JDT
|
||||
|
||||
## 1. Finding `sendEvent` Calls
|
||||
We can use an `ASTVisitor` to find all `MethodInvocation` nodes.
|
||||
|
||||
```java
|
||||
public class SendEventVisitor extends ASTVisitor {
|
||||
@Override
|
||||
public boolean visit(MethodInvocation node) {
|
||||
if ("sendEvent".equals(node.getName().getIdentifier())) {
|
||||
// Found a call!
|
||||
// 1. Extract event (first argument)
|
||||
// 2. Identify the enclosing method and class
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Challenges in Event Extraction
|
||||
Events can be:
|
||||
- Enum constants: `Events.SUBMIT`
|
||||
- Strings: `"SUBMIT"`
|
||||
- Variables: `sm.sendEvent(eventFromPayload)` (Hard to resolve statically)
|
||||
|
||||
We should reuse `CodebaseContext.resolveState` logic (which is basically resolving an expression to a value/fqn).
|
||||
|
||||
## 2. Identifying Enclosing Context
|
||||
Once a `sendEvent` is found, we can traverse up the AST to find the `MethodDeclaration` and `TypeDeclaration`.
|
||||
|
||||
```java
|
||||
ASTNode parent = node.getParent();
|
||||
while (parent != null && !(parent instanceof MethodDeclaration)) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
// parent is now the MethodDeclaration
|
||||
```
|
||||
|
||||
### 2. Extracting Annotations
|
||||
From `MethodDeclaration`, we can check for mappings:
|
||||
- `@PostMapping`, `@GetMapping`, etc.
|
||||
- `@KafkaListener`: Extract `topics`, `groupId`.
|
||||
- `@RabbitListener`: Extract `queues`, `bindings` (Exchange/RoutingKey).
|
||||
|
||||
From `TypeDeclaration`, we can check for:
|
||||
- `@RestController`, `@Controller`
|
||||
- `@RequestMapping` at class level (to get base path)
|
||||
|
||||
## 3. Specialized WebFlux Analysis
|
||||
|
||||
### Annotation-based WebFlux
|
||||
This is largely identical to Spring MVC. The challenge is if the `sendEvent` is wrapped in a reactive operator.
|
||||
```java
|
||||
public Mono<Void> submit(Order order) {
|
||||
return service.save(order)
|
||||
.doOnNext(o -> stateMachine.sendEvent(Events.SUBMIT))
|
||||
.then();
|
||||
}
|
||||
```
|
||||
**Static Strategy**: We need to look inside `LambdaExpression` nodes passed to reactive operators (`doOnNext`, `flatMap`, `map`, `subscribe`). The `ASTVisitor` should traverse into these lambdas.
|
||||
|
||||
### Functional WebFlux (RouterFunctions)
|
||||
Functional endpoints are often defined as Beans returning `RouterFunction`.
|
||||
```java
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> route(OrderHandler handler) {
|
||||
return RouterFunctions.route(POST("/orders"), handler::submitOrder);
|
||||
}
|
||||
```
|
||||
**Static Strategy**:
|
||||
1. Find methods returning `RouterFunction`.
|
||||
2. Analyze the `MethodInvocation` chain (`route`, `andRoute`, `nest`).
|
||||
3. Extract the URI pattern and the `HandlerFunction` reference.
|
||||
4. If the handler is a method reference (`handler::submitOrder`), link it to the corresponding `MethodDeclaration`.
|
||||
|
||||
## 4. Specialized RabbitMQ Analysis
|
||||
`@RabbitListener` can be complex:
|
||||
```java
|
||||
@RabbitListener(bindings = @QueueBinding(
|
||||
value = @Queue(value = "orderQueue", durable = "true"),
|
||||
exchange = @Exchange(value = "orderExchange"),
|
||||
key = "order.created"
|
||||
))
|
||||
public void onOrder(Order order) { ... }
|
||||
```
|
||||
**Static Strategy**:
|
||||
1. Find `@RabbitListener`.
|
||||
2. If it has `bindings`, drill down into `@QueueBinding`, `@Queue`, `@Exchange` to extract the topology.
|
||||
3. If it only has `queues`, resolve the queue name (might be a SpEL expression or property placeholder, which we can try to resolve or just keep as-is).
|
||||
|
||||
## 5. Indirect Flow Detection (The "Service Link")
|
||||
If the project has multiple state machines, we need to know which one is being targeted.
|
||||
Usually, this is done via:
|
||||
- Autowiring by type: `StateMachine<States, Events> sm;`
|
||||
- Autowiring by name: `@Qualifier("mySm") StateMachine sm;`
|
||||
|
||||
We can look at the fields of the class where `sendEvent` is called.
|
||||
|
||||
## 6. Output Enhancement
|
||||
The `Exporter` should be modified to:
|
||||
- In DOT: Add nodes for Endpoints/Listeners and link them to the Events/Transitions.
|
||||
- In SCXML: Add metadata to transitions.
|
||||
71
plan-extended-anaylis/property_resolution.md
Normal file
71
plan-extended-anaylis/property_resolution.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Spring Property and Value Resolution Strategy
|
||||
|
||||
## 1. The Challenge of "Injected" Metadata
|
||||
In Spring, metadata (like Queue names, Topic names, or even Event names) is often not hardcoded but injected using various mechanisms. To provide an accurate map, the analyzer must resolve these values.
|
||||
|
||||
## 2. Supported Injection Patterns
|
||||
|
||||
### Field Injection
|
||||
```java
|
||||
@Value("${app.order-queue}")
|
||||
private String orderQueue;
|
||||
```
|
||||
**Static Strategy**:
|
||||
1. Scan all fields for `@Value`.
|
||||
2. Map `FieldName` -> `Placeholder/Value`.
|
||||
3. If `${...}` is found, resolve it via the `PropertyResolver`.
|
||||
|
||||
### Constructor and Setter Injection
|
||||
```java
|
||||
public OrderService(@Value("${app.event.submit}") String submitEvent) {
|
||||
this.submitEvent = submitEvent;
|
||||
}
|
||||
```
|
||||
**Static Strategy**:
|
||||
1. Scan constructor/method parameters for `@Value`.
|
||||
2. Trace the assignment to a class field (`this.submitEvent = ...`).
|
||||
3. Store the mapping for that field.
|
||||
|
||||
### @ConfigurationProperties
|
||||
```java
|
||||
@ConfigurationProperties(prefix = "app.messaging")
|
||||
public class AppProps {
|
||||
private String queueName;
|
||||
}
|
||||
```
|
||||
**Static Strategy**:
|
||||
1. Identify `@ConfigurationProperties` classes.
|
||||
2. Index their fields with the prefix (e.g., `app.messaging.queueName`).
|
||||
3. When these beans are injected into a service, link the service's usage to the resolved property value.
|
||||
|
||||
## 3. Property Resolver (The "Config Scanner")
|
||||
A component dedicated to building a global map of available properties.
|
||||
|
||||
1. **File Scanning**: Parse `application.properties`, `application.yml`, and `bootstrap.yml`.
|
||||
2. **Profile Support**: Handle `application-{profile}.yml` if a profile is active.
|
||||
3. **Property Map**: Create a `Map<String, String>` of all key-value pairs.
|
||||
|
||||
## 4. Value Propagation (Data Flow)
|
||||
Once a value is resolved or its placeholder is identified, we track its usage.
|
||||
|
||||
**Example Trace**:
|
||||
1. `application.yml` -> `app.queue: "orders"`
|
||||
2. `OrderService` -> `@Value("${app.queue}") String q;` -> `this.queue = q;`
|
||||
3. `OrderService.send()` -> `sm.sendEvent(this.queue);`
|
||||
4. **Resolution**: The "Event" for this trigger is "orders".
|
||||
|
||||
## 5. SpEL (Spring Expression Language) Lite
|
||||
Full SpEL support is hard for static analysis, but we can support "Common Patterns":
|
||||
- Simple bean property access: `#{myBean.name}`
|
||||
- System properties: `#{systemProperties['user.dir']}`
|
||||
- Ternary operators: `${app.enabled ? 'active' : 'inactive'}`
|
||||
|
||||
## 6. Constant Resolution
|
||||
If an annotation uses a reference to a constant:
|
||||
```java
|
||||
@RabbitListener(queues = MyConstants.ORDER_QUEUE)
|
||||
```
|
||||
**Static Strategy**:
|
||||
1. Use JDT to resolve the `QualifiedName` (`MyConstants.ORDER_QUEUE`).
|
||||
2. Fetch the `TypeDeclaration` for `MyConstants`.
|
||||
3. Find the `VariableDeclarationFragment` for `ORDER_QUEUE` and extract its literal initializer.
|
||||
Reference in New Issue
Block a user