# 業務ロジック — Vet.getSpecialtiesInternal() [6 LOC]

| 項目 | 値 |
|-------|-------|
| 完全修飾名 | `org.springframework.samples.petclinic.vet.Vet` |
| レイヤー | Entity（JPA永続化層） |
| モジュール | `vet`（パッケージ: `org.springframework.samples.petclinic.vet`）

## 1. 役割

### Vet.getSpecialtiesInternal()

本メソッドは、獣医師（`Vet`）が保有する専門分野（`Specialty`）のコレクションを返すnull安全なアクセッサである。獣医師は動物病院で複数の専門分野（例: 外科、内科、歯科など）を持つことができ、各専門分野は`Specialty`エンティティとして`vet_specialties`結合テーブル経由で多対多関係にマッピングされる。本メソッドは「ラジイ・レイジー初期化（Lazy Initialization）」パターンを採用しており、`specialties`フィールドが`null`である場合に新しい`HashSet`を自動生成してから返す。これにより、呼び出し側はnullチェックを行わずに安全にコレクションを操作できる。`@ManyToMany(fetch = FetchType.EAGER)`により、`Vet`エンティティの読み込み時に専門分野のデータは即座にフェッチされる。本メソッドはパッケージ_protected_アクセス修飾子を持ち、同一パッケージ内のメソッド（`getSpecialties()`、`getNrOfSpecialties()`、`addSpecialty()`）から内部実装として呼ばれることを意図している。`@XmlElement`注釈付きのpublicな`getSpecialties()`メソッドから呼び出されることで、XMLシリアライズ時にも安全に動作する。

## 2. 処理パターン（詳細業務ロジック）

```mermaid
flowchart TD
    START(["getSpecialtiesInternal()"])
    COND["specialties が null か?"]
    INIT["specialties = new HashSet<Specialty>()"]
    RET["specialties を返却"]
    END_NODE(["Return"])

    START --> COND
    COND -->|"Yes"| INIT
    INIT --> RET
    COND -->|"No"| RET
    RET --> END_NODE
```

**Null安全なラジイ・レイジー初期化:**

`specialties`フィールドが`null`の場合に空の`HashSet`を生成し、初期化済みであれば既存のセットをそのまま返却する。分岐は条件分岐1件のみであり、定数による分岐は存在しない。

## 3. パラメータ分析

| No | パラメータ名 | 型 | 業務的説明 |
|----|---------------|------|---------------------|
| - | なし | - | 引数なし。獣医師エンティティの内部状態に基づくアクセッサ。 |

| # | 参照フィールド | 型 | 業務的説明 |
|---|----------------|------|---------------------|
| 1 | `specialties` | `Set<Specialty>` | 獣医師が保有する専門分野の一覧。`@ManyToMany`で`vet_specialties`結合テーブルにマッピング。`FetchType.EAGER`により読み込み時に即時フェッチされる。 |

## 4. CRUD操作／呼び出しサービス

本メソッドは外部のSC（Service Component）やデータベース直読を行わない。純粋なエンティティの内部状態へのアクセッサであり、参照するフィールドはJPAによって永続化されたデータを含む。

| CRUD | SC / CBS | SCコード | エンティティ / DB | 操作の説明 |
|------|----------|---------|-------------|---------------------|
| R | （なし） | — | `vet_specialties` | 獣医師の専門分野コレクションを返却。結合テーブルへの直接操作は行わない（JPA委譲）。 |
| U | （なし） | — | `specialties`（フィールド） | `specialties`が`null`の場合に`HashSet`を代入して初期化。 |

**補足:** 本メソッドはJPAエンティティのフィールドに直接アクセスするため、実際の永続化はJPAプロバイダ（Hibernate等）によって`@ManyToMany`マッピング規則に基づいて自動処理される。

## 5. 依存関係トレース

直接の呼び出し元は以下の3メソッドである。すべて同一`Vet`クラス内のメソッドであり、外部画面やバッチからの直接呼び出しは想定されない。

| # | 呼び出し元（画面/バッチ） | 呼び出しチェーン（本メソッドまでの全経路） | 終端（SC / CRUD / エンティティ） |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | `Vet.getSpecialties()` | `getSpecialties()` → `getSpecialtiesInternal()` | [R] `vet_specialties` |
| 2 | `Vet.getNrOfSpecialties()` | `getNrOfSpecialties()` → `getSpecialtiesInternal()` | [R] `specialties.size()` |
| 3 | `Vet.addSpecialty()` | `addSpecialty(specialty)` → `getSpecialtiesInternal()` → `.add(specialty)` | [U] `specialties`セットへの追加 |

## 6. 分岐ごとの詳細ブロック

**ブロック 1** — [IF] `(this.specialties == null)` (L53)

> `specialties`フィールドが初期化されていない場合、空の`HashSet`を生成して初期化する。

| # | 種別 | コード |
|---|------|------|
| 1 | SET | `this.specialties = new HashSet<>()` |

**ブロック 2** — [RETURN] (L55)

> 初期化済み（`null`以外）の`specialties`コレクションを返却する。`IF`ブロックの`Yes`経路および`No`経路の両方で実行される共通終端処理。

| # | 種別 | コード |
|---|------|------|
| 1 | RETURN | `return this.specialties` |

## 7. 用語集

| 用語 | 種別 | 業務的意味 |
|------|------|---------------------|
| `Vet` | Entity | 獣医師 — 動物病院で診察・治療を行う専門家のエンティティ |
| `Specialty` | Entity | 専門分野 — 獣医師が認定する専門領域（例: 外科、内科、眼科など） |
| `specialties` | Field | 獣医師の専門分野コレクション — 複数分野を保持する集合 |
| `vet_specialties` | DB Table | 獣医師と専門分野の多対多結合テーブル |
| `@ManyToMany` | JPA注釈 | 多対多リレーションシップのマッピング注釈 |
| `FetchType.EAGER` | JPAフェッチ戦略 | エンティティ読み込み時に即時、関連データをフェッチする戦略 |
| `HashSet` | Javaコレクション | 重複を許さない集合クラス — 専門分野の重複追加を防ぐ |
| `@XmlElement` | JAXB注釈 | XMLシリアライズ時にこのフィールドをXML要素として出力する注釈 |
| `getSpecialtiesInternal()` | Method | null安全な内部アクセッサ — パッケージ_protected_で外部から直接呼ばれない |
| `Person` | Entity | 氏名・住所などの個人情報を保持する親エンティティ |
| `NamedEntity` | Entity | 名前フィールドを備える基本エンティティ |
| `BaseEntity` | Entity | IDなどの基本フィールドを備える最上位エンティティ |
