0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

java&kotlinをオフラインでビルドする環境を作ったときのログ [gradle.kts][maven][shadowJar][IDEA]

Posted at

あらまし

  • Kotlin版Gradle 7.1.1触った
  • src/main/javaにJavaコードとKotlinコードを混在させて双方向呼び出し
  • Mavenリポジトリを推移的依存性ごと全部お取り寄せするのに奮闘した挙句最終的にmvn dependency:copy-dependenciesした
  • gradle.ktsでshadowJar 7.0.0を使ってfat jarを作った
    • おまけで選択的同封もした
  • 成果物を公開した
    • GitHub Actionsの中でビルド&実行もできた

背景

通信速度がときどき激烈に遅くなる場所にあるRaspberry Pi端末上でGradleでのjavaのビルドをしようとしたら、依存jarのダウンロードだけで非常に時間がかかってしまうという問題を、知っていたけど放置していました。

それはそれとして、自分がGroovy版からKotlin版のgradleに移住して色んなプロジェクトのビルドスクリプトを最初から書き直す機会があったので、この際にオフラインビルドもできるようにしました。

重い依存jarをgitリポジトリ内に含めてしまい、最初から持たせた状態で戦地に送り出そうという作戦です。

環境

  • コーディング環境
    • Windows 10
      • WSL
        • openjdk 11.0.11
        • javac 1.8.0_292
        • Apache Maven 3.6.3
      • IntelliJ IDEA (Android Studio 4.2.1)
        • ※Androidは今回関係ないです
  • 実行環境
    • Raspberry Pi 4
      • java 8
  • ビルド環境
    • Gradle 7.1.1
    • Kotlin 1.4.31

手順

作業ディレクトリ

適当な場所に作業ディレクトリを作って、その中でbashを開いて作業をします。

$ mkdir hoge
$ cd hoge

以下、$で始まるコマンドはWSL上のbashのコマンドで、$の前はカレントディレクトリを表します。

最新のgradlewの取得

gradle downloadとかでググるとたどり着けるページから、gradleの本体のビルド済みのバイナリを取得して、ついでに展開もします。

hoge$ wget https://services.gradle.org/distributions/gradle-7.1.1-bin.zip
hoge$ unzip gradle-7.1.1-bin.zip

これで、hoge/gradle-7.1.1/bin/gradleにgradleの実行ファイルが出現しました。

プロジェクトの生成

プロジェクトのディレクトリを生成してその中に移動します。

hoge$ mkdir project1
hoge$ cd project1

gradlewの生成

gradle本体のコマンドからgradlewを生成します。

ダミービルドスクリプトの用意

gradleでwrapperコマンドを実行するにはビルドスクリプトがないといけないため、まずダミーのビルドスクリプトを書きます(【TODO】ビルドスクリプトなしで実行する方法はありそう)。

hoge/project1$ touch build.gradle.kts

gradlewの生成

hoge/project1$ ../gradle-7.1.1/bin/gradle wrapper

これにより、次のファイルおよびディレクトリが出現します。

  • .gradle
  • gradle/
  • gradlew
  • gradlew.bat

gradlewを起動してみる

hoge/project1$ bash gradlew
結果
Downloading https://services.gradle.org/distributions/gradle-7.1.1-bin.zip
..........10%...........20%...........30%..........40%...........50%...........60%..........70%...........80%...........90%...........100%

> Task :help

Welcome to Gradle 7.1.1.

To run a build, run gradlew <task> ...

To see a list of available tasks, run gradlew tasks

To see a list of command-line options, run gradlew --help

To see more detail about a task, run gradlew help --task <task>

For troubleshooting, visit https://help.gradle.org

BUILD SUCCESSFUL in 5s
1 actionable task: 1 executed

これで、この時点で単体で正常に動作するgradlewが手に入っていることが分かりました。

単体で動作するといっても、冒頭のDownloading https://services.gradle.org/distributions/gradle-7.1.1-bin.zipでダウンロードしたはずのファイルがhoge/project1以下の何処にも見当たらないため、おそらく~/.gradleか何かが何らかの影響を受けていると思います。

プロジェクトをIDEAで開く

プロジェクトディレクトリはもうIDEAで開くことができます。

image.png

オフラインでjavaのコンパイルをしてみる

ビルドスクリプトの編集

ビルドスクリプトにjavaをコンパイルするためのプラグインを追加します。

hoge/project1/build.gradle.kts
plugins {
    application
}

ビルドスクリプト上ではIDEAの補完が利きます。

image.png

gradleタスクの実行

jarを作ってみます。


IDEAでは次のボタンからgradleコマンドを実行できます。

image.png


次のトグルボタンをONにすると、gradleがタスクの実行中にインターネットに接続しないようです(ただしgradlewがgradle本体をダウンロードする部分は防げない模様)。

image.png


jarタスクを実行してjarファイルを作ります。

image.png

この呼び出しはコンソール上ではおそらく次のようになります。

hoge/project1$ bash gradlew jar --offline
結果
BUILD SUCCESSFUL in 606ms
1 actionable task: 1 executed

これにより、hoge/project1/build/libs/project1.jarが出現しました。

ソースコードが全くないため中身はメタ情報しかありません。

image.png

Javaソースファイルを追加してみる

次のファイルを作って再びjarを生成します。

hoge/project1/src/main/java/Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("Main");
    }
}

jarの中にはMainクラスが現れました。

image.png


実行もできます。

hoge/project1$ java -cp build/libs/project1.jar Main
Main

mavenの依存性を追加してみる

JUnit 4.13.2を依存性に追加してみます。

hoge/project1/build.gradle.kts(追加)
dependencies {
    implementation("junit:junit:4.13.2")
}

jarの中に含める実験のために、testImplementationではなく敢えてimplementationコンフィギュレーションに追加しています(jarタスクはtestImplementationコンフィギュレーションへの依存がない)。


こうすると、次のように依存性の解決ができずビルドが失敗します。

Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':compileClasspath'.
   > Cannot resolve external dependency junit:junit:4.13.2 because no repositories are defined.
     Required by:
         project :

Possible solution:
 - Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html

これは、ビルドスクリプト上でリポジトリが定義されていないからであり、そのためオフラインモードでなくても発生します。


これを解決するにはビルドスクリプト上でmavenセントラルリポジトリを登録します。

hoge/project1/build.gradle.kts
plugins {
    application
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("junit:junit:4.13.2")
}

これをすることでオフラインでのビルドが出来なくなりました(実は何も書かなくてもデフォルトでGradle Pluginsへの依存性があるのでオフラインでのビルドはできない)。
オンライン状態では問題なくコンパイルできますが、オフライン状態ではローカル(Windowsの場合は
%HOMEPATH%\.gradle\caches\modules-2\files-2.1\の下)にキャッシュがない限り失敗します。


目標はリポジトリの指定を次のようにプロジェクト内のローカルディレクトリにしてビルドおよび実行ができることです。

repositories {
    maven("./maven")
}

maven依存関係をオフライン化するには

作戦1 依存jarをローカルディレクトリに入れて参照する

次のサイトの方法を試しました。

結果、成果物を作るためのコンパイル環境の依存性はこれで解決できましたが、のちの段階でkotlinのjavaクラスファイルへのコンパイルに使用するgradleプラグインの指定時にモジュールではなくファイル名指定でのやり方が分からず、断念しました。

plugins {
    id("org.jetbrains.kotlin.jvm") version "1.4.31"
}

プラグインを指定するときはPluginDependenciesSpecScope#id(String)関数を呼び出していますが、このときの引数はこのあとDefaultPluginId#of(String)に持っていかれ、異常なフォーマットをしていないか確認されます。
そして、その中でプラグインIDは正規表現で表すと、[a-zA-Z0-9.\-_]の文字しか受け付けません。
ディレクトリの区切り文字などを入れた場合、InvalidPluginIdExceptionが発生します。

つまりプラグインIDの指定段階でローカルファイルを指定することはできないようです。


次にsettings.gradle.kts内でresolutionStrategyを使ってorg.jetbrains.kotlin.jvmというプラグインIDに特定のローカルファイルを関連付けるということを試みました。

次のようにモジュール指定になっている記述を書き換えてファイル名指定にできればゴールです。

pluginManagement {
    resolutionStrategy {
        eachPlugin {
            when (requested.id.id) {
                "org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
            }
        }
    }
}

ここで、PluginResolveDetails#useModule(notation : Object)の中を辿ってみると、このnotationという引数はNotationParserクラスに渡され、
ModuleVersionSelectorクラスのオブジェクトに変換されています。

そして、プラグインの管理がPluginRequestインターフェースで行われていること、プラグインの実体の記述がModuleVersionSelectorというクラスでされていることが分かりました。

そしてなんだかんだでファイル名指定(もしくはクラス名指定)はできなそうな雰囲気を感じたので、諦めました(投げやり)。


以上により、kotlinコードをコンパイルするにはおそらくgroupとnameで表されるモジュール名を解決する仕組みの利用が必須であると結論付けました。

作戦2 org.ysb33r.ivypotGradleプラグインを使用してローカルにivyのミラーを作る

org.ysb33r.ivypotを試しました。

結果、リポジトリのコピーが作られたものの、肝心のjarファイルが入っていないという問題が起こりました。

その理由は以下のもののようです。

実は当初勘違いしていて、Ivyって依存関係を".ivy"とかにDLして、そこに全部jarを保存しておいてくれるものかと思ってました。Mavenの".m2/repository/"みたいな感じで、classpathは適当にAntのbuild.xml中で自動解決してくれる~みたいな。
しかしこれは完全な勘違いで、Ivyのメインはあくまでも依存関係を「ダウンロード」することにあります。classpathの調整はやってくれないんですね。じゃあどう使うのかというと、Antプロジェクトの中に"lib"ディレクトリを作っておいて、"ivy:retrieve/"を実行することでその中にjarをダウンロードしてくれます。

これでは依存関係を先に計算しおき、jarだけ格納されたmavenリポジトリ風ディレクトリを読みに行った方が早いではないか、ということでこの作戦は諦めました。

作戦3 mavenGradleプラグインのinstallタスクを使用する

Mavenメタデータの生成を含め、関連するアーティファクトをローカルMavenキャッシュにインストールする。 デフォルトではinstallタスクはarchivesコンフィグレーションに関連付けられる。 このコンフィグレーションのデフォルトでは要素としてJARのみを持つ。 ローカルリポジトリへのインストールに関して詳しく学ぶためには「ローカルリポジトリへのインストール」を参照のこと。

当初、このタスクは依存先のモジュールをローカルリポジトリへ格納するものだと考えていました。

実際にはプロジェクトの成果物をローカルリポジトリへ格納するというタスクでした。


【余談】Gradle 7でmavenGradleプラグインが全く見つからず、「install」タスクを含むアレがなんでこんなに見つからないの!と思ったら、丁度7で削除されていたというドラマがありました。

image.png

作戦4 mvnコマンドのdependency:go-offlineゴールを使う

次のサイトの手法を試しました。

これはdependency:go-offlineゴールを使ってローカルリポジトリにすべての依存関係をダウンロードする手法です。

ビルド環境(実用上はgitホスティングサービスのCI上)でmvnコマンドが利用できる必要があります(※下記)が、「mavenリポジトリをローカルにミラーするgradleのタスクは存在しない」と思い始めたのでこの方法を試しました。


【※】gradleのビルドスクリプトの依存関係にmavenを追加して直接呼び出すという方法がありそうですが、やってみたところヤケクソに長いエラーが出て諦めました。


まずmvnコマンドを利用できるようにします。

$ sudo apt update
$ sudo apt install maven

pom.xmlをいい感じに編集したあとで、次のコマンドでローカルリポジトリの場所を指定してgo-offlineを実行します。

hoge/project1$ mvn dependency:go-offline -Dmaven.repo.local=maven

その結果、ちゃんと目的のファイルはありましたが、やたら色んなものがダウンロードされていました。

image.png

本当に必要なjunit-4.13.2.jarのサイズは375KBですが、このmavenディレクトリのサイズは100MB以上ありました。


ログを見たところ、mavenプラグインの
依存先もすべてダウンロードされていました。

【物凄い上のmavenプラグインの列】
[INFO] Resolved plugin: doxia-core-1.9.1.jar
[INFO] Resolved plugin: plexus-utils-1.5.10.jar
[INFO] Resolved plugin: jtidy-4aug2000r7-dev.jar
[INFO] Resolved plugin: maven-artifact-2.0.9.jar
[INFO] Resolved plugin: plexus-io-2.0.2.jar
[INFO] Resolved plugin: maven-artifact-manager-2.0.6.jar
[INFO] Resolved dependency: junit-4.13.2.jar
[INFO] Resolved dependency: hamcrest-core-1.3.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.090 s
[INFO] Finished at: 2021-07-09T15:53:41+09:00
[INFO] ------------------------------------------------------------------------

どうにかして
mavenプラグインに起因する依存関係を含めずにダウンロードできればよいみたいです。


そこでソースを調べたところ、このゴールは実行時にプラグインのダウンロードを行わないという選択肢は持っていないことが分かりました。

「mavenモジュールを依存関係ごとローカルにコピーすること」を目的としたゴールがあれば解決できそうです。

作戦5 mvnコマンドのdependency:copy-dependenciesゴールを使う

次に試したのは次のサイトの手法です。


結果、mavenリポジトリではなくjarのみがダウンロードされました。

また、mvnコマンドはどのゴールを実行しても初回起動時にすべてのmavenプラグインに起因する依存jarをローカルリポジトリにダウンロードするようなので、ローカルリポジトリにダウンロードさせてそれをいただくという手法は無理っぽいです。

作戦6 dependency:copyゴールのlocalRepositoryDirectoryオプションを使う

Apache Maven Dependency Pluginの中を漁りました。


そして、copyゴールには<localRepositoryDirectory>というオプションがあり、

Path to override default local repository during plugin's execution. To remove all downloaded artifacts as part of the build, set this value to a location under your project's target directory

とありました(ちなみにcopy-dependencies側にはこのオプションは存在しませんでした)。

よくわからないけど、このオプションを付与するとローカルリポジトリが2個になるっぽいです。そして、新たに指定した方のローカルリポジトリにはこのタスクの生成物しか格納されないような気がします。

<localRepositoryDirectory>オプションに対するもう一つ見つけた説明文です。

dependency:copy always downloads artifacts to default local repository first, and then copy the artifacts to the desired locations. For large size unique snapshot artifacts, the downloads can quickly fill up default local repository, and therefore local disk, after many executions. To clean up the downloaded artifacts as part the build, set localRepositoryDirectory's value to a location in your project's target directory.

このオプションの本来の用途は、大きな単一jarでローカルリポジトリを圧迫しないためにゴミ箱を別途指定することのようです。つまりmavenリポジトリの依存ツリーが丸ごと出力される場所ではないようです。


このオプションが使われているゴールが他にないか調べたところ、このオプションはAbstractFromConfigurationMojo#localRepositoryDirectoryフィールドに由来し、そのサブクラスはcopyタスクとunpackタスクの丁度2個のみでした。後者は出力先ディレクトリにjarそのものではなくjarの内容物をドバッと出します。


まとめると、

  • mvnコマンドの
  • dependency:copyゴールを
  • outputDirectoryオプションにダミーの値を指定したうえで
  • localRepositoryDirectoryにリポジトリ格納先ディレクトリを指定して
  • artifactで依存アーティファクトを指定して

起動すると、初回実行時にホームディレクトリ下のローカルリポジトリに大量の余計なjarをダウンロードしつつ、別途指定した固有ローカルリポジトリに指定されたアーティファクトのmavenリポジトリをキャッシュしながら、出力先にそのjarを配置します。


それを行うには、カレントディレクトリに次のpomファイルを配置したうえで、次のコマンドを打ちます。

hoge/project1/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" 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>null</groupId>
    <artifactId>null</artifactId>
    <version>0.0.0</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <localRepositoryDirectory>./maven</localRepositoryDirectory>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
hoge/project1$ mvn dependency:copy -DoutputDirectory=build/maven-dependency-copy -Dartifact=junit:junit:4.13.2

その結果、無事タスクは完了しました。

結果
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------------< null:null >------------------------------
[INFO] Building null 0.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:3.2.0:copy (default-cli) @ null ---
[INFO] Configured Artifact: junit:junit:4.13.2:jar
Downloading from central: https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.pom
Downloaded from central: https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.pom (27 kB at 35 kB/s)
Downloading from central: https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar
Downloaded from central: https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar (385 kB at 704 kB/s)
[INFO] Copying junit-4.13.2.jar to /mnt/i/workspace/hoge/project1/build/maven-dependency-copy/junit-4.13.2.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.600 s
[INFO] Finished at: 2021-07-10T07:50:15+09:00
[INFO] ------------------------------------------------------------------------

しかしながら、指定したローカルリポジトリの中にはjunitの依存先であるorg.hamcrest:hamcrest-core:1.3が存在しません。

image.png

依存性を推移的に解決しているなら同じ場所にダウンロードされているはずです。

gradlew_dependencies
compileClasspath - Compile classpath for source set 'main'.
\--- junit:junit:4.13.2
     \--- org.hamcrest:hamcrest-core:1.3

この挙動は、-Dmaven.repo.local=maven2オプションにより空のローカルリポジトリの下で実行しても変わりませんでした。

また、junitではなくorg.jetbrains.kotlin:kotlin-stdlib:1.4.31で試しても推移的に依存性を解決しないようでした。

gradlew_dependencies
testRuntimeClasspath - Runtime classpath of source set 'test'.
+--- junit:junit:4.13.2
|    \--- org.hamcrest:hamcrest-core:1.3
\--- org.jetbrains.kotlin:kotlin-stdlib:1.4.31
     +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.4.31
     \--- org.jetbrains:annotations:13.0

image.png


作戦7 dependency:copy-dependenciesゴールのuseRepositoryLayoutオプションを使う

copyゴールが依存関係を推移的に解決しないとしても、copy-dependenciesゴールの方は少なくとも推移的に解決はしてくれるだろう(実際説明文にもtransitiveって書いてあるし)と思いました。

takes the list of project direct dependencies and optionally transitive dependencies and copies them to a specified location, stripping the version if desired. This goal can also be run from the command line.


このタスクの問題は出力がjarファイルしかないところなので、mavenリポジトリをそのまま出力するオプションがないかと調べたところ、<useRepositoryLayout>mdep.useRepositoryLayout)がまさにそんな感じでした。

Place each artifact in the same directory layout as a default repository.

このオプションはAbstractFromDependenciesMojo#useRepositoryLayoutフィールドに由来するらしく、copy-dependenciesゴールの他にunpack-dependenciesゴールでも使えるようでした(逆に言うとcopy getなどでは利用不可(別のフィールド実体に由来する同名のオプションも見当たらず))。


また、copyPomおよびaddParentPomsオプションを付けなければgradleの段階で例外が発生したため、これも付与します。

これらのオプションは、pom.xml上でプラグインの使用を明示しなければ無視されるようです。

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.2.0</version>
            </plugin>
        </plugins>
    </build>

このタスクはgroupIdのような個別のアーティファクトを特定するオプションを持たないため、多分pom上に定義された依存関係しか見に行かないんじゃないかと思うので、pom.xmlに依存関係を追加します。

hoge/project1/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" 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>null</groupId>
    <artifactId>null</artifactId>
    <version>0.0.0</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
            </plugin>
        </plugins>
    </build>
    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>

    </dependencies>
</project>

そして次のコマンドで実行します。

hoge/project1$ mvn dependency:copy-dependencies -DoutputDirectory=maven -Dmdep.useRepositoryLayout=true -Dmdep.copyPom=true -Dmdep.addParentPoms=true

結果、無事推移的に依存するすべてのリポジトリがその構造のままjarとpomがダウンロードされました。

image.png


なお、maven-dependency-pluginのバージョンは3.0.0以上では「親のpomがMaven Central Repositoryに存在しないような依存性を(推移的に)含むアーティファクト(具体的にはorg.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.4.31など)」をaddParentPomsを付けて指定するとなぜか解決失敗するということがのちに分かりました。

バージョン2.10では正常に解決できました。理由は謎です(AbstractDependencyFilterMojo#getDependencySets内で依存先の親を解決する部分で落ちているようですが、なぜか追加リポジトリが無視されているようでした【TODO】)。

org.apache.maven.plugins:maven-dependency-plugin:3.0.0:copy-dependencies (default-cli) on project null: Error resolving project artifact: Failure to find org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:pom:1.4.31 in https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced for project org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:pom:1.4.31

プロジェクト下のリポジトリを指定してjavaコンパイル

前節で作戦7によってhoge/project1/mavenディレクトリがmavenリポジトリになっているので、それをそのまま指定してビルドします。

作戦1~6は全部ボツです。

ビルドスクリプト側でプロジェクト内のリポジトリを見るように変更

hoge/project1/build.gradle.kts
plugins {
    application
}

repositories {
    maven("./maven")
}

dependencies {
    implementation("junit:junit:4.13.2")
}

javaコード上で依存jarのクラスを呼び出してみる

正常にクラスがロードできていなければ例外になるようなコードを書いてみます。

hoge/project1/src/main/java/Main.java
import org.junit.Test;

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) {
        System.out.println("Main");
        for (Method method : Test.class.getMethods()) {
            System.out.println(method);
        }
    }
}

この時点で既にIDEA上でgradleプロジェクトのsyncをするとコードの補完ができるようになっていました。

キャッシュ削除

ここで、一旦IDEAのGradleのオフラインモードをONにし、IDEAを終了し、他に起動しているEclipseなどのjavaコンパイラもすべて閉じて、次のキャッシュディレクトリを削除しておきます。

  • %HOMEPATH%\.gradle
  • %HOMEPATH%\.m2
  • hoge/project1/.gradle
  • hoge/project1/build

念のためIDEAのここにあるこれも行いました。

image.png

ビルド・実行

この状態でIDEAからgradle jarを実行すると、無事jarファイルが生成されました。

結果
9:13:40: タスクを実行中 'jar'...

> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :jar

BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
9:13:42: タスクの実行を完了しました 'jar'。

出力されたjarを依存先とともに呼び出してみると、ちゃんと依存先のjarに依存した動作を成功させました。

hoge/project1$ java -cp build/libs/project1.jar:maven/junit/junit/4.13.2/junit-4.13.2.jar Main
結果
Main
public abstract java.lang.Class org.junit.Test.expected()
public abstract long org.junit.Test.timeout()
public abstract boolean java.lang.annotation.Annotation.equals(java.lang.Object)
public abstract java.lang.String java.lang.annotation.Annotation.toString()
public abstract int java.lang.annotation.Annotation.hashCode()
public abstract java.lang.Class java.lang.annotation.Annotation.annotationType()

kotlinをjvmコードにコンパイルする

ビルドスクリプトの改変

gradleにkotlinプラグインを追加して、ソースコードの依存性にkotlinのライブラリを追加します。

hoge/project1/build.gradle.kts
plugins {
    application
    kotlin("jvm") version "1.4.31"
}

repositories {
    maven("./maven")
}

dependencies {
    implementation("junit:junit:4.13.2")
    implementation(kotlin("stdlib-jdk8", "1.4.31"))
}

gradle.ktsを使う場合、kotlinプラグインのバージョンはgradle.ktsのランタイムのkotlinバージョンに合わせなければバージョン衝突になるようです。Gradle 7.1.1ではKotlin 1.4.31が指定のバージョンでした。

プラグインの依存性解決の失敗

オフラインかつプロジェクト内のリポジトリにもkotlinのプラグインの依存性を追加していないため、当然次のような問題が起こります。

問題
* What went wrong:
Plugin [id: 'org.jetbrains.kotlin.jvm', version: '1.4.31'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.4.31')
  Searched in the following repositories:
    Gradle Central Plugin Repository

org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.4.31を依存性に追加すればいいということが分かりました。

org.jetbrains.kotlin.jvm.gradle.pluginはGradle Pluginsリポジトリにある

当初pomに単に依存アーティファクトを追加しましたが、解決に失敗しました。

Maven Central Repositoryには無いようです。

オンライン状態で実行するとちゃんとプラグインが使えたため、デフォルトで追加されるGradle Core Pluginsというリポジトリの方にあるということになります。


このページを見ると、そのURLはhttps://plugins.gradle.org/m2/のようです。


中身を確認してみると、このアーティファクトはpomのみでjarがないようです。そのため、pom.xml内ではこの依存性の<type>pomにしておきます。

依存性の<type>と依存先成果物の<packaging>には次のような対応があるようです。


ちなみにkotlin("stdlib-jdk8", "1.4.31")org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.31というアーティファクトを表します。

settings.gradle.ktsの記述

プラグインの依存関係は(おそらくビルドスクリプトよりも先にコンパイルおよび実行されるために)特別な場所に記述しなければなりません。

hoge/project1/settings.gradle.kts
pluginManagement {
    repositories {
        maven("./maven")
    }
}

pom.xmlの編集・リポジトリダウンロード

アーティファクト名とリポジトリが分かったのでpom.xmlを更新します。ついでにオプションもここに書いてしまいます。

依存性の記述時には<type>に気を付けてください。コピペすると地味に<type>pom</type>がくっついてきたりします。

hoge/project1/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" 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>null</groupId>
    <artifactId>null</artifactId>
    <version>0.0.0</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
                <configuration>
                    <outputDirectory>maven</outputDirectory>
                    <useRepositoryLayout>true</useRepositoryLayout>
                    <copyPom>true</copyPom>
                    <addParentPoms>true</addParentPoms>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <repositories>

        <repository>
            <id>plugins.gradle.org</id>
            <name>plugins.gradle.org</name>
            <url>https://plugins.gradle.org/m2/</url>
        </repository>

    </repositories>
    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlin.jvm</groupId>
            <artifactId>org.jetbrains.kotlin.jvm.gradle.plugin</artifactId>
            <version>1.4.31</version>
            <type>pom</type>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib-jdk8</artifactId>
            <version>1.4.31</version>
        </dependency>

    </dependencies>
</project>

これで次のコマンドによりkotlinのGradleプラグインをダウンロードします。

hoge/project1$ mvn dependency:copy-dependencies

結果、めっちゃ大量の依存性が解決できました。

結果
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------------< null:null >------------------------------
[INFO] Building null 0.0.0
[INFO] --------------------------------[ jar ]---------------------------------
Downloading from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.31/kotlin-stdlib-jdk8-1.4.31.pom
Downloaded from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.31/kotlin-stdlib-jdk8-1.4.31.pom (1.6 kB at 876 B/s)
Downloading from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.pom
Downloaded from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.pom (1.4 kB at 875 B/s)
Downloading from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.jar
Downloaded from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.jar (23 kB at 14 kB/s)
[INFO]
[INFO] --- maven-dependency-plugin:2.10:copy-dependencies (default-cli) @ null ---
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.4.31/kotlin-stdlib-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib/1.4.31/kotlin-stdlib-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.4.31/kotlin-stdlib-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib/1.4.31/kotlin-stdlib-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.31/kotlin-stdlib-jdk8-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.31/kotlin-stdlib-jdk8-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/antlr/antlr4-master/4.5.2-1/antlr4-master-4.5.2-1.pom to /mnt/i/workspace/hoge/project1/maven/org/antlr/antlr4-master/4.5.2-1/antlr4-master-4.5.2-1.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-compiler-runner/1.4.31/kotlin-compiler-runner-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-compiler-runner/1.4.31/kotlin-compiler-runner-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-compiler-runner/1.4.31/kotlin-compiler-runner-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-compiler-runner/1.4.31/kotlin-compiler-runner-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin-model/1.4.31/kotlin-gradle-plugin-model-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin-model/1.4.31/kotlin-gradle-plugin-model-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin-model/1.4.31/kotlin-gradle-plugin-model-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin-model/1.4.31/kotlin-gradle-plugin-model-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/antlr/antlr4-runtime/4.5.2-1/antlr4-runtime-4.5.2-1.jar to /mnt/i/workspace/hoge/project1/maven/org/antlr/antlr4-runtime/4.5.2-1/antlr4-runtime-4.5.2-1.jar
[INFO] Installing /home/riana/.m2/repository/org/antlr/antlr4-runtime/4.5.2-1/antlr4-runtime-4.5.2-1.pom to /mnt/i/workspace/hoge/project1/maven/org/antlr/antlr4-runtime/4.5.2-1/antlr4-runtime-4.5.2-1.pom
[INFO] Installing /home/riana/.m2/repository/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar to /mnt/i/workspace/hoge/project1/maven/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar
[INFO] Installing /home/riana/.m2/repository/com/google/code/gson/gson/2.8.6/gson-2.8.6.pom to /mnt/i/workspace/hoge/project1/maven/com/google/code/gson/gson/2.8.6/gson-2.8.6.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-compiler-embeddable/1.4.31/kotlin-scripting-compiler-embeddable-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-compiler-embeddable/1.4.31/kotlin-scripting-compiler-embeddable-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-compiler-embeddable/1.4.31/kotlin-scripting-compiler-embeddable-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-compiler-embeddable/1.4.31/kotlin-scripting-compiler-embeddable-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-jvm/1.4.31/kotlin-scripting-jvm-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-jvm/1.4.31/kotlin-scripting-jvm-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-jvm/1.4.31/kotlin-scripting-jvm-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-jvm/1.4.31/kotlin-scripting-jvm-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-android-extensions/1.4.31/kotlin-android-extensions-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-android-extensions/1.4.31/kotlin-android-extensions-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-android-extensions/1.4.31/kotlin-android-extensions-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-android-extensions/1.4.31/kotlin-android-extensions-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/com/github/gundy/semver4j/0.16.4/semver4j-0.16.4.jar to /mnt/i/workspace/hoge/project1/maven/com/github/gundy/semver4j/0.16.4/semver4j-0.16.4.jar
[INFO] Installing /home/riana/.m2/repository/com/github/gundy/semver4j/0.16.4/semver4j-0.16.4.pom to /mnt/i/workspace/hoge/project1/maven/com/github/gundy/semver4j/0.16.4/semver4j-0.16.4.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-compiler-embeddable/1.4.31/kotlin-compiler-embeddable-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-compiler-embeddable/1.4.31/kotlin-compiler-embeddable-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-compiler-embeddable/1.4.31/kotlin-compiler-embeddable-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-compiler-embeddable/1.4.31/kotlin-compiler-embeddable-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin-api/1.4.31/kotlin-gradle-plugin-api-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin-api/1.4.31/kotlin-gradle-plugin-api-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin-api/1.4.31/kotlin-gradle-plugin-api-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin-api/1.4.31/kotlin-gradle-plugin-api-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-util-io/1.4.31/kotlin-util-io-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-util-io/1.4.31/kotlin-util-io-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-util-io/1.4.31/kotlin-util-io-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-util-io/1.4.31/kotlin-util-io-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-util-klib/1.4.31/kotlin-util-klib-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-util-klib/1.4.31/kotlin-util-klib-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-util-klib/1.4.31/kotlin-util-klib-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-util-klib/1.4.31/kotlin-util-klib-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin/1.4.31/kotlin-gradle-plugin-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin/1.4.31/kotlin-gradle-plugin-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin/1.4.31/kotlin-gradle-plugin-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin/1.4.31/kotlin-gradle-plugin-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-common/1.4.31/kotlin-scripting-common-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-common/1.4.31/kotlin-scripting-common-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-common/1.4.31/kotlin-scripting-common-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-common/1.4.31/kotlin-scripting-common-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.4.31/kotlin-stdlib-common-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib-common/1.4.31/kotlin-stdlib-common-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.4.31/kotlin-stdlib-common-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib-common/1.4.31/kotlin-stdlib-common-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/junit/junit/4.13.2/junit-4.13.2.jar to /mnt/i/workspace/hoge/project1/maven/junit/junit/4.13.2/junit-4.13.2.jar
[INFO] Installing /home/riana/.m2/repository/junit/junit/4.13.2/junit-4.13.2.pom to /mnt/i/workspace/hoge/project1/maven/junit/junit/4.13.2/junit-4.13.2.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-script-runtime/1.4.31/kotlin-script-runtime-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-script-runtime/1.4.31/kotlin-script-runtime-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-script-runtime/1.4.31/kotlin-script-runtime-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-script-runtime/1.4.31/kotlin-script-runtime-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar to /mnt/i/workspace/hoge/project1/maven/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
[INFO] Installing /home/riana/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom to /mnt/i/workspace/hoge/project1/maven/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/jvm/org.jetbrains.kotlin.jvm.gradle.plugin/1.4.31/org.jetbrains.kotlin.jvm.gradle.plugin-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/jvm/org.jetbrains.kotlin.jvm.gradle.plugin/1.4.31/org.jetbrains.kotlin.jvm.gradle.plugin-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-build-common/1.4.31/kotlin-build-common-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-build-common/1.4.31/kotlin-build-common-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-build-common/1.4.31/kotlin-build-common-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-build-common/1.4.31/kotlin-build-common-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/com/google/code/gson/gson-parent/2.8.6/gson-parent-2.8.6.pom to /mnt/i/workspace/hoge/project1/maven/com/google/code/gson/gson-parent/2.8.6/gson-parent-2.8.6.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-annotation-processing-gradle/1.4.31/kotlin-annotation-processing-gradle-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-annotation-processing-gradle/1.4.31/kotlin-annotation-processing-gradle-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-annotation-processing-gradle/1.4.31/kotlin-annotation-processing-gradle-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-annotation-processing-gradle/1.4.31/kotlin-annotation-processing-gradle-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/sonatype/oss/oss-parent/7/oss-parent-7.pom to /mnt/i/workspace/hoge/project1/maven/org/sonatype/oss/oss-parent/7/oss-parent-7.pom
[INFO] Installing /home/riana/.m2/repository/de/undercouch/gradle-download-task/4.0.2/gradle-download-task-4.0.2.jar to /mnt/i/workspace/hoge/project1/maven/de/undercouch/gradle-download-task/4.0.2/gradle-download-task-4.0.2.jar
[INFO] Installing /home/riana/.m2/repository/de/undercouch/gradle-download-task/4.0.2/gradle-download-task-4.0.2.pom to /mnt/i/workspace/hoge/project1/maven/de/undercouch/gradle-download-task/4.0.2/gradle-download-task-4.0.2.pom
[INFO] Installing /home/riana/.m2/repository/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom to /mnt/i/workspace/hoge/project1/maven/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-daemon-embeddable/1.4.31/kotlin-daemon-embeddable-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-daemon-embeddable/1.4.31/kotlin-daemon-embeddable-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-daemon-embeddable/1.4.31/kotlin-daemon-embeddable-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-daemon-embeddable/1.4.31/kotlin-daemon-embeddable-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-reflect/1.4.31/kotlin-reflect-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-reflect/1.4.31/kotlin-reflect-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-reflect/1.4.31/kotlin-reflect-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-reflect/1.4.31/kotlin-reflect-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-compiler-impl-embeddable/1.4.31/kotlin-scripting-compiler-impl-embeddable-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-compiler-impl-embeddable/1.4.31/kotlin-scripting-compiler-impl-embeddable-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-compiler-impl-embeddable/1.4.31/kotlin-scripting-compiler-impl-embeddable-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-compiler-impl-embeddable/1.4.31/kotlin-scripting-compiler-impl-embeddable-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/intellij/deps/trove4j/1.0.20181211/trove4j-1.0.20181211.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/intellij/deps/trove4j/1.0.20181211/trove4j-1.0.20181211.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/intellij/deps/trove4j/1.0.20181211/trove4j-1.0.20181211.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/intellij/deps/trove4j/1.0.20181211/trove4j-1.0.20181211.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.3.8/kotlinx-coroutines-core-1.3.8.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.3.8/kotlinx-coroutines-core-1.3.8.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.3.8/kotlinx-coroutines-core-1.3.8.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.3.8/kotlinx-coroutines-core-1.3.8.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-daemon-client/1.4.31/kotlin-daemon-client-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-daemon-client/1.4.31/kotlin-daemon-client-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-daemon-client/1.4.31/kotlin-daemon-client-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-daemon-client/1.4.31/kotlin-daemon-client-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/sonatype/oss/oss-parent/9/oss-parent-9.pom to /mnt/i/workspace/hoge/project1/maven/org/sonatype/oss/oss-parent/9/oss-parent-9.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/annotations/13.0/annotations-13.0.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/annotations/13.0/annotations-13.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  7.830 s
[INFO] Finished at: 2021-07-11T03:28:38+09:00
[INFO] ------------------------------------------------------------------------

実はここで1回前述のエラーで止まりましたが、次の記事にあるとおり.m2ディレクトリを削除してもできず、結局maven-dependency-pluginのバージョンを2.10に下げました。

ビルド

キャッシュを削除してjarの生成を試みます。

IDEA上で
gradle jar

無事jarができました。よく見るとKotlinを含むタスクが実行されているのが分かります。

結果
3:33:13: タスクを実行中 'jar'...

> Task :compileKotlin
> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :inspectClassesForKotlinIC
> Task :jar

BUILD SUCCESSFUL in 432ms
4 actionable tasks: 4 executed
3:33:14: タスクの実行を完了しました 'jar'。

src/main/javaにKotlinコードを書いてjavaと双方向に呼び出す

JavaとKotlinで双方向にメソッドの呼び出しを行うような対称的なソースコードを書いてみます。

hoge/project1/src/main/java/Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println(MainKotlin.functionKotlin("Hello from Java!"));
    }

    public static String functionJava(String param) {
        return "JAVA[" + param + "]";
    }
}
hoge/project1/src/main/java/MainKotlin.kt
class MainKotlin {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            println(Main.functionJava("Hello from Kotlin!"))
        }

        @JvmStatic
        fun functionKotlin(param: String) = "KOTLIN[$param]"
    }
}

これらは同ディレクトリに混在して配置することができます。

image.png


ビルドするとjarの中身は実質的に同じ動きをするコードがちゃんと生成されています。

image.png

image.png

たとえKotlinらしいことをしなくてもNullチェックのためにkotlin.jvm.internal.IntrinsicsのようなKotlinのクラスを利用しているので、実行時にロードしなければならないことが分かります。

実行のためのコマンドの生成

applicationGradleプラグインにより提供されるinstallDistタスクを実行すると、build/install/project1/bin/project1という場所にシェルスクリプトが出力されます。

これは依存先のjarがすべてクラスパスに追加されたjavaコマンドと考えてよいです。


ちなみに実行時の依存性は次のようになってしました。

gradle_dependenciesの結果
runtimeClasspath - Runtime classpath of compilation 'main' (target  (jvm)).
+--- junit:junit:4.13.2
|    \--- org.hamcrest:hamcrest-core:1.3
\--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.31
     +--- org.jetbrains.kotlin:kotlin-stdlib:1.4.31
     |    +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.4.31
     |    \--- org.jetbrains:annotations:13.0
     \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.31
          \--- org.jetbrains.kotlin:kotlin-stdlib:1.4.31 (*)

これはinstallDistタスクの出力結果とも対応します。

image.png


先のクラスを実行するためのコマンドは次のようになります。

hoge/project1$ ./build/install/project1/bin/project1 Main
hoge/project1$ ./build/install/project1/bin/project1 MainKotlin

実行

結果、プログラム通りの挙動が得られました。

hoge/project1$ ./build/install/project1/bin/project1 Main
KOTLIN[Hello from Java!]
hoge/project1$ ./build/install/project1/bin/project1 MainKotlin
JAVA[Hello from Kotlin!]

一体化Jarを作る

com.github.johnrengelman.shadowプラグインを使用してfat jarを作ります。

プロジェクト内のMavenリポジトリへ追加

ここを見ると、依存先はgradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.0.0とあります。

おそらくアーティファクトはcom.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:pom:7.0.0です。


よってpomに追加し、mvn dependency:copy-dependenciesコマンドを叩きます。

hoge/project1/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" 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>null</groupId>
    <artifactId>null</artifactId>
    <version>0.0.0</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
                <configuration>
                    <outputDirectory>maven</outputDirectory>
                    <useRepositoryLayout>true</useRepositoryLayout>
                    <copyPom>true</copyPom>
                    <addParentPoms>true</addParentPoms>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <repositories>

        <repository>
            <id>plugins.gradle.org</id>
            <name>plugins.gradle.org</name>
            <url>https://plugins.gradle.org/m2/</url>
        </repository>

    </repositories>
    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlin.jvm</groupId>
            <artifactId>org.jetbrains.kotlin.jvm.gradle.plugin</artifactId>
            <version>1.4.31</version>
            <type>pom</type>
        </dependency>

        <dependency>
            <groupId>com.github.johnrengelman.shadow</groupId>
            <artifactId>com.github.johnrengelman.shadow.gradle.plugin</artifactId>
            <version>7.0.0</version>
            <type>pom</type>
        </dependency>

        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib-jdk8</artifactId>
            <version>1.4.31</version>
        </dependency>

    </dependencies>
</project>

Gradleプラグインを追加

shadowプラグインをpluginsブロックに追加します。

  plugins {
      application
      kotlin("jvm") version "1.4.31"
+     id("com.github.johnrengelman.shadow") version "7.0.0"
  }

この時点でIDEAからgradle tasks --allを実行するとshadowJarタスクが出来上がっています。

【中略】

Shadow tasks
------------
knows - Do you know who knows?
shadowJar - Create a combined JAR of project and runtime dependencies

【中略】

shadowJarタスクのためのメインクラスの設定

メインクラスがなければエラーになるらしいので、ダミーの値をセットしておきます。

application {
    mainClass.set("dummy")
}

ビルドスクリプトの状態

ここまでのことを反映させたビルドスクリプトが次のコードです。

hoge/project1/build.gradle.kts
plugins {
    application
    kotlin("jvm") version "1.4.31"
    id("com.github.johnrengelman.shadow") version "7.0.0"
}

repositories {
    maven("./maven")
}

dependencies {
    implementation("junit:junit:4.13.2")
    implementation(kotlin("stdlib-jdk8", "1.4.31"))
}

application {
    mainClass.set("dummy")
}

fat jarを出力する

shadowJarタスクを実行すると、build/libs/project1-all.jarが出力されます。

結果
5:20:41: タスクを実行中 'shadowJar'...

> Task :compileKotlin UP-TO-DATE
> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :shadowJar


BUILD SUCCESSFUL in 2s
3 actionable tasks: 2 executed, 1 up-to-date
5:20:43: タスクの実行を完了しました 'shadowJar'。

生成されたjarの中には依存性に追加したjunitやkotlinなどのパッケージが同封されています。

image.png

重さも約2MBあります。

image.png

実行

今度は出力されたjarをjavaコマンドから呼び出します。

hoge/project1$ java -cp build/libs/project1-all.jar Main
KOTLIN[Hello from Java!]
hoge/project1$ java -cp build/libs/project1-all.jar MainKotlin
JAVA[Hello from Kotlin!]

【応用】依存性を選択的にfat jarに追加する

詳しいことは省略しますが、次のコードが参考になります。

Groovy版Gradleでは検索で出てきたけど、Kotlin版ではどう書くの?的なメモです。

import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

lateinit var implementationAppending: Configuration

configurations {
    register("implementationAppending") {
        implementationAppending = this
        configurations.implementation.get().extendsFrom(this)
    }
}

dependencies {
    // 同封しない依存性
    implementation("junit:junit:4.13.2")
    // 同封する依存性
    implementationAppending(kotlin("stdlib-jdk8", "1.4.31"))
}

(tasks["shadowJar"] as ShadowJar).run {
    configurations = listOf(implementationAppending)
}

同封するようにした依存性に由来するクラスのみが格納されているの図

image.png

公開

この記事に書かれているものを公開しました。

【応用】GitHub Actions上でのビルド

完全オフラインでできるかどうかはともかく、GitHub Actionsの中でも同じことが出来たら安心感があるのでやりました。

mavenリポジトリを取り寄せてビルドしてjavaコマンドで叩くだけです。

yaml/.github/workflows/ci.yml
name: CI

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Build
        run: |
          bash maven-copy.sh || exit
          bash gradlew shadowJar || exit
      - name: Test
        run: |
          command=(java -cp build/libs/java-kotlin-project-sample-all.jar Main)
          out=$("${command[@]}")
          echo "$out"
          [ 'KOTLIN[Hello from Java!]' = "$out" ] || exit
          command=(java -cp build/libs/java-kotlin-project-sample-all.jar MainKotlin)
          out=$("${command[@]}")
          echo "$out"
          [ 'JAVA[Hello from Kotlin!]' = "$out" ] || exit

無事テストが通りました。

image.png

よかった。

TODO

%HOMEPATH%/.gradle %HOMEPATH%/.m2 ./mavenを削除してダウンロード済みのmavenリポジトリをすべて削除したうえで、初めてgradlewを起動すると、次のようにgradleの本体(なぜかバージョン6.5)のダウンロードを勝手に行ってしまう。

Download https://services.gradle.org/distributions/gradle-6.5-bin.zip finished, took 2 s 925 ms (102.36 MB)

gradle-6.5-bin.zipは100MB近くあるので結局解決してなさそう。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?