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


はじめに

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

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

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

pom.xml の Before/After

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

<?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.xmlBuild Lifecycle の図です。

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

properties

<properties>
    <!-- Kotlin -->
    <kotlin.version>1.1.2-5</kotlin.version>
</properties>
  • Kotlin のVersionを指定してます

dependencies

<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 に追加します
  • printlnlistOf 等が入っています

plugins --> kotlin-maven-plugin

<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 Lifecyclecompile Phase に kotlin-maven-plugincompile Goal の Execution (=Pluginの実行) を追加します

test-compile も同上

plugins --> maven-compiler-plugin

<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 Lifecyclecompile Phase から default-compile ID の Execution を削除します
  • Build Lifecyclecompile Phase に maven-compiler-plugincompile Goal の Execution (=Pluginの実行) を追加します

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

test-compile も同上