Mavenでマルチモジュール構成にする(Jersey RESTful)

[前回](https://qiita.com/kasa_le/items/3c7e7a426acf846ee64e)までのプロジェクトを、マルチモジュール構成にしていきます。

# 結論
先に結論から。
前回の記事では、以下のような形を想像していました。

```
jersey_sample
  |- pom.xml
  |- src/main/java/package/xxx/sampleapp
  |- serverapi
  |    |- pom.xml
  |    |- src/main/java/package/yyy/server
  |- repository
       |- pom.xml
       |- src/main/java/package/zzz/repository
```

まず、マルチモジュールのparentがソースコードを持つことはMavenでは出来ないみたいで、全部を子モジュールにしなければなりませんでした。

で、こう出来ないかと考えたのですが、

```
jersey_sample
  |- pom.xml
  |- sampleapp
  |    |- pom.xml
  |    |- src/main/webapp (※javaコードを持たない)
  |- serverapi
  |    |- pom.xml
  |    |- src/main/java/package/yyy/server (※webappフォルダを持たない)
  |- repository
       |- pom.xml
       |- src/main/java/package/zzz/repository
```

WebAppだけのモジュールを作って、serverapiモジュールを参照してAPI呼び出し出来ないかと考えたのですが、どうにもうまくいきませんでした。
Eclipseなら、クラスパスを追加する方法があるみたいなのですが、IntelliJでは方法がわからず。。。それに、IDE上で出来たとしても、配布するときにどうなるんだ？

ということで、結局こういう形になりました。

```
jersey_sample
  |- pom.xml
  |- serverapi
  |    |- pom.xml
  |    |- src/main/
  |            |- java/package/yyy/server
  |            |- webapp
  |- repository
       |- pom.xml
       |- src/main/java/package/zzz/repository
```

諦めてAPI層が`webapp`も持つ形にしました。まあ、これで実は必要十分だったことが分かったので、よしとします(汗)

しかし、この界隈はバージョンアップが早くて、普通にググっても古い情報ばかりで、なかなか欲しい情報にたどり着けませんね。検索スキルを磨かないと(汗)

# マルチモジュール構成にする

## 1. 親`pom.xml`の作成

まず、今プロジェクトルートにある`pom.xml`をそのまま親として使います。
依存関係は本来、モジュールごとに必要なものを入れるべきかと思いますが(repository層がservletとか要らないはずなので)、今は動かなくなると怖いので(笑)、いったんこのままにしておきます。

`<package>`を、`pom`に変更するだけです。

```xml:pom.xml
    <groupId>com.example</groupId>
    <artifactId>simple-webapp</artifactId>
    <packaging>pom</packaging>
    <version>1.1-SNAPSHOT</version>
    <name>simple-webapp</name>
```

バージョンも変えておきました。

## 2. サブモジュールの作成

まずは、空のサブモジュールを作ります。

- IntelliJのプロジェクトルートを右クリックして、[New]-[Module]
<img alt="new_module.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/d62cc5d7-a80a-ebe6-4451-5e72689a3cc7.png">

- **Maven**を選び、[Next]をクリック
<img width="430" alt="new_mave_module.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/c31e8818-eafc-aa9c-74cf-026d9949bdca.png">

- `serverapi`(任意名称)と入力して[OK]をクリック
<img width="683" alt="serverapi_module.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/f008fc6d-da5b-7c76-cc58-c9c72026fae0.png">

- モジュールが追加される
<img width="296" alt="module_added.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/a855cedd-e5d5-7cb8-ccda-ce2ef62a6f99.png">

上記手順を繰り返し、`repository`モジュールを追加します。
終わると、このような構成になっているはずです。(サブフォルダは閉じてあります)
<img width="297" alt="module_all_add.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/0b146e89-de0d-ee16-832b-0b1fca076ac4.png">


## 3. `repository`モジュールの作成
今は空っぽの`repository`モジュールに、以下のクラスソースファイルを移動していきます。

- Employees
- EmployeeRepository
- 各例外クラス
  - 例外ハンドラーは除く

### (1) `pom.xml`の編集

`<packaging>`を`jar`にします。

```xml:pom.xml
    <artifactId>repository</artifactId>
    <packaging>jar</packaging>
```

### (2) DnDで`Employee`クラスをリポジトリモジュールに移動する

- ファイルをリポジトリモジュールの`src/main/java`フォルダにDrag&Dropする
- 移動先を聞かれるので、[To package]を選び、任意のパッケージ名をフルパスで記述する
  - ここでは、元々の`com.example`から、`com.example.jerseysimple.repository.models`にパッケージを変更しています  
  <img width="527" alt="refactor_move.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/f39a5005-a5e5-0d67-b91a-30fe27d0bc04.png">

- パッケージを新たに作るか聞かれるので、[Yes]をクリック  
<img width="527" alt="recactor_make_dir.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/8521bb0b-bcc7-2a6d-e7f1-fcdab16ef271.png">

- コンフリクト警告が出るが、いったんそのまま[Continue]する
  - パッケージ関連は後でまとめて直します。  
<img width="527" alt="refacgtor_conflict.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/7495637d-ecdd-daec-62ce-69fe56fea3d9.png">

他のクラスについても、それぞれ、下記のパッケージに移動していきます。

- EmployeeRepositpry => com.example.jerseysimple.repository
- 例外クラス => com.example.jerseysimple.repository.exceptions

### (2)モジュールへ移動後

全て移動が完了すると、このような形になります。
また、このモジュールの一部のクラスにもテストを作っておきました。後で、親レベルで`mvn test`としたときに、サブモジュールのテストが全部走ることの確認をしたいので。
`EmployeeRepository`はあまり本質的なものじゃないので書きませんが、例外系クラスが簡単な`getMessage`のテストが出来るのでそれらを用意しました。
<img width="415" alt="moved_repository_module.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/675bfc70-5e64-b6e4-ea84-ddd658fdd15a.png">

この時点で、`EmployeeRepository.java`を開くと、コンパイルエラーが警告されています。
これを直していきましょう。

### (3)モジュールのビルドを通す

- 例外系クラスのimport文を全部消す
<img width="593" alt="delete_imports.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/932b92d9-2441-0bb2-5791-f8f75350c5da.png">

- 赤字の`Employee`にカーソルを合わせて少し待つと、importを促すポップアップが出るので、表示されている通りのショートカットキーを押す。(Macならoption+エンター)
<img width="419" alt="import_employee.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/a5c667d6-2b81-d043-e591-22f6626ea802.png">

- その他の例外クラスについても、同様の操作を繰り返す
- メニューの[Build]から、[Build Module `repository`]を選ぶ
<img width="375" alt="build_repository_module.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/f7db0244-04e3-95f7-9a46-78ed58e104f9.png">

これで、テストも通過するはずです。
なお、ビルドとテストの確認は、ターミナルなどで`repository`モジュールに移動して、`mvn install`としても良いですね。

## 4. `serverapi`モジュールの作成

### (1)`serverapi/pom.xml`の編集

-`<packaging>`を`war`にする
-`reipository`モジュールへの依存関係を追加

```xml:serverapi/pom.xml
    <artifactId>serverapi</artifactId>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>repository</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
```

### (2)ソースファイルを移動
repositoryモジュールの時と同じ手順で、下記クラスを移動し、参照を修正します。

- EmployeeResource
  - `com.example.jerseysimple.api`パッケージに
- MyResource (これはもう削除しても良いがw)
  - `com.example.jerseysimple.api`パッケージに
- 例外ハンドラクラス
  - `com.example.jerseysimple.api.handlers`パッケージに
- テストクラス
  - `com.example.jerseysimple.api`パッケージに

### (3)webappディレクトリを移動

`serverapi`モジュールの`src/main`下に移動します。

### (4)モジュールへ移動後

全て移動が完了すると、このような形になります。
<img width="368" alt="refactor_api_module.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/0676d76b-2242-287a-2e89-81709934a186.png">

モジュールをビルドし、テストを実行してください。
※mvnコマンドの方は現時点で依存関係が解決できず動かないみたいです。IntelliJから行ってください。たぶん、親モジュールの`pom`がまだ一度も作られてないからでしょうね。

## 5. ルートのクリーンアップ

### (1)フォルダの削除
ルートにある諸々のフォルダを削除します。

- `src`
- `resources`

### (2)クリーン

プロジェクトのルートで、`mvn clean`を実行します。

## 6. 実行

### (1)デプロイ対象の変更

Tomcatから起動しますが、[Edit Configuration]の変更が必要です。

- [Deployment]タブを表示し、下部の[+]をクリック
<img width="327" alt="add_war.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/983c65d4-7253-ea41-3872-13a780c8287f.png">

- [Articat...]を選ぶ
<img width="163" alt="select_artifact.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/4c6d655a-61a7-b67f-59c8-a59ce639f4c3.png">

- `serverapi:war exploded`を選択して、[OK]をクリック
<img width="477" alt="add_new_war.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/138120f6-cac6-36f7-04be-10e185cb9113.png">

- `simple-webapp:war exploded`をクリックして、下部の[-]をクリック
<img width="338" alt="remove_old_war.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103886/64df2480-edde-0a6c-16a3-f25703217fc5.png">

- [OK]をクリック

### (2)実行

実行ボタンをクリックします。
ブラウザから各APIにアクセスしてみてください。curlコマンドやPostmanから実行するときは、warが変わったことでURLが変わっていますから気をつけてください。

それから、mvnコマンドでも、ルートからビルド、テストが全部実行されることを確認しましょう。

下記コマンドで、レポートを出すと、モジュールごとのレポートをまとめてくれるので、確認しやすいです。
※[こちら](https://qiita.com/unhurried/items/b10d4597d62dea1b3a94)の記事にあるプラグインを入れてあることが前提です。

```console
$ mvn clean \
    test -Dmaven.test.failure.ignore=true \
    site -DgenerateReports=false \
    -Daggregate=true \
    surefire-report:report
```

プロジェクトルートの`target/site`下にhtmlで出力されています。

# 感想
APIを作るのも楽しくなってきました。でもやっぱりGradle使いたいし、Kotlinが書きたいです(しつこい)

次は、SpringFramework(not Boot)+Jerseyという構成に挑戦してみます。
SpringFrameworkだけでもRESTfulAPIは作れるので、わざわざJerseyと連携させるのも？というところもあるのですが、やってみたいのでやります(笑)

ここまでのソースは、以下にアップしてあります。

https://github.com/le-kamba/JerseySample/tree/multi_modules

# 参考
- Spring Bootアプリケーションをmavenのmulti moduleで構成する  
https://qiita.com/rubytomato@github/items/118817023845b4284553