最近覚えた Kotlin を使って新規で Web API サーバを作り始めた結果、単独で実行可能な jar ファイルの生成でつまづきました。
公式のチュートリアルではうまく行かなかったので、やったことを書いていきます。
shadow をうまく使えなかった話です。
IDE 上で実行可能な状態にするまでは、 「KtorでJSONを返すまで」 を参考にしました。
環境
- IntelliJ IDEA ULTIMATE 2018.1
- Java 8 (java version "1.8.0_91")
- Kotlin 1.2.40
- Ktor 0.9.0
- Gradle 4.5.1
- Groovy 2.4.12
- macOS High Sierra 10.13.3 (開発環境)
- CentOS Linux release 7.4.1708 (Core) (デプロイ先サーバ)
つまづくまで
Ktor 公式の Setting up Project in IntelliJ IDEA を見ながら開発環境を整えました。
「KtorでJSONを返すまで」 を参考に、 JSON を返却できるところまで進めました。
ローカルでの動作が確認できたので、とりあえずサーバにデプロイしたいと考えました。
デプロイするにあたり Ktor 公式のデプロイ方法 を眺めていると、スタンドアロン実行可能な jar ファイルを生成できるというものを発見しました。
すなわち、
java -jar yourapplication.jar
で Web アプリケーションが起動するとのことでした。
しかし、公式ページを参考に build.gradle
に shadow を用いてパッケージ生成をさせようと試みましたが、これがまるでうまく行きませんでした。
どう直してもMainクラスを参照できないのです。
shadow を用いて jar ファイルを生成した結果、全てのクラスファイルが shadow ディレクトリ配下に配置されていました。
これでは、 io.ktor.server.${jettyやnetty}.DevelopmentEngine
を参照できません。
解決方法
stackoverflow で見つけた方法をもとに、自分で gradle の task を定義しました。
参考にした回答は こちら です。
task fatJar(type: Jar) {
manifest {
attributes "Implementation-Title": project.name,
"Implementation-Version": version,
"Main-Class": mainClassName
}
baseName = project.name
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
exclude "META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA"
with jar
}
Ktor 公式のデプロイ方法 をもとに build.gralde
を書き進めていれば、 mainClassName
はすでに定義してあります。
これを Main-Class
に指定した task fatJar
を作成しました。
これにより、
gradle fatJar
で build/libs/${project.name}-${version}.jar
が生成されます。
生成された jar ファイルは
java -jar ${project.name}-${version}.jar
で実行できます。
終わりに
自前で gradle task を定義することで、スタンドアロン実行可能な jar ファイルを生成できました。
もしかしたら Ktor 公式の shadow を用いた方法 に手を加えることで対応できるのかもしれません。
Ktor, Kotlin, Gradle ともにまだ理解が浅いですが、Apache Tomcat を用いたWebサーバよりはとっつきやすいかと思います。