LoginSignup
18
16

More than 5 years have passed since last update.

ことりんと一緒 - 3. 実行可能 JAR

Last updated at Posted at 2017-12-12

説明

2. Gradle プロジェクト では、Kotlin を Gradle でビルドするプロジェクトを作成し、実際にビルド&実行してみました。

ところで、実行の仕方は gradle run でした。つまり、Kotlinの標準ライブラリへの参照をもっている Gradle プロジェクトから実行を行っていました。

では、生成された JAR ファイルを直接実行するとどうなっていたでしょうか。試してみます。

$ java -jar build/libs/sample-1.0-SNAPSHOT.jar
build/libs/sample-1.0-SNAPSHOT.jarにメイン・マニフェスト属性がありません

このようにマニフェスト属性がないというエラーが出力されます。
つまり、JAR ファイルのマニフェストにどのクラスが MainClass かという情報が欠落しているのです。

このエラーを解消して 実行可能JAR を Gradle で作成してみます。

前提

次の環境で作業しています。

項目 内容
OS MacOS
Homebrew が使えること
JDK 1.8.0_152
Gradle 4.3.1

説明

1. マニフェストに Main-Class 属性の追加

Gradle の JAR タスクで マニフェストファイルの編集を行います。MainClass がどれか指定したいので Main-Class 属性を マニフェストファイルに追加されるようにします。

以下のタスク定義を build.gradle に追加します。

build.gradle
jar {
    manifest {
        attributes 'Main-Class': "HelloKotlinKt"
    }
}

上記の定義でマニフェストに MainClass が HelloKotlinKt として登録されます。

2. マニフェストの確認

ビルド実施して生成された JAR に含まれているマニフェストを確認してみます。

$ cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
Main-Class: HelloKotlinKt

3. Main-Class 属性追加後の実行

実行してみます。

$ java -jar build/libs/sample-1.0-SNAPSHOT.jar
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics
        at HelloKotlinKt.main(HelloKotlin.kt)
Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 1 more

Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics と、Kotlin のライブラリが見つからなくてエラーが発生しています。

JAR ファイルを中身を確認してみます。

$ jar tvf build/libs/sample-1.0-SNAPSHOT.jar
     0 Tue Dec 12 14:02:26 JST 2017 META-INF/
    52 Tue Dec 12 14:02:26 JST 2017 META-INF/MANIFEST.MF
    35 Tue Dec 12 14:02:26 JST 2017 META-INF/sample.kotlin_module
  1005 Tue Dec 12 14:02:26 JST 2017 HelloKotlinKt.class

JAR の中に Kotlin のライブラリが含まれていない事が分かります。

4. 依存ライブラリの追加

build.gradle の中で Kotlin のライブラリは次のように定義しています。

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}

つまり、依存関係でコンパイル・スコープとして定義しています。
このコンパイル時に利用していたライブラリを同一JARに含め、FarJAR として作成を行うように定義を行います。

JAR タスクに以下を追加します。

from {
    configurations.compile.collect {
        it.isDirectory() ? it : zipTree(it)
    }
}

5. 依存ライブラリ追加後のJARのビルドと中身の確認

JAR ファイルの中身を閲覧してみると、Kotlin のライブラリが含められている事が確認できます。

$ jar -tvf build/libs/sample-1.0-SNAPSHOT.jar
     0 Tue Dec 12 14:21:12 JST 2017 META-INF/
    52 Tue Dec 12 14:21:12 JST 2017 META-INF/MANIFEST.MF
    35 Tue Dec 12 14:21:10 JST 2017 META-INF/sample.kotlin_module
  1005 Tue Dec 12 14:21:10 JST 2017 HelloKotlinKt.class
   197 Mon Nov 27 19:00:42 JST 2017 META-INF/kotlin-stdlib-jdk8.kotlin_module
     0 Mon Nov 27 19:00:42 JST 2017 kotlin/
     0 Mon Nov 27 19:00:42 JST 2017 kotlin/collections/
     0 Mon Nov 27 19:00:42 JST 2017 kotlin/collections/jdk8/
  2132 Mon Nov 27 19:00:42 JST 2017 kotlin/collections/jdk8/CollectionsJDK8Kt.class
     0 Mon Nov 27 19:00:42 JST 2017 kotlin/internal/
     0 Mon Nov 27 19:00:42 JST 2017 kotlin/internal/jdk8/
  2218 Mon Nov 27 19:00:42 JST 2017 kotlin/internal/jdk8/JDK8PlatformImplementations.class
     0 Mon Nov 27 19:00:42 JST 2017 kotlin/streams/
     0 Mon Nov 27 19:00:42 JST 2017 kotlin/streams/jdk8/
  1745 Mon Nov 27 19:00:42 JST 2017 kotlin/streams/jdk8/StreamsKt$asSequence$$inlined$Sequence$1.class
  1856 Mon Nov 27 19:00:42 JST 2017 kotlin/streams/jdk8/StreamsKt$asSequence$$inlined$Sequence$2.class
  1855 Mon Nov 27 19:00:42 JST 2017 kotlin/streams/jdk8/StreamsKt$asSequence$$inlined$Sequence$3.class
  1869 Mon Nov 27 19:00:42 JST 2017 kotlin/streams/jdk8/StreamsKt$asSequence$$inlined$Sequence$4.class
  1417 Mon Nov 27 19:00:42 JST 2017 kotlin/streams/jdk8/StreamsKt$asStream$1.class
  5018 Mon Nov 27 19:00:42 JST 2017 kotlin/streams/jdk8/StreamsKt.class
     0 Mon Nov 27 19:00:42 JST 2017 kotlin/text/
     0 Mon Nov 27 19:00:42 JST 2017 kotlin/text/jdk8/
  1580 Mon Nov 27 19:00:42 JST 2017 kotlin/text/jdk8/RegexExtensionsJDK8Kt.class
   246 Mon Nov 27 18:49:30 JST 2017 META-INF/kotlin-runtime.kotlin_module
  2190 Mon Nov 27 18:50:20 JST 2017 META-INF/kotlin-stdlib.kotlin_module
   743 Mon Nov 27 18:49:30 JST 2017 kotlin/ArrayIntrinsicsKt.class
  1322 Mon Nov 27 18:49:30 JST 2017 kotlin/Deprecated.class
  1258 Mon Nov 27 18:49:30 JST 2017 kotlin/DeprecationLevel.class
   965 Mon Nov 27 18:49:30 JST 2017 kotlin/DslMarker.class
   343 Mon Nov 27 18:50:08 JST 2017 kotlin/ExceptionsKt.class
  2595 Mon Nov 27 18:50:08 JST 2017 kotlin/ExceptionsKt__ExceptionsKt.class
   739 Mon Nov 27 18:49:30 JST 2017 kotlin/ExtensionFunctionType.class
   414 Mon Nov 27 18:49:30 JST 2017 kotlin/Function.class
  1437 Mon Nov 27 18:50:20 JST 2017 kotlin/InitializedLazyImpl.class
   476 Mon Nov 27 18:49:32 JST 2017 kotlin/KotlinNullPointerException.class
   912 Mon Nov 27 18:50:20 JST 2017 kotlin/KotlinVersion$Companion.class
  4039 Mon Nov 27 18:50:20 JST 2017 kotlin/KotlinVersion.class
 :
 :

6. 依存ライブラリ追加後の実行

最後に、生成された JAR ファイルを実行してみます。

$ java -jar build/libs/sample-1.0-SNAPSHOT.jar
Hello, Kotlin!

エラーなく出力することができました。

まとめ

Gradle で生成する JAR ファイルをどこでも実行できるように実行可能形式のFatJAR (UberJAR) にしておくと便利ですね。

18
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
16