# 機能設計書 68-Javaソースデコンパイル

## 概要

本ドキュメントは、Clojure LSPにおけるJavaソースデコンパイル機能の設計を定義する。この機能は、JARファイル内のclassファイルをJavaソースコードにデコンパイルし、定義ジャンプ等でJavaクラスの実装を閲覧可能にする。

### 本機能の処理概要

**業務上の目的・背景**：Clojureプロジェクトでは、Javaライブラリを依存関係として使用することが一般的である。開発者がJavaクラスの定義にジャンプした際、ソースコードが利用可能でない場合は.classファイルしかない。この機能は、CFR（Class File Reader）ライブラリを使用して.classファイルをデコンパイルし、読み取り可能なJavaソースコードを提供する。

**機能の利用シーン**：
- 開発者がJavaクラスの定義にジャンプした際、自動的にデコンパイルを実行
- デコンパイル結果はキャッシュされ、同じクラスへの再アクセス時は即座に表示
- JARファイル全体をプロジェクトとしてデコンパイルするオプションあり

**主要な処理内容**：
1. JARファイル内の.classファイルURIを受け取る
2. CFRライブラリでデコンパイルを実行
3. 結果をローカルキャッシュに保存
4. デコンパイル済みJavaソースのURIを返却

**関連システム・外部連携**：CFR（Class File Reader）ライブラリ、定義ジャンプ機能（No.3）、clojure/dependencyContents カスタムリクエスト。

**権限による制御**：特に権限制御は存在しない。全ユーザーが同等にこの機能を利用できる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 該当なし | 該当なし | 該当なし | 本機能はLSPプロトコルを通じてエディタから呼び出される |

## 機能種別

デコンパイル処理 / ファイル生成処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | string | Yes | .classファイルを含むJAR URI | jar:file:// または zipfile:// 形式 |

### 入力データソース

- LSPクライアントからの clojure/dependencyContents リクエスト
- 定義ジャンプ時の内部呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| uri | string | デコンパイル済みJavaファイルのURI |
| content | string | Javaソースコード（read-content!の場合） |

### 出力先

- ローカルキャッシュディレクトリ（.lsp/.cache/java/）
- LSPクライアント（JSON-RPC レスポンス）

## 処理フロー

### 処理シーケンス

```
1. .classファイルのURIを受け取る
   └─ jar:file:///path/to/lib.jar!/com/example/Class.class
2. JARファイルの種類を判定
   └─ pom.xml の有無でJavaプロジェクトか判定
3. デコンパイル方法を選択
   └─ 単一ファイル or JAR全体プロジェクト
4. CFRでデコンパイルを実行
   └─ classファイルをJavaソースに変換
5. 結果をキャッシュに保存
   └─ ローカルまたはグローバルキャッシュ
6. デコンパイル済みURIを返却
```

### フローチャート

```mermaid
flowchart TD
    A[.class URI 受信] --> B{JAR内か?}
    B -->|No| C[そのまま返却]
    B -->|Yes| D{既にデコンパイル済み?}
    D -->|Yes| E[キャッシュから返却]
    D -->|No| F{プロジェクトとしてデコンパイル?}
    F -->|Yes| G[JAR全体をデコンパイル]
    F -->|No| H[単一ファイルをデコンパイル]
    G --> I[グローバルキャッシュに保存]
    H --> J[ローカルキャッシュに保存]
    I --> K[デコンパイル済みURI返却]
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | プロジェクトモード | decompile-jar-as-project? 設定でJAR全体をプロジェクトとしてデコンパイル | 設定が true の場合（デフォルト） |
| BR-02 | pom.xml 検出 | JAR内の META-INF/*/pom.xml からプロジェクト情報を取得 | JARファイルの解析時 |
| BR-03 | インナークラス処理 | $記号を含むURIは親クラスのURIに変換 | インナークラスへのジャンプ時 |

### 計算ロジック

**キャッシュパスの計算**:
- ローカル: `.lsp/.cache/java/classes/` + エントリパス
- グローバル: `~/.cache/clojure-lsp/java/decompiled/` + グループID/アーティファクトID/バージョン

## データベース操作仕様

### 操作別データベース影響一覧

本機能は内部DBを直接操作しない。ファイルシステムへのキャッシュ書き込みのみ。

| 操作 | 対象 | 操作種別 | 概要 |
|-----|-----|---------|------|
| キャッシュ書き込み | ファイルシステム | WRITE | デコンパイル結果を保存 |
| キャッシュ読み取り | ファイルシステム | READ | 既存のデコンパイル結果を取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 警告ログ | CFRでデコンパイルエラー | 警告ログを出力して続行 |
| - | 元URI返却 | デコンパイル不可 | 元のURIをそのまま返却 |

### リトライ仕様

リトライは実装されていない。デコンパイル失敗時は元のURIを返却。

## トランザクション仕様

ファイルシステム操作のため、アトミック性は保証されない。

## パフォーマンス要件

- 単一クラスのデコンパイル: 数秒以内
- JAR全体のデコンパイル: 初回のみ数十秒〜数分（以降はキャッシュ）

## セキュリティ考慮事項

- デコンパイル結果はローカルキャッシュに保存される
- 悪意のあるclassファイルがデコンパイル時にコード実行されるリスクは低い（CFRは静的解析）

## 備考

- CFRライブラリ: https://github.com/leibnitz27/cfr
- :java :decompile-jar-as-project? 設定でJAR全体デコンパイルを制御

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

CFRの設定とJARプロジェクト情報の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | java_interop.clj | `lib/src/clojure_lsp/feature/java_interop.clj` | jar->java-project-info（38-59行目） |

**読解のコツ**: jar->java-project-info はJARのpom.xmlを解析し、:group-id, :artifact-id, :version, :source-path を返す。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | server.clj | `cli/src/clojure_lsp/server.clj` | clojure/dependencyContents ハンドラ（205-209行目） |
| 2-2 | handlers.clj | `lib/src/clojure_lsp/handlers.clj` | dependency-contents ハンドラ（421-424行目） |

**主要処理フロー**:
1. **205-209行目（server.clj）**: カスタムリクエスト受信
2. **421-424行目（handlers.clj）**: f.java-interop/read-content! 呼び出し

#### Step 3: コア機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | java_interop.clj | `lib/src/clojure_lsp/feature/java_interop.clj` | decompile!（26-36行目） |
| 3-2 | java_interop.clj | `lib/src/clojure_lsp/feature/java_interop.clj` | decompile-file（61-71行目） |
| 3-3 | java_interop.clj | `lib/src/clojure_lsp/feature/java_interop.clj` | decompile-jar-as-java-project（73-97行目） |
| 3-4 | java_interop.clj | `lib/src/clojure_lsp/feature/java_interop.clj` | uri->translated-file!（99-117行目） |

**主要処理フロー**:
- **26-36行目**: decompile! - CFRを呼び出してデコンパイル実行
- **61-71行目**: decompile-file - 単一ファイルのデコンパイル
- **73-97行目**: decompile-jar-as-java-project - JAR全体のデコンパイル
- **99-117行目**: uri->translated-file! - メイン処理フロー
  - JARファイル内の.classファイルか判定
  - プロジェクト情報を取得
  - デコンパイル方法を選択・実行
  - インナークラスの$記号を処理

### プログラム呼び出し階層図

```
server.clj (clojure/dependencyContents リクエスト受信)
    │
    └─ handlers.clj::dependency-contents
           │
           └─ java_interop.clj::read-content!
                  │
                  └─ uri->translated-file!
                         │
                         ├─ shared/jar-file? (JAR判定)
                         │
                         ├─ shared/class-file? (.class判定)
                         │
                         ├─ jar->java-project-info
                         │      │
                         │      └─ pom.xml 解析
                         │
                         └─ decompile-jar-as-java-project
                         │  または decompile-file
                                │
                                └─ decompile! (CFR呼び出し)
                                       │
                                       └─ CfrDriver.analyse
```

### データフロー図

```
[入力]                         [処理]                              [出力]

jar:file:///lib.jar!/         uri->translated-file!
com/example/Class.class           │
        │                         ▼
        │                    jar->java-project-info
        │                    (pom.xml 解析)
        │                         │
        │                         ▼
        │                    {:group-id "com.example"
        │                     :artifact-id "lib"
        │                     :version "1.0"}
        │                         │
        │                         ▼
        │                    decompile-jar-as-java-project
        │                    または decompile-file
        │                         │
        │                         ▼
        │                    CFR デコンパイル
        │                         │
        │                         ▼
        │                    キャッシュ保存
        │                    (.lsp/.cache/java/...)
        │                         │
        └─────────────────────────▼
                             デコンパイル済みURI  ───▶  LSPクライアント
                             file:///.../.cache/.../Class.java
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| java_interop.clj | `lib/src/clojure_lsp/feature/java_interop.clj` | ソース | デコンパイルのコアロジック |
| handlers.clj | `lib/src/clojure_lsp/handlers.clj` | ソース | LSPリクエストハンドラ |
| server.clj | `cli/src/clojure_lsp/server.clj` | ソース | LSPサーバーエントリーポイント |
| config.clj | `lib/src/clojure_lsp/config.clj` | ソース | キャッシュディレクトリ設定 |
| java_interop_test.clj | `lib/test/clojure_lsp/feature/java_interop_test.clj` | テスト | ユニットテスト |
