`mvn package`で何度もビルドすると置き換わらないファイルが出たりする

Maven初心者です。


tl;dr
------------------

時間はかかるが間違いのない方法としては、`mvn clean package` とすれば大丈夫です。

また、リソースが置き換わる条件は以下の**いずれか**を満たした場合です。

- filtering対象のファイル
- 更新日時が新しくなったファイル
- overwrite プロパティが指定された場合(`-Dmaven.resources.overwrite=true`など)


### 環境

Spring Bootを使った開発をしており、プロファイルを切り替えてリリース用ファイルに差し替えてビルドしたい、という感じです。

ファイル構成はこんな感じ。

- src/main/resouces
  - application.properties: 開発用
  - logback.xml: 開発用
- profiles/staging/resources
  - application.properties: ステージング用
  - logback.xml: ステージング用

pom.xmlもこんな感じにしている。

```
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/>
    </parent>
	<!--中略-->
    <profiles>
      <profile>
          <id>staging</id>
          <build>
              <resources>
                <resource>
                  <directory>profiles/staging/resources</directory>
                </resource>
                <resource>
                  <directory>src/main/resources</directory>
                </resource>
              </resources>
          </build>
      </profile>
	</profiles>
```

### 問題の現象

2回目以降の`mvn package`で、application.propertiesは置き換わるが、**logback.xmlは置き換わらないことがある**という点。

後者については、配置先(target配下)にあるリソースファイルの更新日時を見ており、新しければ更新するようだった。

application.propertiesを特別扱いしてるのかよくわかんないし、logback.xmlが例外的なのかわからなかった。`--debug`付けてもよくわからない。


### maven resources pluginの挙動を調べる

この辺り、誰も引っかかってないのか、ググり方が悪いのか、ネットで調べてもそれっぽい事象が見当たらない。

ならソースコードを見ろということなので、プラグインの動作からファイルのコピー周りの処理まで雑に調べてみました。
ただ、実際の動作がこの通りかどうかはわからない。。。（実装クラスが異なるかもしれない）


- maven-resources-plugin: /org/apache/maven/plugins/resources/ResourcesMojo.java
  - （MavenのプラグインはAbstractMojoを継承して作られるらしい）
  - `MavenResourcesExecution`を作って`MavenResourcesFiltering#filterResources`に渡している。
    - `MavenResourcesFiltering`はインタフェースで、実装は多分`DefaultMavenResourcesFiltering`
- maven: /org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering.java
  - `DefaultMavenResourcesFiltering#filterResources(MavenResourcesExecution)`でMavenResourcesExecutionの情報を基にコピーを行う
  - コピーは`MavenFileFilter`インタフェースを通して行うが、実体はコード上書かれていない(private fieldなのに代入がない)。
    - 調べるとDIで設定するらしい。 `DefaultMavenFileFilter`という実装があるので、特に無ければこれが選ばれそう。
- maven: /org/apache/maven/shared/filtering/DefaultMavenFileFilter.java
  - copyFileの実装を追っていくと、内部で`FileUtils.copyFile`を呼ぶ。
- maven: /org/codehaus/plexus/util/FileUtils.java
  - filteringが有効になっているファイルか、そうでないかで動きが変わる（判定自体は前のDefaultMavenFileFilterで行われる）
      - 有効: overwriteの設定を無視して常に置き換え（filteringで置き換えるので最新になるはずだからoverwriteは意味がない、という考えだと思う。）
      - 無効: ファイル更新日時(lastModified)が新しくなっているか、overwrite==trueであれば更新する
  - ※filteringとは：ファイル内の`${*}`を置き換える（Spring関連ファイルなら`@*@`を置き換える）


動きは何となくわかりましたが、application.propertiesだけ該当するのはまだ解せません。
でも置き換わるということはどこかで設定されているはずです。（ビルド時にファイルが更新される、filteringが有効になっている、overwriteが有効になっている）


### 実効POMを見る

Eclipseを使っていると、親POMを含めて実際に実行されるpom.xmlの内容が確認できます。(Eclipseでは実効POMと呼んでる)

これでmaven-resource-pluginが使われているかなどを確認してみると、プロジェクトのpom.xmlでは定義していない内容を確認できました。

```
	  <resource>
        <filtering>true</filtering>
        <directory>/PATH/TO/PROJECT/src/main/resources</directory>
        <includes>
          <include>**/application*.yml</include>
          <include>**/application*.yaml</include>
          <include>**/application*.properties</include>
        </includes>
      </resource>
```

これはSpring Boot関連のpom.xmlで定義されているようです。

`**/application*.properties`については、filtering設定が有効なので、常に置き換わるだろうということがわかります。


### 他のリソースも毎回置き換えたい。

filteringを使えば置き換わるので、以下のようにすれば良さそうです。

```
      <resource>
        <filtering>true</filtering><!-- ここ追加 -->
        <directory>profiles/staging/resources</directory>
      </resource>
```

でも「filteringを適用させたくない！」という場合はこれは使えません。困った。

その場合はoverwrite設定を入れるか、一度`clean`するしかなさそうです。


### わかったこと

- 今回の現象はSpring Bootの親POMを使うように設定しており、`**/application*.properties`は全部filtering対象になるので、packageするたびに`application.propertiesが`置き換わりました。
- overwriteプロパティの設定を入れるのもありですが、全リソースに作用してしまうため、リソースファイルが多い場合は避けたほうが良いかもしれません。
- 雑な対応としては、毎回cleanすればよく、jenkins等は`mvn clean package`しておけば良さそうです

よくよく考えれば`clean`しなければ前のファイルが残るし、「プロファイルで指定したリソースで上書きしてほしい」ってのもMavenに伝えてないのだから、そのように動くでしょうなぁ、という感じ。（でも`<resource>`にoverwriteの設定を渡せるようにしてほしい...）


### 愚痴

ネットの情報は前提条件が省かれてるものも多いので、ちゃんと検証して自分で説明できるぐらいの裏を取ってから使いたいものです。