dejared-mcp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +11 -0
- package/.mcp.json +9 -0
- package/LICENSE +21 -0
- package/README.md +102 -0
- package/bin/dejared-mcp.js +5 -0
- package/lib/jar-runner.js +113 -0
- package/package.json +35 -0
- package/skills/jar-analysis/SKILL.md +139 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dejared",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Explore, analyze, and decompile Java JAR files with structured workflows.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "HuynhKhanh1402"
|
|
7
|
+
},
|
|
8
|
+
"repository": "https://github.com/HuynhKhanh1402/dejared-mcp",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"keywords": ["java", "jar", "decompiler", "bytecode", "reverse-engineering", "mcp"]
|
|
11
|
+
}
|
package/.mcp.json
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Huynh Quoc Khanh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# dejared-mcp
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server that lets AI assistants explore, analyze, and decompile Java JAR files.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
Add to your MCP client configuration:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"dejared": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["-y", "dejared-mcp"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
That's it. The wrapper automatically downloads the server JAR on first run.
|
|
21
|
+
|
|
22
|
+
### Custom Java Path
|
|
23
|
+
|
|
24
|
+
If Java is not in your system PATH, set the `DEJARED_JAVA_PATH` environment variable:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"dejared": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["-y", "dejared-mcp"],
|
|
32
|
+
"env": {
|
|
33
|
+
"DEJARED_JAVA_PATH": "/path/to/java"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Requirements
|
|
41
|
+
|
|
42
|
+
- Node.js 18+
|
|
43
|
+
- Java 21+ (JRE is sufficient)
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
**Discovery** - Browse JAR structure:
|
|
48
|
+
- `dejared_list_packages` - List all packages with class counts
|
|
49
|
+
- `dejared_list_classes` - List classes in a specific package
|
|
50
|
+
- `dejared_list_resources` - List non-class resource files
|
|
51
|
+
- `dejared_read_resource` - Read text resources (yml, xml, properties, json, etc.)
|
|
52
|
+
|
|
53
|
+
**Hunting** - Search inside JARs:
|
|
54
|
+
- `dejared_search_class` - Search classes by name
|
|
55
|
+
- `dejared_search_string` - Search string literals in bytecode (URLs, SQL, error messages, etc.)
|
|
56
|
+
|
|
57
|
+
**Deep Analysis** - Inspect and decompile:
|
|
58
|
+
- `dejared_get_metadata` - Extract class metadata via ASM (fast, no decompilation)
|
|
59
|
+
- `dejared_dump_package_metadata` - Batch metadata for entire packages
|
|
60
|
+
- `dejared_decompile_class` - Decompile `.class` to Java source code
|
|
61
|
+
|
|
62
|
+
## Decompiler Engines
|
|
63
|
+
|
|
64
|
+
| Engine | Description |
|
|
65
|
+
|--------|-------------|
|
|
66
|
+
| **CFR** (default) | Reliable general-purpose decompiler |
|
|
67
|
+
| **Vineflower** | Modern fork of FernFlower, good with newer Java features |
|
|
68
|
+
| **Procyon** | Alternative engine, can handle some edge cases better |
|
|
69
|
+
|
|
70
|
+
## How It Works
|
|
71
|
+
|
|
72
|
+
The npm package is a thin Node.js wrapper. On first run it:
|
|
73
|
+
1. Checks `~/.dejared-mcp/` for a cached JAR matching the current version
|
|
74
|
+
2. Downloads the JAR from GitHub Releases if not cached
|
|
75
|
+
3. Spawns `java -jar` with stdio inherited for MCP transport
|
|
76
|
+
|
|
77
|
+
The server communicates over stdio.
|
|
78
|
+
|
|
79
|
+
## Configuration
|
|
80
|
+
|
|
81
|
+
| Property | Default | Description |
|
|
82
|
+
|----------|---------|-------------|
|
|
83
|
+
| `dejared.cache.max-size` | `500` | Max entries in the decompilation LRU cache |
|
|
84
|
+
| `dejared.security.max-resource-size` | `5242880` | Max resource file size (bytes) |
|
|
85
|
+
| `dejared.security.decompile-timeout-seconds` | `30` | Timeout per decompilation |
|
|
86
|
+
|
|
87
|
+
## Third-Party Licenses
|
|
88
|
+
|
|
89
|
+
This project uses the following open-source libraries:
|
|
90
|
+
|
|
91
|
+
| Library | License |
|
|
92
|
+
|---------|---------|
|
|
93
|
+
| [Spring Boot](https://spring.io/projects/spring-boot) | Apache 2.0 |
|
|
94
|
+
| [Spring AI](https://spring.io/projects/spring-ai) | Apache 2.0 |
|
|
95
|
+
| [ASM](https://asm.ow2.io/) | BSD 3-Clause |
|
|
96
|
+
| [CFR](https://github.com/leibnitz27/cfr) | MIT |
|
|
97
|
+
| [Vineflower](https://github.com/Vineflower/vineflower) | Apache 2.0 |
|
|
98
|
+
| [Procyon](https://github.com/mstrobel/procyon) | Apache 2.0 |
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { spawn, execFileSync } = require("node:child_process");
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const https = require("node:https");
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
const os = require("node:os");
|
|
8
|
+
|
|
9
|
+
const PACKAGE = require(path.join(__dirname, "..", "package.json"));
|
|
10
|
+
const JAR_VERSION = PACKAGE.jarVersion;
|
|
11
|
+
const JAR_NAME = `dejared-mcp-${JAR_VERSION}.jar`;
|
|
12
|
+
const CACHE_DIR = path.join(os.homedir(), ".dejared-mcp");
|
|
13
|
+
const JAR_PATH = path.join(CACHE_DIR, JAR_NAME);
|
|
14
|
+
const DOWNLOAD_URL = `https://github.com/HuynhKhanh1402/dejared-mcp/releases/download/v${JAR_VERSION}/${JAR_NAME}`;
|
|
15
|
+
|
|
16
|
+
function log(msg) {
|
|
17
|
+
process.stderr.write(`[dejared-mcp] ${msg}\n`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function resolveJava() {
|
|
21
|
+
const envJava = process.env.DEJARED_JAVA_PATH;
|
|
22
|
+
if (envJava) {
|
|
23
|
+
if (!fs.existsSync(envJava)) {
|
|
24
|
+
log(`DEJARED_JAVA_PATH points to "${envJava}" but it does not exist.`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
return envJava;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
execFileSync("java", ["-version"], { stdio: "ignore" });
|
|
31
|
+
return "java";
|
|
32
|
+
} catch {
|
|
33
|
+
log("Java not found. Set DEJARED_JAVA_PATH or install Java 21+.");
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function download(url, dest, redirects = 5) {
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
if (redirects <= 0) return reject(new Error("Too many redirects"));
|
|
41
|
+
|
|
42
|
+
https.get(url, (res) => {
|
|
43
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
44
|
+
res.resume();
|
|
45
|
+
return resolve(download(res.headers.location, dest, redirects - 1));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (res.statusCode !== 200) {
|
|
49
|
+
res.resume();
|
|
50
|
+
return reject(new Error(`HTTP ${res.statusCode} from ${url}`));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const tmp = dest + ".tmp";
|
|
54
|
+
const file = fs.createWriteStream(tmp);
|
|
55
|
+
res.pipe(file);
|
|
56
|
+
file.on("finish", () => {
|
|
57
|
+
file.close(() => {
|
|
58
|
+
const stat = fs.statSync(tmp);
|
|
59
|
+
if (stat.size === 0) {
|
|
60
|
+
fs.unlinkSync(tmp);
|
|
61
|
+
return reject(new Error("Downloaded file is empty"));
|
|
62
|
+
}
|
|
63
|
+
fs.renameSync(tmp, dest);
|
|
64
|
+
resolve();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
file.on("error", (err) => {
|
|
68
|
+
fs.unlink(tmp, () => {});
|
|
69
|
+
reject(err);
|
|
70
|
+
});
|
|
71
|
+
}).on("error", reject);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function ensureJar() {
|
|
76
|
+
if (fs.existsSync(JAR_PATH)) {
|
|
77
|
+
const stat = fs.statSync(JAR_PATH);
|
|
78
|
+
if (stat.size > 0) return;
|
|
79
|
+
log("Cached JAR is corrupted (0 bytes). Re-downloading...");
|
|
80
|
+
fs.unlinkSync(JAR_PATH);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
84
|
+
log(`Downloading dejared-mcp v${JAR_VERSION}...`);
|
|
85
|
+
try {
|
|
86
|
+
await download(DOWNLOAD_URL, JAR_PATH);
|
|
87
|
+
log("Download complete.");
|
|
88
|
+
} catch (err) {
|
|
89
|
+
log(`Failed to download JAR: ${err.message}`);
|
|
90
|
+
log(`URL: ${DOWNLOAD_URL}`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function run() {
|
|
96
|
+
const javaPath = resolveJava();
|
|
97
|
+
await ensureJar();
|
|
98
|
+
|
|
99
|
+
const child = spawn(javaPath, ["-jar", JAR_PATH], {
|
|
100
|
+
stdio: "inherit",
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
child.on("error", (err) => {
|
|
104
|
+
log(`Failed to start Java: ${err.message}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
child.on("exit", (code) => {
|
|
109
|
+
process.exit(code ?? 1);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = { run };
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dejared-mcp",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Explore, analyze, and decompile Java JAR files via MCP",
|
|
5
|
+
"bin": {
|
|
6
|
+
"dejared-mcp": "bin/dejared-mcp.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"lib/",
|
|
11
|
+
"skills/",
|
|
12
|
+
".claude-plugin/",
|
|
13
|
+
".mcp.json",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"jarVersion": "0.0.1",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "HuynhKhanh1402",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/HuynhKhanh1402/dejared-mcp"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"mcp",
|
|
26
|
+
"java",
|
|
27
|
+
"jar",
|
|
28
|
+
"decompiler",
|
|
29
|
+
"bytecode",
|
|
30
|
+
"reverse-engineering"
|
|
31
|
+
],
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jar-analysis
|
|
3
|
+
description: >
|
|
4
|
+
Explore, search, and decompile Java JAR files. Three workflows: Explore
|
|
5
|
+
(top-down structure mapping), Hunt (search for specific code/strings),
|
|
6
|
+
and Deep Analysis (single-class investigation). Use the workflow that
|
|
7
|
+
matches the task.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# JAR Analysis
|
|
11
|
+
|
|
12
|
+
Three workflows for working with Java JAR files. Pick the one that fits your goal.
|
|
13
|
+
|
|
14
|
+
## Available Tools
|
|
15
|
+
|
|
16
|
+
| Tool | Cost | Purpose |
|
|
17
|
+
|------|------|---------|
|
|
18
|
+
| `dejared_list_packages` | Cheap | List all packages with class counts |
|
|
19
|
+
| `dejared_list_classes` | Cheap | List classes in a package (`recursive=true` for sub-packages) |
|
|
20
|
+
| `dejared_list_resources` | Cheap | List all non-class resource files with sizes |
|
|
21
|
+
| `dejared_read_resource` | Cheap | Read a resource file (yml, properties, xml, json, txt, sql, conf) |
|
|
22
|
+
| `dejared_dump_package_metadata` | Cheap | Batch metadata for multiple packages at once (annotations, fields, methods via ASM) |
|
|
23
|
+
| `dejared_get_metadata` | Cheap | Single class metadata (ASM-based, no decompilation) |
|
|
24
|
+
| `dejared_search_class` | Cheap | Find classes by name keyword (case-insensitive) |
|
|
25
|
+
| `dejared_search_string` | Cheap | Find string literals in bytecode constant pools (case-insensitive) |
|
|
26
|
+
| `dejared_decompile_class` | **Expensive** | Full source code decompilation (CFR/vineflower/procyon) |
|
|
27
|
+
|
|
28
|
+
## Shared Rules
|
|
29
|
+
|
|
30
|
+
- All tool calls require the **absolute path** to the JAR file.
|
|
31
|
+
- NEVER decompile a class without checking its metadata first.
|
|
32
|
+
- Default decompiler: CFR. If output is broken, try `vineflower` or `procyon`.
|
|
33
|
+
- Report results in structured format.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Workflow 1: Explore
|
|
38
|
+
|
|
39
|
+
Use when exploring unknown JARs or understanding JAR architecture. Top-down approach: cheap tools first, decompilation last.
|
|
40
|
+
|
|
41
|
+
### Step 1: Map Package Structure
|
|
42
|
+
Call `dejared_list_packages` to get the full layout.
|
|
43
|
+
- Identify the root application package (highest class count, deepest nesting).
|
|
44
|
+
- Distinguish app code from shaded/third-party dependencies.
|
|
45
|
+
|
|
46
|
+
### Step 2: List Classes
|
|
47
|
+
Call `dejared_list_classes` with `recursive=true` on the root application package to get all classes in one call.
|
|
48
|
+
- For targeted exploration of specific packages, use `recursive=false`.
|
|
49
|
+
|
|
50
|
+
### Step 3: Discover Resources
|
|
51
|
+
Call `dejared_list_resources` to see what non-class files exist in the JAR.
|
|
52
|
+
|
|
53
|
+
### Step 4: Read Configuration
|
|
54
|
+
Call `dejared_read_resource` for files discovered in Step 3:
|
|
55
|
+
- `application.yml` / `application.yaml` / `application.properties`
|
|
56
|
+
- `META-INF/spring.factories` or `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`
|
|
57
|
+
- `logback.xml` / `log4j2.xml`
|
|
58
|
+
|
|
59
|
+
### Step 5: Batch Metadata
|
|
60
|
+
Call `dejared_dump_package_metadata` with **all important packages at once** (it accepts a list).
|
|
61
|
+
Example: `packageNames: ["com.example.service", "com.example.config", "com.example.controller"]`
|
|
62
|
+
- Returns annotations, fields, and method signatures for every class.
|
|
63
|
+
- One call replaces dozens of individual `dejared_get_metadata` calls.
|
|
64
|
+
|
|
65
|
+
### Step 6: Selective Decompilation
|
|
66
|
+
Call `dejared_decompile_class` ONLY for classes where you need method body logic.
|
|
67
|
+
- You MUST have reviewed metadata from Step 5 first.
|
|
68
|
+
- Decompile one class at a time; summarize before continuing.
|
|
69
|
+
- For JARs with >20 packages, group by prefix and summarize before diving in.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Workflow 2: Hunt
|
|
74
|
+
|
|
75
|
+
Use when looking for specific functionality, URLs, SQL, error messages, or credentials. Search-driven approach.
|
|
76
|
+
|
|
77
|
+
### Search Tools
|
|
78
|
+
|
|
79
|
+
**`dejared_search_class`** -- Find by class name.
|
|
80
|
+
Case-insensitive keyword match against simple class names.
|
|
81
|
+
- Find specific classes: "UserService", "DatabaseConfig"
|
|
82
|
+
- Find patterns: "Controller", "Repository", "Factory", "Handler"
|
|
83
|
+
|
|
84
|
+
**`dejared_search_string`** -- Find by string literal.
|
|
85
|
+
Scans bytecode constant pools across all classes (case-insensitive).
|
|
86
|
+
- URLs, endpoints, API paths
|
|
87
|
+
- SQL queries, table names
|
|
88
|
+
- Error messages, log messages
|
|
89
|
+
- Config keys, credentials, secrets
|
|
90
|
+
- Useful keywords for security audits: "password", "secret", "token", "key", "jdbc", "http://"
|
|
91
|
+
|
|
92
|
+
### Steps
|
|
93
|
+
|
|
94
|
+
1. **Search** -- Pick the right search tool based on the goal.
|
|
95
|
+
2. **Triage** -- Review results, identify most relevant matches.
|
|
96
|
+
3. **Inspect** -- Call `dejared_get_metadata` on promising classes to understand their role (annotations, fields, methods).
|
|
97
|
+
4. **Decompile** -- Call `dejared_decompile_class` ONLY on classes where you need to see method body logic. Never skip step 3.
|
|
98
|
+
5. **Report** -- Summarize findings with context and implications.
|
|
99
|
+
|
|
100
|
+
Note: String search finds compiled constants only, not runtime-generated strings.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Workflow 3: Deep Analysis
|
|
105
|
+
|
|
106
|
+
Use when investigating a single class in detail. Combines metadata extraction with multi-engine decompilation.
|
|
107
|
+
|
|
108
|
+
### Step 1: Metadata First
|
|
109
|
+
Call `dejared_get_metadata` to extract:
|
|
110
|
+
- Class hierarchy (superclass, interfaces)
|
|
111
|
+
- Annotations (`@Service`, `@Entity`, `@Controller`, etc.)
|
|
112
|
+
- Fields (state the class holds)
|
|
113
|
+
- Methods (behavior -- names, return types, parameters)
|
|
114
|
+
|
|
115
|
+
This tells you the class's role and size before decompiling.
|
|
116
|
+
|
|
117
|
+
### Step 2: Decompile
|
|
118
|
+
Call `dejared_decompile_class` (default engine: CFR). Analyze:
|
|
119
|
+
- Constructor logic and dependency injection
|
|
120
|
+
- Method implementations and business logic
|
|
121
|
+
- Error handling patterns
|
|
122
|
+
- Interactions with other classes
|
|
123
|
+
|
|
124
|
+
### Step 3: Cross-Reference (if needed)
|
|
125
|
+
If decompiled code references important classes:
|
|
126
|
+
- `dejared_search_class` to find them by name.
|
|
127
|
+
- `dejared_dump_package_metadata` on the same package to see sibling classes (accepts a list of packages).
|
|
128
|
+
|
|
129
|
+
### Step 4: Try Alternative Engine (if needed)
|
|
130
|
+
If CFR output has problems (broken lambdas, goto statements, placeholder bodies):
|
|
131
|
+
- `vineflower` -- best for modern Java features.
|
|
132
|
+
- `procyon` -- good for edge cases.
|
|
133
|
+
|
|
134
|
+
### Report Structure
|
|
135
|
+
1. **Role** -- What this class does (one sentence).
|
|
136
|
+
2. **Framework Integration** -- Annotations, Spring beans, injection points.
|
|
137
|
+
3. **Key Methods** -- Important methods and what they do.
|
|
138
|
+
4. **Dependencies** -- Other classes/services it uses.
|
|
139
|
+
5. **Notable Patterns** -- Design patterns, security concerns, performance notes.
|