既存の Java Maven Project に Kotlin を導入する


## はじめに

Javaで書いたMavenプロジェクトに [Kotlin] を導入するのは簡単です。 ``pom.xml`` を書き換えるだけで [Kotlin] のソースコードを追加してJavaのコードと共にビルド出来るようになります。
さすが *100% interoperable with Java™* ですね！ (\*´ｪ`\*)

* [Kotlin: Using Maven]

公式のドキュメントの通りに ``pom.xml`` を修正するとなんとなしに動くのですが、なんでこれで動くのか、そもそも [Maven] の仕組みもちゃんと理解できていなかったので調べてみました。

> [Kotlin] というより、ほぼほぼ [Maven] の解説です

## pom.xml の Before/After

単純な ``pom.xml`` を例に説明します。
``pom.xml`` を書き換える事で、もともと ``*.java`` だけで動いていた Maven Project に  [Kotlin] のコードを追加できるようになります。

```diff
<?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>megmogmog1965</groupId>
    <artifactId>JavaJarToKotlin</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
+       <!-- Kotlin -->
+       <kotlin.version>1.1.2-5</kotlin.version>
    </properties>

    <dependencies>
+       <!-- Kotlin -->
+       <dependency>
+           <groupId>org.jetbrains.kotlin</groupId>
+           <artifactId>kotlin-stdlib-jre8</artifactId>
+           <version>${kotlin.version}</version>
+       </dependency>
+       <dependency>
+           <groupId>org.jetbrains.kotlin</groupId>
+           <artifactId>kotlin-test</artifactId>
+           <version>${kotlin.version}</version>
+           <scope>test</scope>
+       </dependency>
    </dependencies>

    <build>
        <plugins>
+           <!-- Kotlin -->
+           <plugin>
+               <groupId>org.jetbrains.kotlin</groupId>
+               <artifactId>kotlin-maven-plugin</artifactId>
+               <version>${kotlin.version}</version>
+               <executions>
+                   <execution>
+                       <id>compile</id>
+                       <phase>compile</phase>
+                       <goals>
+                           <goal>compile</goal>
+                       </goals>
+                   </execution>
+                   <execution>
+                       <id>test-compile</id>
+                       <phase>test-compile</phase>
+                       <goals>
+                           <goal>test-compile</goal>
+                       </goals>
+                   </execution>
+               </executions>
+           </plugin>

            <!-- for .java -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
+               <executions>
+                   <!-- Replacing default-compile as it is treated specially by maven -->
+                   <execution>
+                       <id>default-compile</id>
+                       <phase>none</phase>
+                   </execution>
+                   <!-- Replacing default-testCompile as it is treated specially by maven -->
+                   <execution>
+                       <id>default-testCompile</id>
+                       <phase>none</phase>
+                   </execution>
+                   <execution>
+                       <id>compile</id>
+                       <phase>compile</phase>
+                       <goals>
+                           <goal>compile</goal>
+                       </goals>
+                   </execution>
+                   <execution>
+                       <id>testCompile</id>
+                       <phase>test-compile</phase>
+                       <goals>
+                           <goal>testCompile</goal>
+                       </goals>
+                   </execution>
+               </executions>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
```

## 解説

まず、Phase とか Goal とか意味がわからないので図にしてみます。以下は上記 ``pom.xml`` の [Build Lifecycle] の図です。

![kotlin-build-lifecycle.png](https://qiita-image-store.s3.amazonaws.com/0/60131/1809c0fb-bd73-1811-fea9-05ece2f07010.png "kotlin-build-lifecycle.png")

要は [Kotlin] のコードを先にビルドして、``*.java`` を後からビルドしたい。じゃないと ``*.java`` から [Kotlin] への参照が解決できない。

### properties

```xml
<properties>
    <!-- Kotlin -->
    <kotlin.version>1.1.2-5</kotlin.version>
</properties>
```

* [Kotlin] のVersionを指定してます

### dependencies

```xml
<dependencies>
    <!-- Kotlin -->
    <dependency>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-stdlib-jre8</artifactId>
        <version>${kotlin.version}</version>
    </dependency>
    <dependency>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-test</artifactId>
        <version>${kotlin.version}</version>
        <scope>test</scope>
    </dependency>
</dependencies>
```

* kotlin-stdlib を Project に追加します
* ``println`` や ``listOf`` 等が入っています

### plugins --> kotlin-maven-plugin

```xml
<plugins>
    <!-- Kotlin -->
    <plugin>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-maven-plugin</artifactId>
        <version>${kotlin.version}</version>
        <executions>
            <execution>
                <id>compile</id>
                <phase>compile</phase>
                <goals>
                    <goal>compile</goal>
                </goals>
            </execution>
            <execution>
                <id>test-compile</id>
                <phase>test-compile</phase>
                <goals>
                    <goal>test-compile</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    ...
```

* [Build Lifecycle] の ``compile`` Phase に ``kotlin-maven-plugin`` の ``compile`` Goal の Execution (=Pluginの実行) を追加します

> ``test-compile`` も同上

### plugins --> maven-compiler-plugin

```xml
<plugins>
    ...
    
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.6.1</version>
        <executions>
            <!-- Replacing default-compile as it is treated specially by maven -->
            <execution>
                <id>default-compile</id>
                <phase>none</phase>
            </execution>
            <!-- Replacing default-testCompile as it is treated specially by maven -->
            <execution>
                <id>default-testCompile</id>
                <phase>none</phase>
            </execution>
            <execution>
                <id>compile</id>
                <phase>compile</phase>
                <goals>
                    <goal>compile</goal>
                </goals>
            </execution>
            <execution>
                <id>testCompile</id>
                <phase>test-compile</phase>
                <goals>
                    <goal>testCompile</goal>
                </goals>
            </execution>
        </executions>
        ...
```

* [Build Lifecycle] の ``compile`` Phase から ``default-compile`` ID の Execution を削除します
* [Build Lifecycle] の ``compile`` Phase に ``maven-compiler-plugin`` の ``compile`` Goal の Execution (=Pluginの実行) を追加します

> つまり、kotlin-maven-plugin:compile を先に実行する為に、一旦削除して追加し直している

> ``test-compile`` も同上




[Kotlin]:https://kotlinlang.org/
[Maven]:https://maven.apache.org/

[Build Lifecycle]:https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html


[Kotlin: Using Maven]:https://kotlinlang.org/docs/reference/using-maven.html
[Maven: Introduction to the Build Lifecycle]:https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
[Maven: Guide to Configuring Default Mojo Executions]:https://maven.apache.org/guides/mini/guide-default-execution-ids.html