81 lines
3.1 KiB
Markdown
81 lines
3.1 KiB
Markdown
# 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. Profile-Aware Property Resolver
|
|
A component dedicated to building a multi-dimensional map of available properties.
|
|
|
|
1. **File Scanning**: Parse `application.properties`, `application.yml`, and `bootstrap.yml`.
|
|
2. **Profile Identification**:
|
|
- From filenames: `application-{profile}.properties`.
|
|
- From YAML documents: `spring.config.activate.on-profile` (Spring Boot 2.4+).
|
|
3. **The Multi-Profile Map**:
|
|
- Instead of one map, we store: `Map<ProfileName, Map<Key, Value>>`.
|
|
- The "default" profile is the base.
|
|
|
|
## 4. Smart Value Propagation
|
|
When a trigger uses a property, we want to know it's profile-dependent.
|
|
|
|
**Example Trace**:
|
|
1. `application.yml` -> `app.queue: "orders"`
|
|
2. `application-prod.yml` -> `app.queue: "orders-prod"`
|
|
3. `TriggerPoint` stores:
|
|
- `placeholder: "${app.queue}"`
|
|
- `defaultResolvedValue: "orders"`
|
|
4. **Rendering Strategy**: The renderer can show "orders" by default, but provide a "Profile Toggle" to switch to "prod" and see the labels update to "orders-prod".
|
|
|
|
## 5. Metadata Retention
|
|
We should never "squash" profiles during analysis. The `CodebaseMetadata` will carry the full profile matrix to the exporter.
|
|
|
|
## 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.
|