初心者用 Maven pom.xmlについて

# はじめに 
Jarファイルを作る際JDKを用いてjavaファイルを一つずつコンパイルしてzipにまとめてjarに変えて...etc
***なんてめんどくさいことはしませんよね?*** 

pom.xmlを書いてしまえばMavenで実行してあげるだけであっという間にjarファイルを作ってくれます 

それだけ?と思う方は一度他者と一緒にプロジェクトを進めることを考えてみてください

自分はクラスファイルをどこにおいてクラスパスをどこに通しどのライブラリをjarに含めるのか
どのリソースを一緒に含めてあげるのか...
すべて把握していて手動でできるといっても一緒にプロジェクトを進めている方が知るはずないですよね?

何はともあれpom書こう(脳死) ***Gradle書きたい方にこの記事はほとんど参考にならないんでブラウザバックしてどうぞ***


# pomの最低限の要素
```XML:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>...</groupId>
    <artifactId>...</artifactId>
    <version>...</version>
   
</project>
```
この要素さえ最低限あれば一応pomとして働きます

groupId,artifactId,version以外はほとんどおまじないに近いですが一応説明します

```xml
<?xml version="1.0" encoding="UTF-8"?>
```
xmlなら必ず書く必要があるものです
バージョンは1.0が一般的です
文字コードはファイルを保存するときに指定したもの書いてください(だいたいUTF-8)
<br>

```xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>   
</project>
```

pomのルートノードです pomのバージョンやスキーマを指定するところですがほとんど定型文
おまじないの範疇でいいと思う

```xml
    <groupId>...</groupId>
    <artifactId>...</artifactId>
    <version>...</version>
```
***グループId***はプロジェクトがどこの団体or個人に属するものなのか区別するためのものです

わかりやすい例だと
>Aさんの開発したプロジェクトがHogeという名前で
Bさんの開発したプロジェクトもHogeという名前だった場合
CさんがAさんとBさんの両方のプロジェクトに依存したHogeHogeプロジェクトなんかを作る際

AさんのHogeを使っているのかBさんのHogeを使っているのか区別できなくなります

人が区別できなくなる分にはまだましなのですがMavenが依存関係を構築する際も区別できなくなります

ここで活躍するのが***グループId***です
だいたいは企業のドメインを逆にしたものです 個人ならプロジェクトを区別するためだけのものですから好きに付ければいい

Aさんならjp.a.project
Bさんならorg.group.b.project

あくまでプロジェクトを区別するためのものですからドメインを取得したりなんてことはしなくていいです<br><br>
***アーティファクトId***はプロジェクトの名前です お好きにどうぞ  
***バージョン***は開発バージョンです beta-1.0とか 1.0-SNAPSHOTとか プロジェクトを区切る際に変更します

# pomの主な要素
主に
properties
repositories
dependencies
build
を使います ほかにもいろいろありますが頻繁に書くのはこの4つです

***properties***・・・変数的なものです projectのデフォルト値やプラグインが参照する値もここで上書きできます

作ったプロパティーは${プロパティー名}で呼び出せます リソースの中でもフィルタリングを有効にすれば使えます

```xml
  <properties>
    <java.version>1.8</java.version>
    <upload.password>1234</upload.password>
    ${upload.password}
  </properties>
```

***repositories***・・・依存する外部ライブラリを取得する際のリポジトリのURLを記述します

MavenCentralリポジトリにあるライブラリはリポジトリの記述なしで依存関係を作れます
github上に作成されたMavenリポジトリなんかを参照する際に書きます

参照するリポジトリの数だけ書きます idはMavenが区別するためのものなので好きに書いていいです

```xml
  <repositories>
        <repository>
            <id>test</id>
            <url>https://~</url>
        </repository>
        <repository>
          ...
        </repository>
  </repositories>
```

***dependencies***・・・依存するライブラリを記述します

依存するライブラリのグループId アーティファクトId バージョンを書き込みます
スコープはcompile provided runtime test system の中から選びます

compileは常にクラスパスに含みます
providedはAPIなどの提供されるライブラリの場合使用します コンパイル時のみクラスパスに含まれます
runtimeは実行時のみ必要なライブラリの場合使用します 実行時にのみクラスパスに含まれます
testはテスト時のみ必要なライブラリ(JUnitとか)の場合使用します テストのコンパイルと実行時のみクラスパスに含まれます
systemは明示的にライブラリを指定する際に使用します あまり一般的ではないので説明は割愛

```xml
  <dependencies>
      <dependency>
          <groupId>jp.a.project</groupId>
          <artifactId>TestProject</artifactId>
          <version>1.0</version>
          <scope>compile</scope>
      </dependency>
      <dependency>
       ...
      </dependency>
  </dependencies>
```

***build***・・・ビルドの手順を記述します

書く内容は使用するプラグインとそのゴールとフェーズのバインド
リソースの設定や成果物の生成場所 生成名なんかを記述します

プラグインとかバインドに関しては下で解説します

リソースはディレクトリとフィルタリングするかどうかを設定します
フィルタリングするとリソース内の${プロパティ名}が実行時の値に置き換えられます

```xml
    <build>
        <defaultGoal>clean package</defaultGoal>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
            </plugin>
            <plugin>
               ...
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
```

# ビルドライフサイクル
Mavenにはビルドライフサイクルというものがあります

ライフサイクルは

クリーンライフサイクル ・・・ビルドのお掃除
デフォルトライフサイクル ・・・ビルドの作業
サイトライフルサイクル ・・・プロジェクトのサイト作成

の３つに分類されます

# フェーズ

このライフサイクルは***フェーズ***という作業の工程を細かく分類したものを持っています

クリーンライフサイクルなら
pre-clean  : ビルドを削除する前に必要な処理
clean      : 前回作成されたビルドの削除をする処理
post-clean : プロジェクトのクリーニングを完了するために必要な処理

デフォルトライフサイクルなら
validate :プロジェクトが正しいこと、および必要なすべての情報が利用可能であることを確認する処理
initialize :プロパティの設定やディレクトリの作成など、ビルド状態を初期化する処理
generate-sources :コンパイルに含めるソースコードを生成する処理
process-sources :ソースコードに対する処理 値のフィルタリングなど
generate-resources :パッケージに含めるリソースを生成する処理
process-resources :リソースをターゲットディレクトリーにコピーする処理
compile	:プロジェクトのソースコードをコンパイルする処理
process-classes	:生成されたクラスファイに対する処理
generate-test-sources :テストソースコードを生成する処理
process-test-sources :テストソースコードに対する処理 値のフィルタリングなど
generate-test-resources	:テスト用のリソースを作成する処理
process-test-resources :リソースをテスト用ディレクトリーにコピーする処理
test-compile :テストソースコードをコンパイルする処理
process-test-classes :生成されたテストクラスファイルに対する処理
test :テストフレームワークを使用してテストを実行する処理 JUnitとか
prepare-package	:パッケージを準備するために必要な処理
package	:コンパイルされたコードをJARなどの配布可能な形式でパッケージ化する処理
pre-integration-test :統合テストを実行する前に必要な処理
integration-test :必要に応じて、パッケージを処理し、統合テストを実行できる環境に展開する処理
post-integration-test :統合テストの実行後に必要な処理
verify :検査を実行して、パッケージが有効であり、品質基準を満たしていることを確認する処理
install	:ローカルリポジトリにパッケージをインストールする処理
deploy :パッケージをリモートリポジトリにコピーする処理

サイトライフサイクルなら
pre-site :サイトの生成前に必要な処理
site :プロジェクトのサイトドキュメントを生成する処理
post-site :サイト生成を完成させ、サイト展開の準備に必要な処理
site-deploy :生成されたサイトのドキュメントを指定されたWebサーバーにデプロイする処理

# フェーズ実行

Mavenでビルドする際 mvn package などのコマンドを使用しますがそのpackageに該当するのがフェーズです
フェーズは実行されると同じビルドライフサイクル上の指定フェーズまでを上から順番に実行していきます
packageの場合 デフォルトサイクルに属するので validate~packageまでが順番に実行されます

# ゴール
***フェーズ***には***ゴール***というものがいくつか紐づけられています (デフォルトで)
この***ゴール***は実際に行う処理です

***フェーズ***が持つ***ゴール***をすべて実行して次の***フェーズ***に進みます

packagingで選んだファイルの種類によってゴールの構成は変わるようですが
何も書かなければ自動でJarを生成する構成になります

***ゴール***を自分で***フェーズ***に紐づけることで自分のしたい処理を加えることができます
このことを***バインド***するといいます

# プラグイン
ビルドの際に行う処理(ゴール)はすべてプラグインが持つ機能を利用しています
このプラグインはJavaのプロジェクトで作られています なのでグループIdやアーティファクトId　バージョンがあります

ゴールはクラスのメソッドを実行しているようなものだと思っとけばいいです

ゴールの実行時に引数のように値を渡して実行結果を変えたい場合
プラグインもしくはexecutionのconfigurationで変更することが可能です 指定しない場合プラグイン側のデフォルト値が適用されます

下の例だとmavenのcompilerプラグインとshadeプラグインを使用しています
jarの生成の場合デフォルトでcompileフェーズでcompileゴールを実行するのでcompilerプラグインは宣言するだけでいいです
shadeプラグインはデフォルトで実行されないので***バインド***する必要があります 
プラグインで検索すれば選択できるgoal名と設定できるconfigurationの詳細が書いてあるページがあるはずです

```xml
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <createDependencyReducedPom>false</createDependencyReducedPom>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
```

# おまけ
Mavenが提供している公式のプラグインはmaven-○○○-pluginで統一されている
そのほかは○○○-maven-pluginで統一されている

# 最後に
Mavenを勉強していてプラグインに関する日本語の資料が少なくて苦労したのですこしでも誰かの知識になったらうれしい

### 追記
参考文献書いてねぇ
https://maven.apache.org/guides/index.html